1. XSS (Reflected) - 反射型
反射型 XSS 是最基础的考点,重点在于理解“输入即输出”。
知识点与技能
- 黑名单绕过:大小写混淆、双写绕过。
- 标签替换:当 <script> 被禁用时,利用 <img>, <a>, <svg> 等标签触发事件。
- 属性注入:在已有标签的属性中构造恶意代码。
通关攻略
| 等级 | 防御逻辑 | 通关 Payload (示例) | 核心技巧 |
|---|---|---|---|
| Low | 完全没有任何过滤。 | <script>alert(1)</script> | 基础测试。 |
| Medium | 使用str_replace过滤了<script>标签。 | <sCript>alert(1)</sCript> | 大小写绕过(PHP 函数对大小写敏感)。 |
| High | 使用preg_replace正则过滤了所有包含<script的模式。 | <img src=x onerror=alert(1)> | 更换标签。利用图片加载失败触发onerror事件。 |
| Impossible | 使用htmlspecialchars()将特殊字符转义为 HTML 实体。 | 无(除非浏览器有 0-day)。 | 防御核心:<变<,脚本不再被解析。 |
2. XSS (Stored) - 存储型
知识点与技能
- 前端限制绕过:利用 F12 修改 maxlength 属性。
- HTTP 头部注入:有时输入点不在表单,而在 User-Agent 或 Referer。
- 存储位置分析:Payload 在哪个页面触发,是否影响管理员后台。
通关攻略
| 等级 | 防御逻辑 | 通关 Payload (示例) | 核心技巧 |
|---|---|---|---|
| Low | 对输入没有任何处理。 | <script>alert(1)</script> | 直接在留言板输入。 |
| Medium | 对 Message 过滤了标签,对 Name 限制了长度。 | Name:<sCrIpT>alert(1)</sCrIpT> | F12 修改长度限制。利用 Name 字段绕过对 Message 的严格过滤。 |
| High | 更加严格的正则过滤。 | <img src=1 onerror=alert(1)> | 同样使用非 script 标签触发。 |
| Impossible | 严格的实体转义和 Token 验证。 | 无。 | 完全转义,数据被视为纯字符串处理。 |
3. XSS (DOM) - DOM 型
DOM 型 XSS 不经过后端服务器处理,完全发生在浏览器端。这需要你具备较强的 JavaScript 审计能力。
知识点与技能
- 前端代码审计:通过 F12 查看 JS 逻辑,寻找 innerHTML, document.write, eval() 等危险函数。
- URL 锚点利用:利用 # 号后的内容不发送到服务器的特性绕过后端检查。
- 路径解析:理解浏览器如何解析 URL 中的参数。
通关攻略
| 等级 | 防御逻辑 | 通关 Payload | 核心技巧 |
|---|---|---|---|
| Low | 直接从 URL 参数取值并document.write。 | ?default=<script>alert(1)</script> | 直接修改 URL 传参。 |
| Medium | 后端检查 URL 中是否包含<script。 | ?default=English&<img src=1 onerror=alert(1)> | 闭合与插入。后端只查default后面的值,利用&引入新标签。 |
| High | 使用白名单,只允许 English, French 等固定值。 | ?default=English#<script>alert(1)</script> | 利用#绕过。#之后的内容不会传给服务器,从而绕过后端的白名单校验。 |
| Impossible | 不再直接解析 URL,对输入进行硬编码处理。 | 无。 | 逻辑层加固,不再将 URL 参数作为指令执行。 |
一上午通关两个靶场,速度确实很快,但也正因为太快,你可能只记住了 Payload(招式),而没领悟到“内功心法”。
在安全实习面试中,面试官不在乎你背了多少个 <script> 脚本,他们在乎的是:“当给你一段混在几千行业务逻辑里的 PHP/JS 代码时,你能不能一眼看出这里会出事?”
这就是你说的代码审计和防御本质。以下是 XSS 学习中最精髓的三个点:
一、 XSS 的精髓:数据与指令的“边界模糊”
XSS 的本质只有一句话:“由于程序没有分清‘用户数据’和‘程序指令’,导致用户数据被浏览器当成了程序指令执行。”
- 正常情况:你输入 Hello,浏览器把它当成文字渲染。
- 异常情况:你输入 <script>...,浏览器以为这是开发者写的代码,于是执行了它。
精髓点: 所有的 XSS 攻击,都是为了“闭合”掉当前的正常环境,并“开启”一个恶意环境。
- 如果在 <div> 标签里,你要闭合 <div>;
- 如果在 value="..." 属性里,你要先用 " 闭合属性,再用 > 闭合标签。
二、 如何看函数语法功能(代码审计基础)
在 DVWA 中,每一关都有 View Source。看代码时,你只需要盯着三个核心要素:输入、过滤、输出。
1. 寻找输入点 (Source)
看代码里是怎么拿用户数据的。
- PHP:$_GET['name']、$_POST['message']、$_COOKIE['id']。
- JS (DOM型):location.search、document.referrer、window.name。
审计思路:只要是用户可控的地方,都是潜在的毒源。
2. 识别过滤函数 (Sink 处理)
这是决定漏洞等级(Low 到 Impossible)的关键。你需要熟悉这些常见的防御函数:
| 函数名称 | 功能与弱点 |
|---|---|
| str_replace() | 功能:替换字符串。弱点:通常只替换一次,或者区分大小写。例如只删<script>,你写<sCript>就过了。 |
| preg_replace() | 功能:正则匹配替换。弱点:如果正则表达式写得不严谨(比如没加全局匹配/g),依然可以被绕过。 |
| htmlspecialchars() | 功能:转义< > & " '为 HTML 实体。弱点:默认不转义单引号(除非加了参数),且对href里的伪协议无效。 |
| strip_tags() | 功能:剥离 HTML 标签。弱点:有时会误伤正常业务,且处理不当可能留有残余。 |
3. 查看输出位置 (Sink)
看数据最后是怎么显示在页面上的。
- echo / print:直接输出到 HTML。
- document.write() / .innerHTML:JS 动态写入。注意:.textContent 或 .innerText 是安全的,因为它们只解析为文本。
三、 实战中的“语法审计”怎么做?
当你看到一段代码时,按照这个逻辑走:
追踪变量:变量 $user_input 进来后,中间经历了哪些函数?
模拟解析:
- 如果是 echo "<div>".$user_input."</div>"; -> 找标签绕过。
- 如果是 echo "<input value='".$user_input."'>"; -> 找单引号闭合绕过。
找“漏网之鱼”:开发者是否只过滤了 <script>?那我能不能用 <img onerror=...>?是否只过滤了双引号?那我能不能用单引号?
1. 深度理解“上下文”(Context)
这是 XSS 审计的最核心逻辑。同一个 Payload,在不同的输出位置,命运完全不同。
HTML 正文环境:输出在 <div>$input</div>。
- 核心:寻找能执行 JS 的标签(<script>、<img>、<svg>)。
HTML 属性环境:输出在 <input value="$input">。
- 核心:必须先用 " 或 ' 闭合掉属性,再用 > 闭合标签。
- 面试考点:如果 > 被过滤了怎么办?你可以利用属性本身的事件,如:" onfocus="alert(1)" autofocus="。
JavaScript 变量环境:输出在 <script>var name = '$input';</script>。
- 核心:这是最容易被忽略的。你不需要任何尖括号 < >。
- Payload:'; alert(1); //。用单引号闭合字符串,分号结束语句,// 注释掉后面的残留。
2. 浏览器解析特性的“奇技淫巧”
WAF(防火墙)通常是基于正则表达式的,而浏览器解析 HTML 是非常“宽容”的。利用这种差异,就是绕过的精髓。
编码绕过:
- 十进制/十六进制编码:在 HTML 属性中,<img src=x onerror="alert(1)">。
- URL 编码:在 href 属性中,javascript:%61%6c%65%72%74%28%31%29。
利用 HTML5 新特性:
- 很多旧的 WAF 只认识 onerror,但不认识 <details ontoggle=alert(1)> 或者 <video><source onerror=alert(1)>。
宽字节与字符集绕过:
- 在某些老旧系统中,利用特殊的字符编码(如 GBK)可能会导致转义符号 \ 被“吃掉”,从而逃逸出引号。
3. 从 XSS 到权限接管的“后渗透”
CSRF + XSS 组合拳:
- 如果后台有添加管理员的功能,但有 CSRF 令牌(Token)保护。你可以利用 XSS 脚本在管理员浏览器里读取 Token,然后伪造一个添加账号的 POST 请求。
获取内网信息:
- 利用 JS 发起 Ajax 请求,扫描管理员所在的内网 IP 段(探测内网其他弱口令设备)。
持久化控制(XSS 后门):
- 利用 Service Worker。一旦在用户浏览器中植入,即使页面关闭,你的恶意 JS 依然可以在该域下运行。
在做题或审计时,养成一个习惯:右键“检查”,看你的 Payload 注入后,在 DOM 树里长什么样。
- 它是被删了?
- 是被转义成了 <?
- 还是被完整地放在了引号里?