Java反序列化系列(2)——反射和URLDNS
Java反序列化系列(2)——反射和URLDNS
前言
上文中我们引出了产生漏洞的攻击路径,这次我们就来实战复现一下ysoserial中的利用链——URLDNS,ysoserial是一款知名的java反序列化利用工具,里面集合了各种java反序列化payload,可以通过看它的源码,来学习java反序列化利用链。
ysoserial项目地址:https://github.com/frohoff/ysoserial
URLDNS利用链分析
URLDNS 就是 ysoserial 中⼀个利用链的名字,但其参数仅为⼀个URL,其能触发的结果也不是命令执行,而是⼀次 DNS 请求。
常常在检测反序列化漏洞时使用。
通过 HashMap 的反序列化调用 URL 的 hashCode 方法发起 DNS 查询,通常用来检测反序列化漏洞的存在。
利用链:HashMap.readObject() -> HashMap.putVal() -> HashMap.hash() -> URL.hashCode()
通过代码来看一看URLDNS链子:
URL 是由 HashMap 的put方法产生的,所以我们先跟进put方法当中。put方法之后又是调用了hash方法;hash方法则是调用了hashcode这一函数。
而这里的key值是我们设置的URL地址,即hashmap.put(new URL("http://rbf5ok.ceye.io),1); 此处key为url,value为1。
因为上面我们的分析,这里会调用key值的hashCode方法,所以我们就去看URL的hashCode方法。
URL 中的hashCode被handler这一对象所调用
而handler又是URLStreamHandler的抽象类。我们再去找URLStreamHandler的hashCode方法。
这里调用了getHostAddress这个方法,这就是我们利用与URLDNS的方法。其实现的功能是根据主机名获取其IP地址,在网络中就是一次DNS查询,会发送请求。
总结一下URLDNS这个Gadget
- HashMap->readObject()
- HashMap->hash()
- URL->hashCode()
- URLStreamHandler->hashCode()
- URLStreamHandler->getHostAddress()
- InetAddress->getByName()
通过代码来利用一下,SerializationTest.java中添加代码
1 | |
先运行将其序列化,我们的目的是希望它在反序列化的过程中向DNSLog发送请求,然而在序列化的过程中就收到了请求。
这是什么呢?回到URL的hashCode方法这里,原来是当hashCode的值不为-1的时候(初始化时hashCode为-1),它就会直接返回hashCode。在我们执行了hashmap.put(new URL("http://rbf5ok.ceye.io),1);以后,hashCode的值实际上就已经变成了url的hashCode了。
问题找到了,那我们的需求自然就是序列化的过程中不向DNSLog发送请求,避免误导判断,以及在反序列化之前将hashCode的值设置成-1,可以通过反射来去修改这个已有对象的属性。
反射
此处我们横云断山,来讲一讲反射。
Java 的反射机制是指在运行状态中,对于任意一个类都能够知道这个类所有的属性和方法; 并且对于任意一个对象,都能够调用它的任意一个方法;这种动态获取信息以及动态调用对象方法的功能成为Java语言的反射机制。
万物有阴必有阳,有正必有反。在了解反射之前,我们先来了解一下什么时”正射”
正射
1 | |
这里实例化了Student类,用实例化好的对象进行操作,这就是正射。
反射
1 | |
反射就是在运行时才知道要操作的类是什么,并且可以在运行时获取类的完整构造,并调用对应的方法。
反射的作用:让Java具有动态性
- 修改已有对象的属性
- 动态生成对象
- 动态调用方法
- 操作内部类和私有方法
在反序列化的漏洞中,反射的作用:
- 定制需要的对象
- 通过invoke调用除了同名函数以外的函数
- 通过Class类创建对象,引入不能序列化的类
下面,我们写一个测试类了解一下如何使用反射
1 | |
输出结果为Person{name='lotus',age23} ,我们成功的通过反射构造了实例p并且完整了赋值
还可以获取类里面的属性
1 | |
如何去修改某个类的属性呢?我们可以先通过getDeclaredField获取该属性,再通过set赋值
1 | |
输出的结果为:Person{name='lotus',age=23} Person{name='lotus',age=25}
这里有三处要注意的点:1、getDeclaredFields获取私有属性 2、 由于age属性为私有属性,要需要通过将setAccessible设置为true允许访问该Fields 3、set赋值的实例就是我们刚刚通过构造函数实例的对象
属性说完了,方法也是一样的方式
1 | |
执行后的结果世事漫随流水,算来浮生一梦,也可以通过getMethods()获取所有方法,与属性相似,这里就不过多赘述。
解决URLDNS利用链遗留问题
回想一下我们想实现的目标,1、序列化是url的hashCode不为-1 不会向dnslog发起请求;2、反序列化的时候向dnslog发起请求
1 | |
通过刚刚反射的学习,我们可以在执行hashMap前修改url的hashCode属性,执行后再次修改其属性。
1 | |
执行序列化,dnslog不会收到请求;执行反序列化,dnslog就能收到请求了
小结
URLDNS这条链子就走完了,但反射的利用方式还有很多,ysoserial里的利用链也还有很多,后续会慢慢补完。