java反序列化漏洞之URLDNS
0x00 什么是序列化和反序列化
序列化就是将对象转换为字节序列的过程, 反序列化就是把字节序列恢复为对象的过程。
将对象序列化以后可以在一定程度上保证对象的完整性和可传递性,便于在网络上传输或者保存在本地文件中。序列化机制使得对象可以脱离程序的运行而独立存在。
为什么要使用序列化和反序列化 ?
- 对象序列化可以实现分布式对象
- java对象序列化不仅保留一个对象的数据,还会递归保存对象引用的每个对象的数据
- 序列化可以将内存中的类写入文件或数据库中
- 对象、文件、数据拥有多种不同的文件格式,很难统一传输和保存
0x01 ysoserial
在提到反序列化漏洞利用链前,我们就跳不过一个里程碑式的工具。ysoserial,它是2015年由Gabriel Lawrence (@gebl)和ChrisFrohoff (@frohoff)这两位大神在AppSecCali上放出的一个工具,它可以让⽤户根据⾃⼰选择的利⽤链,⽣成反序列化利⽤数据,通过将这些数据发送给⽬标,从⽽执⾏⽤户预先定义的命令
什么是利用链?
利用链也叫“gadget chains”,通常称为gadget,可以理解为一种方法,从漏洞触发位置开始到执行命令的位置结束,一种生成poc的方法。
0x02 URLDNS
URLDNS是ysoserial中一个利用链的名字,准确的来说,它并不能称之为一个利用链;因为它的参数不是一个可以利用的命令,而仅为一个URL,其触发的结果也不是命令执行,而是一次DNS请求
虽然这个利用链
实际上是不可利用
的,但因为其有如下的优点,非常适合我们在检测反序列化漏洞时使用:
- 使用java内置的类构造,对第三方库没有依赖
- 在目标没有回显的时候,能通过DNS请求得知是否存在反序列化漏洞
ysoserial中的URLDNS代码:
1 | public class URLDNS implements ObjectPayload<Object> { |
0x03 URLDNS利用链分析
3.1 配置IDEA环境
去github上将yso源码下载下来,ysoserial。然后用IDEA打开,因为他是maven打包的项目,在打开后IDEA会自动根据配置下载依赖。
然后我们找到URLDNS类,并配置Debug Configurations
修改Program arguments,加上运行时的命令行参数即可( http://xxx.xxx.com)
3.2 开始调试
因为触发反序列化的⽅法是 readObject
,又因为Java开发者(包括Java内置库的开发者)经常会在这⾥⾯写⾃⼰的逻辑,所以导致可以构造利⽤链。
我们直接看HashMap
中的readObject
方法,发现他在如下图中位置将HashMap
的键名计算了hash
在这个位置下个断点,对这个hash函数进行调试并跟进,这是调用栈:
hash
方法调用了key的hashCode()
方法:
然后再看看hashCode
方法:
此时,handler
是URLStreamhandler
对象,在继续跟进hashCode
方法
这⾥有调⽤getHostAddress
⽅法,继续跟进:
这⾥ InetAddress.getByName(host)
的作⽤是根据主机名,获取其IP地址,在⽹络上其实就是⼀次 DNS查询。到这⾥就不必要再跟了。 我们⽤⼀些第三⽅的反连平台就可以查看到这次请求,证明的确存在反序列化漏洞:
到这里,整个URLDNS
的Gadget就出来了
- HashMap->readObject()
- HashMap->hash()
- URL->hashCode()
- URLStreamHandler->hashCode()
- URLStreamHandler->getHostAddress()
- InetAddress->getByName()