xss-labs Level3 代码审计报告
目标文件:
level3.php| 漏洞类型: 反射型 XSS —— 单引号属性上下文注入 | CWE: CWE-79 / CWE-80 | 危害等级: 中危(依赖 PHP 版本,见备注)
风险路径:GET /level3.php?keyword=<payload>→<input value='...'>单引号属性注入
一、漏洞代码定位
level3.php 第 17-22 行:
$str = $_GET["keyword"];
echo "<h2 align=center>没有找到和".htmlspecialchars($str)."相关的结果.</h2>"."<center>
<form action=level3.php method=GET>
<input name=keyword value='".htmlspecialchars($str)."'> // L20 单引号包裹 + htmlspecialchars
<input type=submit name=submit value=搜索 />
</form>
</center>";
漏洞点: L20。属性值用单引号包裹,并做了 htmlspecialchars()。看似"既转义又引号包裹",但:
htmlspecialchars()的默认标志位是ENT_COMPAT(旧版 PHP 默认只转义双引号",不转义单引号'),因此单引号'仍能原样穿出属性。- 开发者误以为"转义了"就是安全的,忽略了单引号包裹 + 默认标志位这一组合。
二、漏洞原理
- 属性
value='...'用单引号定界,而htmlspecialchars($str)在旧版 PHP 下不转义',攻击者用一个'即可闭合属性,再注入事件属性。 - 注意与 Level2 的区别:Level2 是"完全没转义",Level3 是"转义了但定界符用错了(单引号)+ 默认标志位漏转义"。
三、利用方式与 Yakit 可重放数据包
Payload(URL 解码后):
?keyword=' onfocus=alert(1) autofocus='
渲染结果: <input name=keyword value='' onfocus=alert(1) autofocus=''> → 单引号闭合 value,注入 onfocus + autofocus,autofocus 自动聚焦并触发 onfocus。
Yakit 可重放原始请求:
GET /level3.php?keyword=%27%20onfocus=alert(1)%20autofocus=%27 HTTP/1.1
Host: 127.0.0.1
User-Agent: Mozilla/5.0
Accept: text/html
Connection: close
触发方式: 页面加载后输入框被 autofocus,onfocus 触发 alert(1) → 命中通关逻辑跳转 level4。
四、修复建议
$str = $_GET["keyword"] ?? "";
$safe = htmlspecialchars($str, ENT_QUOTES, 'UTF-8'); // 明确 ENT_QUOTES,同时转义单引号与双引号
echo "<h2 align=center>没有找到和".$safe."相关的结果.</h2>"
. '<center>
<form action=level3.php method=GET>
<input name=keyword value="'.$safe.'"> // 属性定界符统一改用双引号
<input type=submit name=submit value=搜索 />
</form></center>';
要点:
- 永远显式指定转义标志位
ENT_QUOTES,不要依赖htmlspecialchars()的默认值(不同 PHP 版本默认值不同,极易被误用)。 - 属性定界符统一用双引号,与转义策略保持一致。
- 配置
php.ini/代码中显式声明默认编码,避免编码推断导致的转义失效。
五、备注
- PHP 版本依赖(重要): 本关经典利用仅在 PHP < 8.1 有效 —— 旧版
htmlspecialchars()默认ENT_COMPAT,不转义单引号。PHP 8.1+ 已把默认值改为ENT_QUOTES,默认就会转义'(输出为',浏览器解析后是属性值内部的字符而非定界符),该利用默认失效。 - 因此审计结论: 旧环境(PHP 5.x / 7.x)中危可利用;新环境(PHP 8.1+)该点默认已免疫,但仍建议按"修复建议"统一加固,因为这是"靠默认值碰巧安全"的脆弱代码。
- 若需在 PHP 8.1+ 复现教学场景,可在
php.ini或代码里手动htmlspecialchars($str, ENT_COMPAT)模拟旧行为。
正文完