Hack The Box

Hack The Box: BountyHunter Walkthrough

BountyHunter uses XXE for file read, recovered SSH credentials, and Python eval in ticketValidator.py for root.

BountyHunter Hack The Box machine artwork
Official Hack The Box machine artwork for BountyHunter.Hack The Box machine page opens in a new tab

Recon & Enumeration

Use nmap to full scan for open ports and services:

HackTheBox “BountyHunter” Walkthrough, figure 2

Check the port 80.

HackTheBox “BountyHunter” Walkthrough, figure 3

Check the portal subdirectory.

HackTheBox “BountyHunter” Walkthrough, figure 4

It indicates the ongoing development phase and offers a URL for testing the lab environment.

HackTheBox “BountyHunter” Walkthrough, figure 5

We found a data-entry form that saves input externally, resembling a beta report submission system. Examine the page source.

HackTheBox “BountyHunter” Walkthrough, figure 6

This resembles a typical HTML page. Time to inspect the bountylog JavaScript file.

HackTheBox “BountyHunter” Walkthrough, figure 7

It's a form allowing value input, with data storage elsewhere. Upon inspecting the page source, we noted XML structure. This suggests vulnerability to XXE (XML External Entity). To gather more insights, we employed dirsearch.

HackTheBox “BountyHunter” Walkthrough, figure 8

Exploitation:

Open BurpSuite and navigate to the portal link then proceed to the Bounty Report System.

HackTheBox “BountyHunter” Walkthrough, figure 9

Submit a test report and monitor the request in Burp.

HackTheBox “BountyHunter” Walkthrough, figure 10

The field above are encoded in base64 to construct an XML structure, enabling a vulnerability check for XXE.

<?xml version="1.0" encoding="ISO-8859-1"?> <bugreport> <title>test</title> <cwe>test</cwe> <cvss>test</cvss> <reward>test</reward> </bugreport>

Transfer the request to the repeater and insert the encoded payload below into the data field after encoding it to Base64 and ensuring URL compatibility.

HackTheBox “BountyHunter” Walkthrough, figure 11

In the repeater section, we substitute our request's data field with our payload before sending it out.

HackTheBox “BountyHunter” Walkthrough, figure 12

Attempt to extract the contents of the db.php file obtained through dirsearch tool above. 
Since it's a PHP file, direct viewing isn't possible as it gets executed. 
To access its content, we'll use the PHP wrapper php://filter/convert.base64-encode/resource, converting the PHP file's content into base64 and displaying it. For more information on PHP wrappers, refer to this opens in a new tab article. 
Adjust our payload to retrieve the content of the db.php file.

HackTheBox “BountyHunter” Walkthrough, figure 13

In the repeater section, we substitute our request's data field with our payload again before sending it out.

HackTheBox “BountyHunter” Walkthrough, figure 14

After decoding the information from the db.php file, we obtain the following data.

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

Verify SSH access. Couldn't log in with the admin username but examining the extracted file /etc/passwd above reveals a user named "development".

HackTheBox “BountyHunter” Walkthrough, figure 15

Privilege Escalation:

Check what privileges we have.

HackTheBox “BountyHunter” Walkthrough, figure 16

The $sudo -l command indicates that the user development has root permission to execute ticketValidator.py. Inspect its contents.

development@bountyhunter:~$ cat /opt/skytrain_inc/ticketValidator.py#Skytrain Inc Ticket Validation System 0.1#Do not distribute this file.def load_file(loc):    if loc.endswith(".md"):        return open(loc, 'r')    else:        print("Wrong file type.")        exit()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            continue        if i == 1:            if not x.startswith("## Ticket to "):                return False            print(f"Destination: {' '.join(x.strip().split(' ')[3:])}")            continue        if x.startswith("__Ticket Code:__"):            code_line = i+1            continue        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                else:                    return False    return Falsedef 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.")    else:        print("Invalid ticket.")    ticket.closemain()

The eval() function in Python is powerful but potentially dangerous if not used carefully. It allows execution of any valid Python expression or code, making it susceptible to Python Code Injection attacks if malicious input is provided. To safeguard against this, rigorous data validation must precede its use dynamically in applications. For further insights into this vulnerability, refer to this article opens in a new tab.

We found four invalid tickets "md files" in the python script directory:

HackTheBox “BountyHunter” Walkthrough, figure 17

The script indicates the ticket is invalid.

The script's use of the eval() function without sanitization allows for execution of arbitrary Python expressions, presenting an opportunity for OS command injection. By crafting expressions like __import__('os').system('/bin/bash')** and concatenating them with other input strings using the and operator, we can exploit this vulnerability to escalate privileges.

I gained root shell access by creating a file named "root.md" in the "development" user's home directory depending on the structure of the invalid tickets found above.

HackTheBox “BountyHunter” Walkthrough, figure 18

Then, I invoked root.md while running "ticketValidator.py" with root privileges.

HackTheBox “BountyHunter” Walkthrough, figure 19

Further reading

Evidence connected to this article.

Back to article start