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; |