最近看到 P 神公众号上发了篇 Apache Ofbiz 的漏洞分析所以就跟着学习了一下,没想到长亭这两天马上就又发布了鉴权绕过导致的几个利用 CVE,于是也跟着做了些分析。
</serializable
这个关键词的检测org.apache.ofbiz.base.util.CacheFilter#doFilter
/control/xmlrpc/;/
从而绕过针对 </serializable
标签的检查。serializable
的限制,接下来还需要绕过认证的模块。这一部分代码逻辑是在调用 runEvent
方法时进行。org.apache.ofbiz.webapp.control.LoginWorker#checkLogin
这里条件分支当中的 login
函数非常关键,其返回值是否等于 error 决定了是否可以绕过鉴权。unpwErrMsgList
当中会添加提示信息,使得走入下面这个条件分支,而在返回时,因为我们设置了 requirePasswordChange
参数值为 Y,因此返回的则是 requirePasswordChange
,不再是 error
。/webtools/control/ProgramExport
依然在之前 webtools 目录下,因此映射的 servlet 都是一样的。nextRequestResponse.type
的值来渲染视图。context
中设置,这里意思也就是可以在请求参数中设置。groovyProgram
即可。SecuredUpload.isValidText
。Replaced direct null checks on username, password, and token with UtilValidate.isEmpty() method calls for consistency
这个也就是前面漏洞提到鉴权的地方,前面是空字符串可以绕过,这里改换成了 UtilValidate.isEmpty() 看下它里面还判断了字符串长度,因此使用空字符串不再可以绕过。
https://github.com/apache/ofbiz-framework/commit/82c17376880a8fd8a11261e1e00dad45cfed344d
Use screen engine for the request getJSONuilabels
themes/common-theme/webapp/common/js/util/OfbizUtil.js
diff 当中看到两个 js 文件,getJSONuilLabels
函数里面通过 jQuery 发送请求到 getJSONuiLabelArray
API ,请求方式为 POST ,并且传参 requiredLabels
。
然后 PartyProfileContent.js 当中看到调用了该 getJSONuilLabels
方法,传的格式为 json 。
applications/party/webapp/partymgr/static/PartyProfileContent.js
根据变量名 UiLabel 我们可以大致推理出这里是在做一个国际化处理,即发送标签名并从与 CommonUiLabels 关联的配置文件当中读取相应标签名的国际化信息并返回。
OK 我们可以尝试发起这个请求验证一下。一番查找之后这个接口是对应的是 webtools/control/getJSONuiLabelArray
感兴趣的话可以看下这个默认国际化配置文件信息就在 framework/common/config/CommonUiLabels.xml。
getJSONuiLabelArray
路由信息位于 framework/common/webcommon/WEB-INF/common-controller.xml。
可以看到 https 设置为 true,说明这里调用也是需要先鉴权的(因此需要我们先做鉴权绕过)。之后的事件处理 handler 为 CommonEvents 类。
其实这里思路已经有了,就是看看这个配置文件是否是可以指定的,因为所有的参数都可以控制。因此分析的主要逻辑在 org.apache.ofbiz.base.util.UtilProperties#getResourceBundle
这里,第一个参数就是前面 CommonUiLabels
对应位置值。
首先会调用 createResourceName
方法,里面第三个参数如果为 true 的话,会移除后缀出现 .xml/.properties
的(后面还会出现)。并且将 locale 本地信息添加到后缀。
之后如果 bundleCache
中没有对应项的话,则会去掉之前添加的 locale 本地信息后缀,换一个其他的,这里看到 locale 本地信息是存在空字符串的,也就是什么都不添加。然后再去查找,如果还没有则会调用 getProperties
方法。
org.apache.ofbiz.base.util.UtilProperties#getProperties(java.lang.String, java.util.Locale) 可以看到会调用 resolvePropertiesUrl
解析 resource
的 url。里面实际还会调用一次 createResourceName
,这回第三个参数变成了 false,也就是不会去除后缀。因此可以任意指定加载配置文件。
可以看到这里支持多种协议,包括常见的 http/file 协议。
然后如果是指定了某个协议时, org.apache.ofbiz.base.util.UtilProperties#resolvePropertiesUrl 就会创建一个 URL 实例。
后续 org.apache.ofbiz.base.util.UtilProperties.ExtendedProperties#ExtendedProperties(java.net.URL, java.util.Locale) 就会建立连接并读取其中的内容。因此这里就是文件读取以及 SSRF 的漏洞 sink 点。
它这里支持读取 properties 或 xml 文件,我们这里以 properties 为例。
那么内容如何解析并回显呢?来到 org.apache.ofbiz.base.util.UtilProperties#getMessage(java.lang.String, java.lang.String, java.util.Locale)
方法,这里看到只需要读取的键值对中,key 存在与 name
(就是对应的前面传入的标签值)一样的话就取出并回显。
配置文件读取
以读取 applications/accounting/config/payment.properties 中的几个 key 为例
SSRF 利用
这里随便写一个 properties 文件,然后 python -m http.server 8000
起个服务
POC 验证
成功对 8000 端口服务发起了请求
[1] Insecure Deserialization in Apache XML-RPC · CVE-2019-17570 · GitHub Advisory Database
[2] CVE-2023-49070&&CVE-2020-9496 OFBIZ XML-RPC漏洞分析 - 先知社区 (aliyun.com)
[3] https://mp.weixin.qq.com/s/iAvitO6otPdHSu1SjRNX3g
[4] https://www.mi1k7ea.com/2021/09/21/浅析Ofbiz反序列化漏洞(CVE-2020-9496)/
[5] https://xz.aliyun.com/t/8184#toc-3
[6] The Apache OFBiz® Project - Release Notes 18.12.11
[7] Apache OFBiz未授权命令执行浅析(CVE-2023-51467) (y4tacker.github.io)