整理下cc链,开局先上图,做了好几个小时
可以看出其实这么多条链都只是排列组合,基本没有非用哪条链不可的情况。这8条链里面,到执行点sink前有6条路径到ChainedTransformer.transform,一条路径到TransformingComparator.compare,共7种。而执行点中有3种执行方法,所以只从已有链出发就能推出21条链。
还可以添加新的元素,比如使用DefaultedMap代替LazyMap,或者添加URLClassLoader.loadClass作为执行点,都可以创造所谓的新的链条,根据需求修改即可。
大概写了下各条链的简易版,顺序按照直觉:
CC1
CC1用IncokerTransformer+Runtime作为代码执行点,调用链用LazyMap.get。触发点用的是AnnotationInvocationHandler,因此受到jdk版本限制,需要jdk<8u71。
1 | Transformer[] transformers = new Transformer[]{ |
CC6
CC6将触发点改成了HashMap,解决了jdk版本限制的问题,其他和CC1一样。写Poc时候注意两个问题,一是LazyMap在put时会触发调用链导致本地执行,二是LazyMap触发一次后会添加key导致不能再次触发,这两个问题都可以通过反射改值解决。先放个没用的transfromer,序列化前再改回来。
1 | Transformer[] transformers = new Transformer[]{ |
CC3
CC3的触发和调用链部分和CC1相同,因此同样受jdk版本限制。主要修改了代码执行的地方,调用了jdk原生的TemplatesImpl+TrAXFilter类,实现动态类加载,引入了新的代码执行点。
1 | TemplatesImpl templates = new TemplatesImpl(); |
需要按照代码要求构造动态加载的类Test.java,照着报错调就行
1 | public class Test extends AbstractTranslet { |
CC5
和CC6基本没区别,改了触发点,从HashMap变成了BadAttributeValueExpException。没什么特别意义,只是又多了一个从toString到get的链路。
1 | Transformer[] transformers = new Transformer[]{ |
CC4
代码执行部分和CC3一样用的是TemplatesImpl+TrAXFilter。修改了触发点和调用链部分,调用链使用了在CommonsCollections4里才实现Serializable接口的TransformingComparator类,触发点使用了优先队列,提供了一个使用compare的链路。
1 | TemplatesImpl templates = new TemplatesImpl(); |
CC2
和CC4一样都是CC4.0版本下的利用链,区别是代码执行部分改成了用InvokerTransformer触发动态类加载和初始化,并且不使用Transfromer数组了。由于不依赖ConstantTransformer,所以需要在最外层的参数里把构造好的templates传进去。
1 | TemplatesImpl templates = new TemplatesImpl(); |
CC7
和CC6差不多,把触发点改成了HashTable,提供了一个使用equals方法的调用链,不受jdk限制,没啥特别的了。两个Map需要hash相等,其实不需要哈希碰撞,随便写一个值异或回来就行。
1 | Transformer[] transformers = new Transformer[]{ |
ysoserial里面的CC链就这些,实际上并不代表这些链就是完美的,了解了原理根据需要去改就行了,有点像拼乐高,一块一块的。