XSS Nedir?

Herkese merhabalar bugün xss hakkında uzunca konuşacağız. Sizler için sayfanın en alt kısmında sıkça kullandığımız ve karşınıza çıkabilecek terimleri açıklamalarıyla beraber derleyip mini bi sözlük hazırladık hepinize iyi okumalar dilerim.
XSS, yani Cross-Site Scripting, bir web güvenlik açığıdır. Saldırganların, bir web uygulamasına kötü niyetli JavaScript (veya başka script) kodları enjekte etmesine olanak tanır. Bu kod daha sonra o siteyi ziyaret eden kurbanın tarayıcısında çalıştırılır , kısaca XSS = Kullanıcının tarayıcısında istenmeyen kodun çalıştırılması da denebilir.

XSS Türleri

Reflected XSS (Yansıyan XSS)

  • Zararlı kod URL’ye veya bir parametreye eklenir.
  • Kullanıcı linke tıkladığında tarayıcıda çalışır.
  • Genelde phishing ve sosyal mühendislik ile birleştirilir.

Stored XSS (Kalıcı XSS)

  • Zararlı kod sunucuya kaydedilir örneğin yorumlar, forum mesajları vs.
  • Diğer kullanıcılar sayfayı açtığında kod otomatik çalışır.
  • En tehlikeli türüdür.

DOM-Based XSS

  • Zararlı kod doğrudan tarayıcı tarafında (JavaScript DOM manipülasyonu) çalışır.
  • Sunucuya gitmeden, sayfa üzerinde çalışan script’lerin yanlış işlenmesiyle oluşur.

XSS ile Neler Yapılabilir?

  • Çerez (cookie) çalmak → Oturum ele geçirmek
  • Kullanıcı adına işlem yapmak
  • Phishing amaçlı sahte formlar göstermek
  • Keylogger yerleştirmek
  • Kullanıcıyı başka sayfalara yönlendirmek

1. Keşif

URL parametreleri (?q=, id=, search=)

POST body alanları (form , yorum kısımları, profil alanları)

HTTP başlıkları (Referer, User-Agent gibi) bazı uygulamalar bunları sunucuda gösterir

Upload edilen içerikler (örneğin profil bio, görüntü alt metin)

JSON/REST API parametreleri ve AJAX istekleri

DOM kaynaklı noktalar: sayfa içindeki JavaScript ile kullanıcı girdisinin DOM’a yazıldığı yerler (innerHTML, document.write, eval vb.)

Reflected XSS:

Karşımıza bir web sitesi çıktı ve bu sitede arama yapabildiğimiz bir search kısmı var.

resim

Buradan hareketle yazdığım herhangi bir içeriğin html de göründüğünü fark ediyorum ve aklıma şöyle bir yazarsam nasıl bir sonuç alırım diye sorular geliyor:

resim

Ve BUM! gördüğünüz gibi uygulama <b>taglarını sayfaya dahil etti ve kalın merhaba yazdırdı. Bunu kaynak koddan da görmekte fayda var:

resim
İnput alanına yazılan HTML kodlarının sunucu tarafında yorumlandığı ve çalıştırıldığının görülmesinden sonra söz konusu alana XSS zafiyetini tetikleyecek payload yazdık ve search girdi alanına payload olarak <script>alert("introvert was here")</script> ifadesini girdik. Eğer web uygulaması XSS zafiyetini barınıdıyorsa bu komut sunucu tarafında çalıştırılacak ve “introvert was here” içeren bir pop-up kutucuğu açılacaktır. Payload girildikten sonra search butonuna tıklandığında oluşan url aşağıda verilmiştir.

resim

NOT: kaynak kod içinde payload görünüyorsa sunucu tarafından dönüyor (reflected). Kaynak kodda yok ama Elements içinde görünüyorsa client-side (DOM XSS).

resim

Çoğu uygulama < > gibi karakterleri escape eder, burada şanslıydık ama daha sonraki denemelerimizde alternatif payload’lar denemeliyiz.

Şimdi kendimize şunu sormalıyız:

Reflected mi? (payload URL’de Response içinde gözüküyor mu — kaynak kod kontrolü)

Stored (Kalıcı) mı? (payload veritabanına kaydediliyor ve başkaları tarafından görüntülendiğinde çalışıyor mu?)

DOM-based mi? ( kaynakda gözükmüyor ama Elements panelinde DOM’a JS ile yazılıyor)

Bu üçünden hangisi olduğuna göre risk seviyesi değişir.

Şu anki durumumuza bakılırsa bunun reflected xss olduğuna varabiliriz.Şimdi bir başka senaryomuzda stored xss testi yapalım ve aradaki farkı görelim.

Stored XSS:
Bu xss türünde text inputuna girilen veri, veriyi giren kullanıcı ve veri giriş tarihiyle birlikte sayfa içerisine kalıcı olarak yerleştirilmektedir.
İnput alanına girilen değerler eğer bir filtrelemeden geçirilmiyor ve olduğu gibi sayfa kaynak kod içerisine gömülüyorsa bu durumda girilen veri kalıcı olacağından sayfayı ziyaret eden tüm kullanıcılar tarafından görüntülenecek ve işlenecektir.

resim

resim

Evet, diğer herkesin yorumu ince yazı iken benimki kalın oldu. Şimdi exploit edebilecek miyiz bakalım. Basit bir script ile devam edelim:

<script>alert('introvert')</script>

Girilen payload herhangi bir filtrelemeden geçmeden sayfa kaynak kodu içerisine yerleştirilmiştir. Bu aşamadan sonra söz konusu sayfayı kullanıcılar ziyaret ettiklerinde payload çalışacak ve akranda “introvert” yazılı bir pop-up çıkacaktır. Stored XSS zafiyetinin Reflected XSS zafiyetinden daha tehlikeli olmasının nedeni de sayfayı ziyaret eden tüm kullanıcılarda girilen payloadın çalıştırılmasıdır.

Şu ana kadar kadar gerçekleştirilen testler bize gösterdi ki kullanıcı tarafından alınan herhangi bir veri eğer sayfa kaynağı içerisine yerleştiriliyor ise bu durum XSS zafiyetine neden olabilmektedir.

NOT: Söz konusu test sayfası üzerinde herhangi bir girdi alanının olmaması , bu sayfa üzerinde zafiyet testi yapılmayacağı anlamına gelmemektedir. Ziyaretçiye ait user-agent bilgisinin ekrana yazılabilmesi için, söz konusu bilginin bir GET metodu ile sunucuya aktarılması gerekmektedir. Dolayısı ile söz konusu GET isteği sunucuya iletilmeden önce bir proxy yardımı ile yakalanır ve header alanları değiştirilir ise zafiyet testi gerçekleştirilebilir.

resim_
resim

DOM XSS:

DOM XSS, payload’ın sunucu tarafında değil doğrudan tarayıcıda işlenip DOM’a yerleştirilmesiyle oluşur. Yani kaynak (location, document.referrer, localStorage, vs.) → tainted data → (ör. sink, innerHTML, eval, insertAdjacentHTML, setAttribute vb.) akışı vardır.
Şimdiki senaryomuz şu şekilde; elimizde yine bir arama kısmı var ve oraya merhaba yazdığımda ansayfaya sağ tık incele dediğimizde DOM kısmında görüntüleyebiliyoruz:

resim

NOT:
XSS’de “sink” ,verinin (kötü niyetli payload’ın) çalıştırıldığı veya etkisini gösterdiği yer.Yani kullanıcıdan gelen (tainted) veri bir sink’e ulaşırsa XSS gerçekleşir.

Source (kaynak):Kullanıcı kontrollü veri nereden geliyor? (ör. location.search, location.hash, document.referrer, form input, DB’den gelen comment).
Taint flow: Bu verinin uygulama boyunca izlediği yol.
Sink:Bu verinin DOM’a/JS’e “konduğu” ve tarayıcıda kodun çalışmasına yol açan API veya HTML yeridir. Eğer tainted veri doğru şekilde sanitize edilmeden sink’e giderse XSS olur.

En yaygın XSS sink’leri


- `element.innerHTML` / `element.outerHTML` — HTML olarak eklememelisiniz; → `textContent` veya sanitize etmelisiniz.(Kötü niyetli kullanıcılarınızın HTML form elemanları üzerinden sisteminize girdiği bilgiler, zaafiyeti önlemek açısından bir temizlik işlemine tabi tutulmalıdır. Bu temizlik işlemine ise, “Sanitize” denilir.)

- `element.insertAdjacentHTML(...)` — DOM’a raw HTML ekler; kullanmamalısınız → sanitize edin veya `createElement`+`textNode`.

- `document.write()` / `document.writeln()` — sayfaya doğrudan yazma; hiç kullanmayın; alternatif: güvenli DOM API’leri.

- `element.innerText`/`element.textContent` (NOT: güvenli sink değildir; bunlar güvenli alternatiflerdir );kullanabilirsiniz.

- `element.setAttribute(...)` (özellikle `on*` eventleri veya `href`, `src`) — attribute enjeksiyonu riski; protokol/isim kontrolü ve escape.

- `element.onclick = ...` veya doğrudan `on*` attribute’lara atama — event handler içine kullanıcı verisi sokma; kullanmamalısınız.

- `element.outerHTML = ...` — tüm elementi raw HTML ile değiştirme; sanitize edin veya kaçının.

- `insertAdjacentElement` + `innerHTML` kombinasyonları — dolaylı HTML injection; textContent / createTextNode kullanın.

- `eval(...)` / `new Function(...)` — kullanıcı verisini kod olarak çalıştırma; kesinlikle kullanmayın.

- `setTimeout(string)` / `setInterval(string)` — string argümanı eval gibi çalıştırır; kullanmayın.

- `location = userInput` / `location.href = userInput` / `window.open(userInput)` — `javascript:` veya open-redirect riskleri; URL protokolunu doğrulayın.

- `element.insertAdjacentHTML` / jQuery `.html()` / `.append()` / `.prepend()` / `.replaceWith()` — kütüphane versiyonlarında raw HTML ekler; jQuery: use `.text()` veya sanitize edin.

- `iframe.srcdoc` / `iframe.contentWindow.document.write` — iframe içinde HTML çalıştırma; sanitize veya deny edin.

- `element.style` / CSS injection (ör. `style` attribute’a kullanıcı verisi koymak) — CSS üzerinden saldırı/keşif; stil atamalarda whitelist kullanın.

- `href="javascript:..."` veya `src="javascript:..."` — URI protocol sink; protokol kontrolü (sadece http/https).

- `dangerouslySetInnerHTML` (React) — React özel sink; kullanmayın veya DOMPurify ile sanitize et.

- `v-html` (Vue) / `ng-bind-html` / Angular bypass APIs (`$sce.trustAsHtml`) — framework-specific raw HTML sink’leri; sanitize veya avoid edin.

- `setAttribute('srcdoc', ...)` veya benzeri HTML-attribute-based renderers — attribute içinde HTML çalıştırır; sanitize edin.

- `postMessage` hedefinde doğrudan innerHTML kullanmak — cross-origin içerik tehlikesi; kaynağı doğrulayın.

- `innerHTML` benzeri template renderers (server/client-side template engine’lerin raw insertion noktaları) — server-side template’lerde de context-aware escaping uygulayın.

NOT:
jQuery, DOM manipülasyonu, event yönetimi, AJAX istekleri ve cross-browser (özellikle eski tarayıcılar) uyumluluğunu kolaylaştırmak için geliştirilmiş hafif bir JavaScript kütüphanesidir. Kısa ve zincirlenebilir (chaining) API’si sayesinde sık kullanılan işlemleri az kodla yapmayı sağlar.
- Eleman seçmeyi hızlandırır. ($('.item'))
- Sayfaya metin koymak için .text() kullanılır. ($('#a').text('Merhaba'))
- Sayfaya HTML koymak için .html() kullanılır. ($('#a').html('<b>Merhaba</b>'))
- Buton tıklamalarını dinlemek kolaydır. ($('#btn').on('click', ()=>{}))
- Sunucuya istek atmak için $.ajax() veya $.getJSON() kullanılır.
- Kodları zincirleyerek kısa yazarsın. ($('#a').addClass('x').show())
- Eklenti (plugin) ile yeni fonksiyonlar eklenir. ($.fn.myPlugin = ...)

Ne demek oluyor?

  • Kullanıcı olarak arama kutusuna merhaba yazıp gönderince bu metnin sayfanın DOM ağacında görünmesi demek: uygulama bu girdiyi alıp sayfada bir elemente yerleştiriyor.

  • Önemli soru: Ham HTML olarak mı (ör. <div>merhaba</div> içinde raw HTML) yoksa metin olarak mı (HTML-escaped veya textContent ile) gösteriliyor?

    • Raw HTML -> potansiyel tehlike (script tag’leri, event handler’lar çalıştırılabilir).

    • Text olarak -> genelde güvenli (tarayıcı bunu HTML olarak yorumlamaz).

resim
Ancak burada sayfa kaynağında merhaba yazısı <b> içerisinde görünmüyor yani buna şimdilik DOM xss olasılığı var diyebiliriz.
Şimdi exploit adımlarına geçelim:
Burada dikkat edeceğimiz birkaç husus var. Bunlardan biri yukarıdaki DOM ekran görüntüsünde. Yapılan sorgu “” içerisinde yapılmış yani öncelikle bunu ve eski tagi kapatıp kendi sorgumuzu yazmalıyız, örneğin:

"><svg onload=alert(1)>

Yani amaç: kullanıcının yazdığı veri bir attribute içinde yer alıyorsa o attribute’u kırıp DOM’a yeni bir element eklemek ve bunun onload/onerror/onmouseover gibi event handler’ıyla JavaScript çalıştırmak.**

Neden <svg onload=...> tercih edilir?

  • <script> etiketleri çoğu filtre/WAF tarafından doğrudan engellenir. SVG ise sıklıkla daha az filtrelenir.

  • SVG öğesi remote src gerektirmez; onload/onerror ile otomatik tetiklenebilir.

  • <img onerror=...> benzeri payload’lar da işe yarar ama bazı filtreler img veya onerror’u yakalayabilir; SVG daha “farklı” bir vektördür ve bypass için kullanışlıdır.

  • HTML5 ve modern tarayıcılar SVG event handler’larını destekler; bu yüzden geniş etki alanı vardır.

resim


Mini Sözlük

Terim Açıklama
XSS Saldırganın, kötü niyetli JavaScript (Script) kodu enjekte ederek, bu kodu siteyi ziyaret eden diğer kullanıcıların tarayıcısında çalıştırmasına olanak tanıyan web güvenlik açığı.
Payload Saldırganın hedef sistemde çalıştırmak istediği kötü niyetli kod veya veri. XSS’te genellikle <script>alert(1)</script> gibi JavaScript kodudur.
Reflected XSS Yansıyan XSS. Zararlı kodun bir URL parametresi ile gönderildiği, sunucunun cevabın bir parçası olarak hemen eklediği ve kurbanın tarayıcısında çalıştığı tür. Kalıcı değildir.
Stored XSS Kalıcı XSS. Zararlı kodun sunucu tarafında bir veritabanına kalıcı olarak kaydedildiği (yorumlar, forum mesajları) ve sayfayı ziyaret eden her kullanıcıda çalıştığı en tehlikeli tür.
DOM-Based XSS Zararlı kodun sunucuya gitmeden, doğrudan kurbanın tarayıcısında, JavaScript DOM manipülasyonu ile çalıştığı tür.
Çerez Bir web sitesinin kullanıcı tarayıcısında depoladığı oturum ve kullanıcı bilgilerini tutan küçük veri parçalarıdır. XSS ile çalınmaları oturum ele geçirmeye yol açar.
Oturum Ele Geçirme Saldırganın geçerli bir kullanıcının oturum kimliğini ele geçirerek o kişinin kimliğine bürünmesi.
Phishing Saldırganın sahte formlar veya siteler aracılığıyla kurbanların hassas bilgilerini çalmaya çalıştığı sosyal mühendislik saldırısıdır.
Keylogger Kullanıcının klavyede bastığı tuşları kaydeden zararlı kod veya yazılım.
URL Parametreleri Bir web adresinin ? işaretinden sonra gelen ve değişken-değer çiftleri şeklinde verilerin sunucuya iletildiği kısımdır.
HTTP Başlıkları Tarayıcı ve sunucu arasındaki iletişimde, isteğin veya cevabın meta verilerini taşıyan bilgiler (User-Agent, Referer vb.).
POST Body Alanları POST isteği gönderilirken verilerin HTTP isteğinin gövde kısmında taşındığı alanlardır (form, yorum verileri).
DOM Tarayıcının bir web sayfasını mantıksal ağaç yapısı olarak temsil etme şekli. JavaScript bu yapıyı değiştirir.
Sink Kullanıcıdan gelen güvenilmez verinin (tainted data) işlenerek kodun çalışmasına neden olduğu API veya HTML özelliğidir. (innerHTML, eval gibi).
Source Kullanıcı kontrolündeki verinin alındığı kaynak. (location.search, form inputları gibi).
Tainted Data Kullanıcı tarafından kontrol edilen ve zararlı payload içerebilme potansiyeli olan veridir.
innerHTML Bir HTML elementinin içindeki içeriği raw HTML olarak ayarlayan DOM özelliğidir. XSS’e yol açtığı için risklidir.
textContent Bir HTML elementinin içindeki içeriği sadece düz metin olarak ayarlayan güvenli alternatiftir.
Escape (Kaçış) HTML veya JavaScript’te özel anlamı olan karakterlerin (<, >, ", ') bu anlamlarını yitirip düz metin olarak görünmesini sağlayan kodlama işlemidir.
Sanitize (Temizleme) Kullanıcı girdisinden gelen verinin, potansiyel zararlı kodları (örneğin <script>) kaldırarak veya güvenli hale getirerek temizlenmesi.
Event Handler Bir HTML elementinde bir olay (tıklama, yükleme vb.) meydana geldiğinde otomatik çalıştırılan JavaScript kodu. XSS’te <svg onload=...> gibi kullanılır.
Proxy İstemci ile sunucu arasında aracı görevi gören ve istekleri yakalayıp değiştirmek için kullanılan araç (Burp Suite vb.).
User-Agent Tarayıcının, işletim sisteminin bilgilerini sunucuya bildiren HTTP başlığı.
Referer Kullanıcının geçerli sayfaya hangi sayfadan geldiğini gösteren HTTP başlığı.
JSON/REST API Verilerin sunucular arasında hafif ve yapılandırılmış bir şekilde (JSON formatında) alınıp verilmesini sağlayan mimari.
AJAX İstekleri Sayfanın tamamını yeniden yüklemeden, arka planda sunucuyla veri alışverişi yapmayı sağlayan teknikler.
HTML Etiketi (Tag) Bir web sayfasının yapısını tanımlayan kod parçası (<b>, <div>).
Attribute Bir HTML etiketinin özelliklerini tanımlayan ek parametreler (type="text", onload="...").
Zafiyet Bir sistemdeki güvenlik açığı veya tasarım hatası.
Exploit Etmek Bir güvenlik zafiyetinden yararlanarak o sistemde izinsiz eylem gerçekleştirmek.
DOM Manipülasyonu JavaScript kullanarak bir web sayfasının DOM ağacını değiştirmek.
Eval JavaScript’te bir metin dizesini kod olarak çalıştıran tehlikeli fonksiyon. Kullanıcı girdisi ile XSS riskini artırır.
WAF Web Uygulama Güvenlik Duvarı. Web uygulamalarını, XSS ve SQL Enjeksiyonu gibi yaygın saldırılara karşı korumak için tasarlanmış güvenlik mekanizması.
jQuery DOM manipülasyonu, event yönetimi ve AJAX isteklerini kolaylaştıran hafif JavaScript kütüphanesi. .html() kullanımı XSS’e yol açabilir.
location.search Tarayıcıda geçerli URL’nin sorgu dizisini (? işaretinden sonrasını) döndüren JavaScript kaynağı (Source).
document.referrer Kullanıcının bir önceki sayfasının URL’sini döndüren JavaScript kaynağı (Source).
insertAdjacentHTML DOM’a raw HTML ekleyen, güvenli olmayan bir JavaScript methodu (Sink).
document.write() Sayfaya doğrudan raw HTML yazan, XSS riski taşıyan bir JavaScript methodu (Sink).
setAttribute Bir HTML elementine bir nitelik (attribute) atayan method. Özellikle on* eventleri için kullanıldığında risklidir (Sink).