SQL Injection Nedir? Veritabanı Nasıl Manipüle Edilir?
Kör (blind) SQL Injection tekniklerinden Burp Suite ve SQLMap ile pratik sömürüye: Zaman (Time), Mantık (Boolean) ve Hata (Error) tabanlı yaklaşımlar
SQL Injection, kullanıcı girdisinin doğrudan veritabanı sorgusuna yapıştırıldığı her noktada veritabanının çalınmasına, silinmesine veya değiştirilmesine yol açan klasik ama hâlâ ölümcül bir web zafiyetidir. Bu yazıda kör (blind) SQLi'nin zaman (time-based) ve mantık (boolean-based) tabanlı varyasyonlarını, hata tabanlı (error-based) sömürüyü ve Burp Suite ile SQLMap'in pratik kullanımını laboratuvar notlarımdan yola çıkarak ele alıyorum.
Giriş
En yetkilendirilmiş, en “güvenli” görünen sistemlerin bile arama kutusuna yazılan tek bir tırnak işaretiyle (') yerle bir olması, siber güvenliğin en ironik gerçeklerinden biri. Yıllar geçse, WAF’lar gelişse, ORM’ler yaygınlaşsa da SQL Injection (SQLi) hâlâ OWASP Top 10’daki tahtını bırakmıyor.
Siber güvenlik süreçlerinde karşılaştığımız zafiyetleri sadece otomatize araçlarla (örneğin SQLMap) taratıp geçmek bizi iyi bir mühendis yapmaz. İşin mantığını, arka planda dönen veritabanı sorgularını manipüle etmeyi anlamak şarttır. Bu yazıda, laboratuvarlardaki pratik çalışmalarım esnasında tuttuğum notlardan yola çıkarak SQLi’nin kör (blind) ve hata tabanlı (error-based) varyasyonlarını, arka planındaki mantığıyla birlikte ele alacağım.
SQL Injection Tam Olarak Ne?
Temelde SQL Injection çok basit bir fikre dayanır: uygulama, senden aldığı bir veriyi (kullanıcı adı, arama terimi, id numarası) arka plandaki SQL sorgusuna doğrudan yapıştırıyorsa, sen o verinin içine SQL komutları gizleyerek veritabanına normalde yapmaması gereken şeyleri yaptırabilirsin.
Bunu günlük bir örnekle düşünelim: bir kurumda dilekçe kutusuna talebini yazıyorsun, görevli dilekçeni okumadan doğrudan sisteme giriyor. Normalde “İzin talebi” yazman beklenirken, sen “İzin talebi, ayrıca bu yıl kim izin istediyse hepsinin talebini reddet” yazsan ve görevli (uygulama) bu cümlenin tamamını tek bir komut gibi, ayrıştırmadan sisteme (veritabanına) iletse — içerideki sistem manipüle edilmiş olur ve sen dışında çalışma arkadaşlarının hiçbiri izin kullanamayacak olur. Bu da tatil dönüşü kaos yaratmaya sebebiyet verir.
-- Normal Kullanım
SELECT * FROM products WHERE product_name = 'Yves Saint Laurent Couture Mini Clutch Luxury Eyeshadow Palette';
-- SQL Injection Saldırısı
SELECT * FROM products WHERE product_name = 'Yves Saint Laurent Couture Mini Clutch Luxury Eyeshadow Palette' OR 1=1 --';
Peki ekranda hiçbir veri, hiçbir hata mesajı görmüyorsak? İşte o zaman devreye Kör (Blind) SQL Injection teknikleri giriyor.
1. Zamana Karşı Yarış: Time-Based Blind SQL Injection
Veritabanından dönen veriyi ekranda göremiyorsak ve sistem “doğru/yanlış” girdilerimize hiçbir görsel tepki vermiyorsa, veritabanına soru sorma şeklimizi değiştirmeliyiz.
Mantık basit: veritabanına bir soru sorarız ve “Eğer bu soru doğruysa, sistemi belirli bir saniye (örneğin 5 saniye) beklet” deriz. Sunucunun cevap verme süresini (response time) ölçerek bilgiyi parça parça dışarı çıkarırız (exfiltration).
Veritabanı adını bulmaya çalışırken önce uzunluğunu tahmin etmek için spontane bir değer gireriz:
email=test' AND (SELECT 1 FROM (SELECT(IF(LENGTH(DATABASE())=6,SLEEP(5),0)))a)--
Eğer veritabanının adı 6 harften oluşuyorsa sistem 5 saniyelik gecikme yaşar.
Uzunluğun 6 karakter olduğunu netleştirdikten sonra, bu sefer harfleri tek tek SUBSTR() fonksiyonuyla denemeye başlarız:
email=test' AND (SELECT 1 FROM (SELECT(IF(SUBSTR(DATABASE(),1,1)='h',SLEEP(5),0)))a)--
email=test' AND (SELECT 1 FROM (SELECT(IF(SUBSTR(DATABASE(),1,2)='ho',SLEEP(5),0)))a)--
En nihayetinde tam adı hedeflediğimizde sorgumuz şu şekli alır:
email=test' AND (SELECT 1 FROM (SELECT(IF(DATABASE()='utopia',SLEEP(5),0)))a)--
Sorgu tam olarak eşleştiğinde Burp Suite Repeater ekranında dönen yanıtın süresi uzuyor. Aşağıdaki ekran görüntüsünde, sağ altta bu sorgunun sunucuda başarıyla çalıştığını kanıtlayan yaklaşık 6.6 saniyelik gecikme süresi görülüyor:
Bu sayede ne kadar yorucu da olsa hiçbir görsel ipucu olmadan, sadece zamanı ölçerek harf harf veritabanı adını keşfedebiliyoruz.
2. Doğru mu Yanlış mı? Boolean-Based Blind SQL Injection
Farklı bir senaryoda, ekranda doğrudan veritabanından çekilen ham bir veri yazmıyordur ama uygulama, gönderdiğimiz mantıksal sorgunun sonucuna göre “Ürün Stokta Var” veya “Ürün Bulunamadı” gibi iki farklı durumsal tepki (True/False) veriyorsa Boolean-Based SQL Injection yöntemini kullanırız.
Buradaki laboratuvar çalışmamda sistemi adım adım köşeye sıkıştırarak derinlemesine bir saldırı zinciri yürüttüm. İşte operasyonun aşamaları:
Aşama A: Manuel Keşif ve Durum Analizi
Öncelikle bir telefon şirketinin stok uygulamasında normal bir arama gerçekleştirerek sistemin davranışını analiz ettim (search=iPhone13). Sistem bana We have this product in stock. (True) yanıtını verdi. Parametrenin sonuna tek tırnak (') koyarak SQL sorgusunu kırdığımda ise sayfa yapısının bozulduğunu gözlemledim. Bu, girdinin doğrudan veritabanına gittiğinin ve manipüle edilebileceğinin açık bir kanıtıydı.
Aşama B: Mantıksal İstismar (Doğru Soru Sorma)
Sistemin True/False tepkilerini netleştirdikten sonra, arama parametresinin yanına veritabanı adının uzunluğunu test eden mantıksal bir önerme ekledim:
search=iPhone13' AND (SELECT LENGTH(DATABASE()))=10--
Arka planda çalışan veritabanı motoru bu isteği aldığında sorguyu şu şekilde birleştirdi:
SELECT * FROM products WHERE product_name = 'iPhone13' AND (SELECT LENGTH(DATABASE()))=10;
Veritabanı önce sol taraftaki ürünün varlığını doğruladı (True) ve ardından AND bağlacı nedeniyle sağ taraftaki önermeyi denetledi: “Mevcut veritabanı adımın karakter uzunluğu 10 mu?” Uzunluk 10’dan farklı olsaydı sorgu False dönecek ve arayüzde “Stok yok” uyarısı basılacaktı. Ancak yaptığım testte sistem bana olumlu yanıt verdi:
We have this product in stock.
Aşama C: SQLMap ile Otomatize Oturum (Büyük Saldırı)
Manuel olarak veritabanı adının 10 karakter olduğunu keşfettikten sonra, bu 10 harfi tek tek elle denemek ciddi bir zaman kaybı yaratacaktı. Bu aşamada Burp Suite üzerindeki başarılı HTTP isteğinin tamamını (header’lar, cookie’ler ve session bilgileriyle birlikte) bir metin dosyasına (istek.txt) kaydettim ve SQLMap üzerinden gelişmiş bir atak başlattım:
sqlmap -r istek.txt --batch --current-db
-r istek.txt: SQLMap’e hedef trafiği ve oturum bilgilerini bu dosyadan okumasını söyledim.--batch: Araca tarama esnasında soru sormadan varsayılan en agresif/akıllı adımlarla ilerlemesi talimatını verdim.--current-db: Boolean-Based açığı sömürerek güncel veritabanı ismini söküp getirmesini istedim.
Arka planda SQLMap, search parametresine saniyede onlarca True/False sorgusu göndererek sayfa içeriğindeki yapısal değişimleri milisaniyelik hızlarla ölçtü. Manuel olarak kurduğum “10 karakter” filtresini otomatize ederek tüm harf kombinasyonlarını saniyeler içinde deşifre etti ve güncel veritabanı ismini başarıyla düşürdü.
3. Veritabanını Konuşturmak: Error-Based SQL Injection
Eğer şanslıysak ve hedef uygulama arka planda oluşan veritabanı hatalarını (database errors) filtrelemeden doğrudan ekrana bastırıyorsa, kör yaklaşımlarla harf harf uğraşmamıza veya otomatize araçları dakikalarca bekletmemize gerek kalmaz. Veritabanını bilerek mantıksal bir hataya zorlarız ve almak istediğimiz kritik bilgiyi o hata mesajının içine gömerek tek bir istekte dışarı çıkartırız.
Bu laboratuvar çalışmasında, hedef web uygulamasındaki img= parametresinin SQL enjeksiyonuna açık olduğunu tespit ettikten sonra, hata tabanlı sömürü yöntemlerinden en etkilisi olan updatexml() fonksiyonunu kullandım. Linkin sonundaki parametreye şu payload’u yerleştirdim:
1 and updatexml(1,concat(0x7e,(select database()),0x7e),1)--
Arka plandaki hata mantığı:
0x7ekarakteri~(tilde) işaretine denk gelir.updatexml()fonksiyonu ikinci parametre olarak geçerli bir XML XPath ifadesi bekler. Ancakconcat()ile araya tilde koyarak bu yapıyı bilerek bozuyoruz.- Fonksiyon geçersiz bir XPath formatı gördüğünde çalışmayı durdurur ve bir veritabanı hatası üreterek içeriye gömdüğümüz
(select database())sorgusunun sonucunu hata mesajının tam ortasında ekrana basar.
updatexml() ile tetiklenen PDOException hatası, veritabanı adını iki tilde (~) arasında doğrudan ekrana sızdırıyor.Bu sayede, hiçbir otomasyon aracına veya kör denemelere ihtiyaç duymadan, sadece veritabanının kendi ürettiği hata mesajını okuyarak güncel veritabanı adına saniyeler içinde ulaştım.
SQL Injection’a Karşı Savunma
SQLi teknik olarak eski bir zafiyet olsa da, savunma tarafı hâlâ disiplin gerektiriyor:
- Parametreli sorgular (prepared statements): Kullanıcı girdisi asla sorgu string’ine doğrudan eklenmemeli.
- Input validation: Beklenmeyen karakterler (
',--,;) filtrelenmeli — ama tek başına yeterli değil. - En az yetki prensibi: Uygulamanın veritabanı kullanıcısı sadece ihtiyacı olan işlemleri yapabilmeli.
- Hata mesajlarını gizlemek: Ham veritabanı hatalarının (stack trace, PDOException vb.) kullanıcıya doğrudan gösterilmemesi, Error-Based saldırıları büyük ölçüde engeller.
- WAF ve izleme: Bilinen payload kalıplarını yakalasa da tek katmana güvenilmemeli.
Sonuç
SQL Injection, günümüzde modern WAF sistemleri ve ORM yapıları nedeniyle eskisi kadar kolay tetiklenemese de, girdi doğrulamanın ve parametreli sorguların ihmal edildiği her noktada ölümcül olmaya devam ediyor. Kör senaryolarda bile — ekranda tek bir veri görünmese dahi — zaman farkları veya True/False tepkileri üzerinden bir veritabanını harf harf konuşturmak mümkün. Bu zafiyetlerin manuel olarak nasıl işlediğini ve otomatize araçların arka planda hangi mantıkla çalıştığını kavramak, biz bilgisayar mühendislerinin güvenli kod yazma vizyonunun temel taşlarından biri.
Kaynakça
- Canlı, Y. “Web Uygulama Güvenliğinde SQL Injection: Teori, Pratik ve Kör Yaklaşımlar (Kendi Notlarımdan)”, Medium, Haziran 2026.
- OWASP Foundation, “SQL Injection”, OWASP Top 10.
- PortSwigger Web Security Academy, “SQL injection”.
- SQLMap Resmi Dokümantasyonu, sqlmap.org.
Sen de yaz, arşivde yerini al
AltaySec Arşiv'e katkı ver — uzmanlığını Türkçe siber güvenlik literatürüne kat.
Yazar Ol