Apache XML-RPC是一个Java实现的XML-RPC库,基于HTTP传输的XML实现RPC,最后一个版本为2020年2月6日发布的3.1.3。

Apache OFBiz是一个企业自动化流程开源框架,提供ERP、CRM、电商应用程序。

漏洞分析

CVE-2016-5003

  • 影响 Apache XML-RPC <= 3.1.3

根据Data Types官方文档,设置了enabledForExtensions属性时,支持以http://ws.apache.org/xmlrpc/namespaces/extensions作为命名空间的serializable标签,用于传输以Base64编码的序列化字节数组。

0ang3el在博客中给出了POC截图,看到以rO0AB开头的Base64编码序列化数据,对应十六进制Java原生序列化数据的aced0005魔数头。

全局搜索readObject,看到SerializableParser#getResult调用super.getResult()获取字节数组后反序列化。SerializableParser继承自ByteArrayParser

ByteArrayParserstartElement方法中解码Base64编码的字节数组,在endElement方法中调用了setResult方法。ByteArrayParser继承自TypeParserImpl

TypeParserImpl中实现了getResultsetResult方法。查找对ByteArrayParser#startElement的调用,这里的接口会出现很多干扰结果。世上无难事只要肯放弃,反向跟进因为动态实现而路径爆炸后,试试正向跟进。

定位到XmlRpcRequestParser,类注释表示它是对XmlRpcClient请求的解析器。从startElement方法的判断逻辑可以猜测,各级XML标签分别为methodCallmethodNameparamsparamvalue,与POC截图吻合。

endElement方法同理,两个方法分别调用了从父类RecursiveTypeParserImpl继承而来的startValueTagendValueTag方法。代表Map对象的struct标签则会进入default分支调用startElementendElement方法(SerializerTest#testMapParam测试用例可以看到相应XML)。

RecursiveTypeParserImpl#startElement中看到了对TypeParser接口实例的调用。

跟进getParser方法可知pLocalNameserializable时调用SerializableParser

查找对RecursiveTypeParserImpl#startElement的调用并筛选后,看到SerializableSerializer#write在序列化时写入了相应的pLocalName

CVE-2019-17570

  • 影响 3.1 <= Apache XML-RPC <= 3.1.3

客户端解析响应数据时的反序列化,逻辑类似。

CVE-2020-9496

  • 影响 Apache OFBiz < 17.12.04

全局搜索org.apache.xmlrpc,定位到XmlRpcEventHandler#getRequest,一路反向跟进得到调用链。

1
2
3
4
5
6
org.apache.ofbiz.webapp.event.XmlRpcEventHandler#execute
org.apache.ofbiz.webapp.event.XmlRpcEventHandler#invoke
org.apache.ofbiz.webapp.control.RequestHandler#runEvent
org.apache.ofbiz.webapp.control.RequestHandler#doRequest
org.apache.ofbiz.webapp.control.ControlServlet#doGet
org.apache.ofbiz.webapp.control.ControlServlet#doPost

OFBiz根据framework/component-load.xml创建Context,并在相应的WEB-INF/web.xml中指定url-pattern

ControlServlet#doGetthis.getRequestHandler方法实际调用了RequestHandler#getRequestHandler方法。

一直跟到RequestHandler构造方法,由ConfigXMLReader#getControllerConfigURL获取配置文件路径后,经EventFactory构造方法创建对应的handler。

webtools的配置文件/WEB-INF/controller.xml中存在<request-map uri="xmlrpc",并且include了common-controller.xml,再进一步include了handlers-controller.xml

定义了xmlrpc对应XmlRpcEventHandler,即sink所在类。


OFBIZ-11716增加了鉴权配置。

OFBIZ-12332增加了过滤关键字的Filter

CVE-2023-49070

  • 影响 Apache OFBiz < 18.12.10

RequestHandler#doRequest判断securityAuth后,执行checkLoginEvent

进入if分支的条件是security标签auth属性的值为true,对应上文OFBIZ-11716增加的鉴权。

根据webcommon/WEB-INF/common-controller.xml找到LoginWorker#extensionCheckLogin,其进一步调用了LoginWorker#checkLogin

进入343行的if分支则会返回error,否则会顺序执行并返回success。判断条件是逻辑或,跟进login方法。

requirePasswordChange参数为YunpwErrMsgList不为空时,会进入三目运算符分支返回非error字符串。

看到438行/441行,只要用户名/密码为空就存在add,满足if条件绕过身份认证。

至于OFBIZ-12332增加的路径判断,RequestHandler#doRequest业务功能中用了HttpServletRequest#getPathInfo获取路径,而Filter用的HttpServletRequest#getRequestURI,是经典的路径绕过。

另外对</serializable的检查,改改设置XML命名空间的位置,给标签加个前缀即可绕过。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
POST /webtools/control/xmlrpc?USERNAME=&PASSWORD=&requirePasswordChange=Y HTTP/1.1
Host: 127.0.0.1:8443
Content-Type: application/xml
Content-Length: 4104

<?xml version="1.0"?>
<methodCall xmlns:ex="http://ws.apache.org/xmlrpc/namespaces/extensions">
<methodName>xxx</methodName>
<params>
<param>
<value>
<struct>
<member>
<name>xxx</name>
<value>
<ex:serializable>rO0AB...</ex:serializable>
</value>
</member>
</struct>
</value>
</param>
</params>
</methodCall>

OFBIZ-12812删除了Apache XML-RPC相关库和代码

参考链接

Beware of ws-xmlrpc library in your Java App

Apache - Deserialization of Untrusted Data in XML-RPC (CVE-2019-17570)

GHSL-2020-069: Unsafe deserialization of XMLRPC arguments in ApacheOfBiz - CVE-2020-9496

Tomcat URL解析差异性导致的安全问题