Brandon T. Elliott
CTF Writeup: Trellix HAX 2023 - "Spying Through the Webdoor"
The CTF
Trellix HAX 2023 took place from February 25th, 2023 (3AM EST) to March 11th, 2023 (3AM EST).
The Challenge
This reverse engineering challenge begins with a fictional backstory and a binary called arc-httpd
to download and analyze in order to solve it.
The Binary
After downloading the binary and running a chmod +x
on it to make it executable, we can run the binary on a specified port (in our case, we chose 8081):
However, navigating to it in the web browser gives us a 404 Not Found:
Manual Inspection
Initially, I poked and prodded at it for awhile by intercepting a request with Burp Suite and sending it to repeater in order to see if maybe it was just a simple cmd
parameter or something along those lines. However, this proved to be a fruitless endeavor.
Therefore, it was time to disassemble the binary with Ghidra.
Ghidra
Defined Strings
After importing the file to Ghidra and instructing it to analyze the binary, I took a quick look at the defined strings, which contained some interesting references, including one to /cgi-bin/
However, navigating to the cgi-bin
directory gives us a 403 Forbidden:
The defined strings also contained a reference to robots.txt
, which contained the following contents:
Exploring Functions
Exploring the binary within Ghidra more, we find a string which appears to print a success message along with the key:
This reference appears within the do_cgi_request
function on line 38, which we will analyze next.
The do_cgi_request
Function
This function is decompiled by Ghidra as the following:
I began to decipher what this function was doing and started by renaming the variables to make more sense.
Although there was more code in the function after this section, I quickly had deciphered the function enough to understand how it may be possible to extract the key:
On line 29 is a call to a do_hash
function which takes in 4 parameters:
- The key input which appears to be parsed from the http request as a directory within /cgi-bin/
- The length of the key (which appears to be 23)
- A data section within the binary which I’ll be referring to as the salt
- The length of the salt (which appears to be 8)
On line 31, it copies data from a location within the binary which I’ll be referring to as KEY_HASH_STORED with length of 23, and compares it to the hash returned from the do_hash function mentioned previously. This is then used on line 32 to check if the correct key was supplied within the web request.
The next step was to look at the do_hash function itself.
The do_hash
function
This function is initially decompiled by Ghidra as the following:
Since I already knew the parameters supplied to this function, it didn’t take much to be able to decipher exactly what was happening:
It seemed to be a simple algorithm using an xor operation along with the key, the salt, and a hardcoded decimal value of 66 to calculate the hash.
Line 15 within the for loop can be simplified to:
hash[x] = key[x] ^ salt[x % 8] + 66
Thankfully, we already identified the KEY_HASH_STORED data located in the binary, which is what is checked against the result of this function in the do_cgi_request
function. We also have the hardcoded salt data.
Therefore, since we know all values used in this equation except for one (the key), we can reverse it to solve for the key by using some simple algebra, along with the fact that:
a = b ^ c
(where ^ is an xor operator), is the same as:
b = a ^ c
.
This results in the solution being the following equation:
key[x] = hash[x] - 66 ^ salt[x % 8]
The Data
All that’s left to do now is to grab the salt and hash data from the binary (referred to previously as salt
and KEY_HASH_STORED
), and code a function to solve for the key.
Here we see the section containing what I’m referring to as the salt, which we know to be 8 in length:
And here we see the section containing the resultant hash, which we know to be 23 in length:
The Solution
Using this hardcoded data along with our new equation, I decided to code a solution for the key using C.
After compiling and running the code, the key was successfully printed out!
Additional Info / Sending Commands
Although we now have the key (which is also the flag, therefore the challenge is solved at this point), the challenge also references being able to send commands, so I analyzed the do_cgi_request
function a bit further, as most of the logic for parsing and running commands appears to take place after the key is already printed out.
After renaming some variables, we now have some additional info about how this works:
It appears the function ultimately parses the request in the following format:
/cgi-bin/{key}/{command}
Additionally, it appears to set the command to whoami
by default if no command was specified in the http request, and there is also some additional logic as well, such as printing out an error message if you specify the rm
command, etc.
Using this information, we can now intercept a request using Burp Suite again, send it to repeater, and craft a request with the key and the id
command to test this logic, which appears to be successful!