URLDNS
1 | public static void main(String[] args) throws MalformedURLException { |
如果这样执行的话,就会对url发起DNS解析,
可以调试看看:
首先调用HashMap的put方法。
1 | public V put(K key, V value) { |
会通过hash函数调用key.hashCode()计算key的hashCode;
1 | static final int hash(Object key) { |
key是传入的URL对象,最终调用URL对象的hashCode函数,
1 | public synchronized int hashCode() { |
handler是URLStreamHandler的对象;handler在构造函数时被赋值了
1 | transient URLStreamHandler handler |

接着调用了URLStreamHandler.hashCode中的getHostAddress(u)方法导致DNS解析

poc
1 | package demo1; |
CommonsCollections6
前部分和URLDNS一样,后半部分和CC1一样,中间该用了TiedMapEntry
可以看看TiedMapEntry类一部分代码
1 | public class TiedMapEntry implements Map.Entry, KeyValue, Serializable { |
hashCode调用了getValue();其中getValue调用了get方法,并且map是可控的,
Gadget chain:
1 | ObjectInputStream.readObject() |
从CC1的基础上就加了两行代码
1 | Transformer[] transformers = new Transformer[]{ |
和URLDNS一样的特点(又有差异),在反序列化时就会执行命令,但是URLDNS链在序列化执行命令后,如果不做修改;反序列化就不会执行了
但是CC6不一样,他是序列化和反序列化都会执行命令;所以感觉就是不做修改也无伤大雅
如果要使得序列化时不调用的话,和URLDNS类似的修改就可以了
1 | package demo1; |
CommonsCollections5
和CC6差不多,只是入口链不一样
CC6是利用TiedMapEntry中的hashCode函数;CC5是利用TiedMapEntry中的toString函数;为什么还可以利用toString方法;其实也就是因为toString也调用了调用了getValue方法的原因
1 | public String toString() { |
BadAttributeValueExpException这个类的readObject调用valObj.toString(),valObj的值是可控的;尽管BadAttributeValueExpException没有实现 Serializable 接口的情况下,任然可以序列化
GPT:BadAttributeValueExpException类可能使用了一种特殊的序列化方式,使其能够在没有实现 Serializable 接口的情况下被序列化。一些标准的异常类,如 RuntimeException 的子类,有时会被设计成可序列化的,即使它们没有显式地实现 Serializable 接口。
1 | private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException { |
Gadget chain:
1 | ObjectInputStream.readObject() |
poc
1 | package demo1; |
CommonsCollections7
1 | ObjectInputStream.readObject() |
CC7这条链前半部分有点绕;
先利用HashMap中putVal方法,通过哈希碰撞(其实就是两个节点放在了数组中的同一个位置,HashMap本来就是数组+列表的形式);
然后会调用key.equals(k);要添加的key对象的equals方法,k是数组中已存在的对象;
1 | final V putVal(int hash, K key, V value, boolean onlyIfAbsent, |
CC7是将key的值为一个Lazymap对象,所以会调用Lazymap.equals,但是Lazymap没有equals方法,所以找到了lazymap的父类AbstractMapDecorator;
1 | public boolean equals(Object object) { |
map的值为当前调用put方法的HashMap,然后就会调用HashMap的equals方法;但是HashMap没有equals方法,所以找到了HashMap的父类AbstractMap;(一开始没搞太懂map是什么时候被赋值为当前调用put方法的HashMap的,调试后发现是通过LazyMap的构造函数super(map);)
注意:在AbstractMap.equals方法中,将对象o(也就是Hashmap数组中已经存在的Hashmap对象,并不是当前调用put方法的Hashmap对象)赋值给了m;然后调用m.get(key),如果对象o是一个恶意的Lazymap对象,就会调用Lazymap.get
1 | public boolean equals(Object o) { |
poc
1 | package demo1; |

