免责声明!
本公众号所分享内容仅用于网络安全技术讨论,切勿用于违法途径,所有渗透都需获取授权,违者后果自行承担,与本号及作者无关,请谨记守法
。
大 纲
上一文章我们学习了Java反序列化的含义和应用场景以及如何在JDK自带的io包里面实现序列化和反序列化,和JDK反序化漏洞成因。本文章我们开始学习由AnnotationInvocationHandler类引起的反序列化漏洞,即Apache Commons Collections反序化漏洞。
1
环境配置:
2
Apache Commons Collections介绍:
Apache Commons Collections是一个开源的Java工具库,由Apache软件基金会维护。它扩展了Java标准集合框架(java.util.collections),提供了更多高效、灵活的数据结构和工具类,帮助开发者简化集合操作、处理复杂数据逻辑。
Commons Collections包为Java标准的Collections API提供了相当好的补充。在此基础上对其常用的数据结构操作进行了很好的封装、抽象和补充。让我们在开发应用程序的过程中,既保证了性能,同时也能大大简化代码。
3
Java反射机制:
(1) Java程序运行原理:
S1:编译器(javac)将.java源代码文件编译为.class字节码文件;
S2:Java虚拟机(JVM)通过类加载器动态加载字节码到内存,这一步骤分为三个阶段,即加载、链接和初始化。
S3:JVM通过执行引擎解释内存中的字节码(形成多种计算机指令,不同系统对应不同的指令,从而实现了跨平台),然后自动回收内存垃圾。
(3) Java反射机制:
Java反射机制(Reflection)是Java语言的一项高级特性,允许程序在运行时动态地获取类的信息、操作对象的属性和方法,甚至突破封装访问私有成员(在程序运行的时候动态创建一个类的实例,调用实例的方法和访问它的属性)。
这种能力为框架开发、动态代理、序列化等场景提供了强大的灵活性,但也需要谨慎使用以避免性能和安全问题。
<3> 没有使用Java反射机制的代码示例:
// It will open the calculator program on Windows platform.
public class Testfile1 {
public static void main(String[] args) {
try {
// 初始化Runtime类
Class clazz = Class.forName("java.lang.Runtime");
// 调用Runtime类中的方法得Runtime类的对象
Object rt = clazz.getMethod("getRuntime").invoke(null);
// 再次使用invoke方法调用Runtime类中的方法时,传递我们获得的对象,这样就可以调用
clazz.getMethod("exec", String.class).invoke(rt, "calc.exe");
} catch (Exception e) {
e.printStackTrace();
}
}
}
Java反射机制核心操作步骤:
S1:加载Runtime类(获取class对象):
借助Class.forName方法动态加载java.lang.Runtime类,Class.forName会返回一个Class对象,这个对象代表着指定类。
S2:获取Runtime类的实例:
运用getMethod方法获取Runtime类的getRuntime方法,然后通过invoke方法调用该方法。由于getRuntime是静态方法,所以invoke的第一个参数为null。
S3:调用exec方法启动计算器:
获取Runtime类的exec方法,并且调用它来启动Windows系统的计算器程序。exec方法的参数是一个字符串,代表要执行的命令。
4
反序列化漏洞原理:
Java原生的反序列化要利用一定要满足两个条件,即入口类实现了序列化接口并且重写了readObject函数。实现序列化接口的类才能被Java序列化和反序列化,重写readObject方法才有可能执行到危险方法。否则无法调起和执行其他代码,更无从谈起利用。
5
Apache Commons Collections反序列化漏洞原理:
(1) 影响范围:
实现了Transformer链式调用,我们只需要传入一个Transformer数组
ChainedTransformer就可以实现依次的去调用每一个Transformer的
transform方法。
<3> ConstantTransformer类:
为了获得一个对象,transform()它会返回构造函数的对象。
<4> TransformedMap类:
InvokeTransformer类,ChainedTransformer类和ConstantTransformer类都是Transformer接口的一个子类,而TransformedMap类中就是存储了以上这三个子类,它的key和value都是transformer。
前面我们讲了可以通过Java的反射机制动态的创建一个类(对象),那么我们同样也可以利用Java的反射机制动态的构造一个恶意类,这就造成了我们的CC漏洞。
S2:Java反序列化时,readobject方法触发memberValues(即LazyMap)的entrySet().iterator()操作;
S3:LazyMap.get()或者TransformedMap的checkSetValue调用chainedTransformer.transform();
S4:通过InvokerTransformer类反射链最终执行Runtime.exec("calc.exe")。
6
CC1调用链:
(1) 传统的CC1链构造过程:
https://mvnrepository.com/artifact/commons-collections/commons-collections/3.2.1
https://hg.openjdk.org/jdk8u/jdk8u/jdk/rev/af660750b2f4
<2> CC1调用链漏洞的源码示例及详解:
CC调用链的代码流程如下:
源码:
import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.functors.ChainedTransformer;
import org.apache.commons.collections.functors.ConstantTransformer;
import org.apache.commons.collections.functors.InvokerTransformer;
import org.apache.commons.collections.map.TransformedMap;
import java.io.*;
import java.lang.annotation.Target;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
执行效果:
代码详解:
在Commons Collections中有一个Transformer接口,其中包含一个 transform方法,通过实现此接口来达到类型转换的目的。
我们可以看到Transformer接口主要三个实现类,分别为ConstantTransformer类、invokerTransformer类和
ChainedTransformer类。
InvokerTransformer类:
在Transformer方面里面可以看到使用getClass()方法获取了一个对象,前面我们在讲Java反射机制的时候使用Class.forName()方法获得了一个对象,这两种方法都是用来获得一个对象。
实现了通过反射来调用某方法,可以看到transform方法,接收input对象,然后反射调用,参数全是可以控制的。
问题:
这里为什么说是可控的呢?
回答:
我们看一下构造方法就会明白,这里其实就是一个很标准的任意方法调用。
ConstantTransformer类:
我们可以看到接受一个对象返回一个常量,无论接收什么对象都返回iConstant这个常量在构造函数当中。
ChainedTransformer类:
当传⼊的参数是⼀个数组的时候,就开始循环读取,对每个参数调用transform⽅法,从而构造出⼀条链。它赋值时会传入一个要调用方法的数组,然后将传入的方法链式(前一个的输出作后一个的输入)调用。
import org.junit.Test;
import java.io.*;
public class CC {
public static void serialize(Object obj) throws Exception {
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.bin"));
oos.writeObject(obj);
}
public static Object unserialize(String filename) throws Exception {
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(filename));
Object obj = ois.readObject();
return obj;
}
public void test() throws Exception {
unserialize("cc1.ser2");
}
}
没看够~?欢迎关注!
往期推荐
Web篇 | 一文掌握Java反序列化漏洞,干货!(上)
工具篇 | 把deepseek塞进微信:实现自动回复消息!王炸!!!
内网篇 | 【送给小白的】内网信息收集:端口扫描详解,干货!!!
漏洞复现篇 | CVE-2025-24813 Tomcat,最新RCE漏洞,速看!!!
内网篇 | 史上最全的内网IP扫描攻略,干货!
内网篇 | 干货!深入解析NTLM协议:挑战-响应认证机制揭秘,红队必备!
Web篇 | 最强sqlmap联动burpsuite+WAF绕过姿势,Hvv面试必备!
Web篇 | 技巧!布尔盲注-利用burpsuite实现半自动化
漏洞复现篇 | Ecshop SQL注入引起的任意代码执行漏洞
SRC篇 | 如此简单的逻辑漏洞,速看!!!
内网篇 | 干货!Windows系统本地认证
红队必备:一文教你掌握pwd抓取技术,让你秒变高手!
SRC篇 | 今天你挖洞了吗?Webpack未授权访问漏洞,实战!
原文始发于微信公众号(零日安全实验室):Web篇 | 一文掌握Apache Commons Collections反序列化漏洞,速看!!!(上)
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论