Well hello everyone! After a (long) break, I’m finally back with my first ever writeup for TryHackMe’s Bookstore! This box focuses on web enumeration, API fuzzing, and binary decompiling in order to gain a reverse shell and escalate privileges. Without further ado, let’s get started.

Scanning


As with any box, I’ll start by performing a port scan using a custom script that combines two scanning tools: masscan and nmap. Once the scan is finished, I found ports 22, 80, and 5000 to be open on the machine:

nmap scan results

One thing of note is the /api found in robots.txt of the server on port 5000. I’ll come back to this once I do recon on the port.

Recon - Port 80


The first thing I’ll look at is the web server hosted on port 80. Navigating to the IP address of the web server gives me the following homepage:

Bookstore homepage

As with most CTFs, I’ll browse through each page to see if there any information of interest. For this box, there wasn’t anything of much use on the immediate pages. However, diving into the source of each page using Developer Tools revealed a good amount of useful data.

On the landing page, the website’s HTML and JavaScript files don’t provide any telling information. Moving to the “Books” page, I find an interesting JavaScript file titled api.js. The script conatains the following code:

An interesting comment

After reading through the script, I am able to determine that the webpage is making API calls to port 5000, which is expected due to the robots.txt entry for that server containing a page called /api. I also find an interesting comment that notes that an earlier version of the API had a parameter that was vulnerable to Local File Inclusion (LFI). I’ll come back to this later.

The final page, “Login”, also contains an interesting comment in it’s source:

Another intersting comment

This comment points out that there is a “debugger pin” in a user’s .bash_history file. While I don’t immediately know what “debugger” the comment is refering to, the note on the .bash_history file does provide us with a target for the LFI-vulnerable API. This brings about the conclusion of the port 80 recon, so we’ll move on to port 5000.

Recon - Port 5000


To begin, I decide to look up what exactly “Werkzeug” is. Reading through the Werkzeug documentation, I find that Werkzeug has a debugger that can be accessed through the /console path. The documentation also notes that the debugger can have a pin set. This all but confirms the intersting file in the user’s .bash_history file contains a pin to give us access to the Werkzeug debugger. To confirm that this console is set up like the documentation lays it out, I navigate to the console path and was greeted with a lock screen.

Werkzeug locked console

With this confirmed, I’ll now move to the api part of the site. Travelling to the /api page I discovered earlier reveals the API landing page with a variety of different API calls that can be made:

So many choices…

I know that this API is vulnerable to LFI, but only on an earlier version. One thing I notice about the URLs for the API calls is that each one has v2 in it. Assuming this is denoting the version, I decide to try to use v1 in its place. Surely enough, navigating to one of the listed URLs with v1 instead of v2 yields a successful API call. With all of this information, I now believe I have a clear path to exploitation.

Exploitation


In order to exploit the LFI issue, I need to find the parameter that is vulnerable to LFI. To do this, I’ll use the wfuzz application to fuzz valid parameter names and see which ones return a valid response. The target for wfuzz will be http://<BOOKSTORE_IP>:5000/api/v1/books?FUZZ=../../../../../etc/passwd and I’ll be using the directory-list-2.3-medium.txt wordlist. With these parameters, I end up finding an interesting parameter that is not used by items returned by the API.

A successful fuzz!

Navigating to that page in a web browser, I can see that the parameter is vulnerable to LFI as it prints out the contents of /etc/passwd/ to the page. Unfortunately, /etc/passwd does not have any useful information. However, I do know from earlier that the pin for the Werkzeug debugger is in a user’s .bash_history file. By using this file as the path on the parameter that is vulnerable to LFI, I get the Werkzeug pin.

Success!

Now that the pin has been acquired, I can navigate to /console and access the Werkzeug debugger. In the debugger, I have access to a Python console. This console provides the perfect opportunity to create a reverse shell, so useing a python “one-liner”, I am able to successfully spawn a reverse shell and read user.txt!

hacker voice I’m in

Privilege Escalation


Now that I have a reverse shell, it’s time to look for some privilege escalation opportunities. Luckily for me, the first promising privilige escalation is sitting right in the user’s home directory.

A wild SUID has appeard!

From running the ls -l and file commands, I can see that there is a Linux ELF binary called try-harder that has the SUID bit set and is owned by the root user. Running the program, I’m asked for a “magic number”. Seeing this, I’m thinking that providing the correct number to the program will put me into a root shell. To determine if my theory is correct, I’m going to decompile this program using Ghidra - the NSA’s reversing engineering suite.

After starting a Python web server on the target machine to transfer the binary over, I opened it up in Ghidra and navigated to the “main” function within the “Functions” folder. I can now see the decompiled code written in C.

Almost there…

After looking over the code, I can see that the following happens:

  1. The UID is set to 0 (root)
  2. Variable local_18 is set to a hex value of 0x5db3
  3. The “magic number” entered by the user is stored in the variable local_1c
  4. A mathematicaly function is performed involving local_18, local_1c, and the hex value 0x1116 and is stored in variable local_14
  5. If the the value of local_14 is equal to the hex value 0x5dcd21f4, then run the command /bin/bash -p

With this in mind, I now need to figure out what the caret (^) operator does and then convert the hex values to decimal. After doing some Google-fu, I found that the caret operator is used for bitwise XOR. This is extremely convenient as the inverse of bitwise XOR is just bitwise XOR! So what does this mean? This means that given the equation:

c = x ^ a ^ b (where x is the “magic number”)

we can solve for x through the equation:

x = a ^ b ^ c (order doesn’t matter, so it could be b ^ a ^ c and so on)

After quickly converting the hex values to decimal, I can use the following values to determine the “magic number”:

Yay math!

Now that I know the “magic number”, I can run the binary, enter the number, and gain root access to the machine!

pwnd, n00b

Remediation


Just for kicks, I thought it would be interesting to go over a few things that could be done in order to prevent this machine from getting rooted. The goal here is to provide recommendations that would have minimal to no impact on assumed business processes. With this in mind, heres a quick list of things that need to be done to further secure this machine:

  1. Remove needless comments about the code/vulnerabilities
  2. Disable the vulnerable version of the API
    • If the vulnerable version must be used, at least disable the vulnerable parameter
  3. Disable the Werkzeug debugger console
    • Werkzeug documentation notes that the debugger should never be enabled in production (link)
  4. Ensure that no binaries with SUID/SGID bits set can be exploited to escalate privileges.

Conclusion


This box was great - it rewarded thorough investigation and provided me with the opportunity to use wfuzz for the first time. I’m definitely looking forward to the next box I get to root!