Hack The Box: BountyHunter

Jump Ahead: EnumUserRootResources


To solve this machine, we begin by enumerating open ports using nmap – finding ports 22 and 80 open. From the web server, we find a form that uses custom Javascript. Looking at the Javascript code, we find it submits user-supplied XML to another script that parses the XML. Exploiting this, we are able to read a file that contains database credentials. Using the database password, we are able to get access to the machine as development, and read user.txt. As development, we are able to run a python script as root. Exploiting a code injection vulnerability in the script, we are able to get a shell as root, and read root.txt.


Like all machines, we begin by enumerating open ports using nmap. From our scans, we find ports 22 and 80 open.

$ sudo nmap -v -p- --min-rate 3000 $RHOST
$ sudo nmap -sV -A -p 22,80 -oA enum/nmap/tcp-scripts $RHOST
# Nmap 7.91 scan initiated Sun Jul 25 10:31:00 2021 as: nmap -sV -A -p 22,80 -oA enum/nmap/tcp-scripts
Nmap scan report for
Host is up (0.047s latency).

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-server-header: Apache/2.4.41 (Ubuntu)
|_http-title: Bounty Hunters
Warning: OSScan results may be unreliable because we could not find at least 1 open and 1 closed port
Aggressive OS guesses: Linux 4.15 - 5.6 (95%), Linux 5.3 - 5.4 (95%), Linux 2.6.32 (95%), Linux 5.0 - 5.3 (95%), Linux 3.1 (95%), Linux 3.2 (95%), AXIS 210A or 211 Network Camera (Linux 2.6.17) (94%), ASUS RT-N56U WAP (Linux 3.4) (93%), Linux 3.16 (93%), Linux 5.0 (93%)
No exact OS matches for host (test conditions non-ideal).
Network Distance: 2 hops
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

TRACEROUTE (using port 80/tcp)
1   47.54 ms
2   47.66 ms

OS and Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
# Nmap done at Sun Jul 25 10:31:24 2021 -- 1 IP address (1 host up) scanned in 24.34 seconds

Next, we run gobuster to enumerate files and directories on the webserver. Doing so, the only interesting results we have are /portal.php and /db.php. Going to the webserver in the browser, we see a basic page that tells it’s a site for bug bounty hunters.

Clicking the “Portal” link, we are taken to a page that says the portal is under development. It also includes a link to test the bounty tracker.

Clicking the link to the bounty tracker, we are taken to the “Bounty Report System”. On this page, there is a web form that we are able to interact with. Looking at the page source, the web form uses custom Javascript, located at /resources/bountylog.js, when it is submitted.

Taking a look at the custom Javascript, we see that it forms XML based on the user’s input, converts it to base64, and submits the XML to /tracker_diRbPr00f314.php. Looking at /tracker_diRbPr00f314.php, we see that it returns text, that likely uses the values supplied via the XML.

As the XML is formed based on user input, it’s likely vulnerable to XML External Entity (XXE) injection. To test that the XML is formed as we suspect, we use the Bug Bounty System form as intended, and submit some test data. After getting the response in the browser, and comparing it to the POST request in BurpSuite, we have confirmed our suspicion.

Getting User

Now that we have confirmed user-controlled XML is being processed, we can create a proof-of-concept (POC) using CyberChef. For our POC, we will try to read the /etc/passwd file, which we are certain the machine has. For reference, we will use this cheatsheet to create the base64 string needed for the POC. We also need to URL-encode the base64, so it does not get incorrectly sent to the server.

Once we’ve created the POC base64 string, we can use BurpSuite’s Repeater to send it in the “data” field. Doing so, we get a listing of the user accounts and their relevant information. Notably, we see root and development are the only accounts with a shell.

As our POC worked, we can now use it for more data exfiltration. Remembering that previously we found /db.php, this is the file we will want to read, as it likely contains credentials. Since it probably contains php code, we have to change how we use XML to read the file, as we do not want it to be processed by the server. Looking at the cheatsheet, we can use php wrappers to base64-encode a file, and exfiltrate with no problem. Doing so, we are able to read the contents of the file, and find a password for the database.

Using the password, we test it against the development user via SSH, and are given a shell. This allows us access to now read user.txt.

Getting Root

Having gained a shell as development, we begin our initial enumeration. The first thing we always run is sudo -l to check for commands/scripts we may run as another user. Doing so, we see we are able to run a python script as root.

Reading through the script, we see it reads a “.md” file, and checks the first 2 lines for set values. If they are not there, it returns false. Interestingly, further in the script, we see there is an “eval()”, which processes raw python code. Since the argument to the eval() is user supplied, we may be able to exploit it, and get a shell as root (since the script is ran as root).

Since the code that processes the eval() statement has certain conditions that have to be met in order to execute, we can bypass this limitation by including a nested eval() that contains our code to get a shell. After creating the malicious “.md” file, we run the python script as root, supply our filename, and get a shell as root. With this, we are now able to read root.txt.

Thank you for taking the time to read my write-up. I am interested in other ways this machine has been solved. Feel free to reach out to me and we can discuss it. Thanks!