Brandon T. Elliott

home

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.

prompt

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):

binary

However, navigating to it in the web browser gives us a 404 Not Found:

404

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/

defined-strings

However, navigating to the cgi-bin directory gives us a 403 Forbidden:

403

The defined strings also contained a reference to robots.txt, which contained the following contents:

robots.txt

Exploring Functions

Exploring the binary within Ghidra more, we find a string which appears to print a success message along with the key:

congrats

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:

do_cgi_request

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:

do_cgi_request_renamed

On line 29 is a call to a do_hash function which takes in 4 parameters:

  1. The key input which appears to be parsed from the http request as a directory within /cgi-bin/
  2. The length of the key (which appears to be 23)
  3. A data section within the binary which I’ll be referring to as the salt
  4. 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:

do_hash

Since I already knew the parameters supplied to this function, it didn’t take much to be able to decipher exactly what was happening:

do_hash_renamed

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:

salt

And here we see the section containing the resultant hash, which we know to be 23 in length:

hash

The Solution

Using this hardcoded data along with our new equation, I decided to code a solution for the key using C.

code

After compiling and running the code, the key was successfully printed out!

key

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:

additional

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!

burp