CVE-2021-30128 Apache OFBiz反序列化漏洞分析
影响版本
Apache OFBiz < 17.12.07
环境搭建
这里使用Apache OFBiz 17.12.06
、jdk8u202
搭建环境,配置如下
然后编译即可
编译完成后会生成一个build目录
然后配置JAR Application
这里的jre
版本是OFBiz
运行版本,上面的8u202
是Gradle
编译时用的版本
漏洞分析
diff如下
可以看到这里新增了黑名单DEFAULT_DENYLIST
,内容为rmi
和<
,猜测可能是处理数据时出现的安全问题。和CVE-2021-26295一样,在framework\webapp\src\main\java\org\apache\ofbiz\webapp\event\SOAPEventHandler.java#invoke开始
跟进SoapSerializer#deserialize
跟进XmlSerializer#deserialize
跟进Xmlserializer#deserializeSingle
这里面判断了是否为某种标签然后做出特定处理,最后return deserializeCustom(element);
跟进Xmlserializer#deserializeCustom
这里将序列化数据先进行十六进制解码,再调用UtilObject#getObject
跟进UtilObject#getObjectException
这里wois使用了SafeObjectInputStream类
这里定义了反序列化时的黑白名单,黑名单为不能是java.rmi.server
,白名单为
在修复版本中添加了黑名单<
,从这里的匹配机制可以看出如果使用了<
那么就会绕过黑白名单的处理,看一下后续是怎么解析的。跟进ObjectType#loadClass
可以看到这里取出了<
之前的值
所以我们使用org.apache.commons.beanutils.BeanComparator<xxx
即可绕过,但是到loadClass得先经过白名单,所以使用org.apache.commons.beanutils.BeanComparator<java.xxx
即可。
当然在jdk会对类名进行判断,ObjectStreamClass#initNonProxy
跟进ObjectStreamClass#classNamesEqual
这里只截取了最后一个.
后面的值,所以我们用org.apache.commons.beanutils.BeanComparator<java.BeanComparator
即可绕过。
那我们应该怎么修改序列化数据中的类名呢,这里使用SerializationDumper来dump出序列化数据结构然后修改。
首先利用yso生成CommonsBeanutils1的payload,以十六进制输出
然后利用SerializationDumper输出序列化数据结构
1 | java -jar SerializationDumper-v1.13.jar 十六进制 |
把这几处不满足白名单的都按照上面的绕过方法改一改
最后将其重新编译回去,得到序列化的二进制流
1 | java -jar SerializationDumper-v1.13.jar -b res.txt rebuild.bin |
将其十六进制编码后即为POC