Mark's Cybersecurity Write-Ups

Cyber Apocalypse 2023 - Misc - Remote Computation

The alien species use remote machines for all their computation needs. Pandora managed to hack into one, but broke its functionality in the process. Incoming computation requests need to be calculated and answered rapidly, in order to not alarm the aliens and ultimately pivot to other parts of their network. Not all requests are valid though, and appropriate error messages need to be sent depending on the type of error. Can you buy us some time by correctly responding to the next 500 requests?

We’re given a docker container that we can spawn and connect to.

Connecting to it we get a menu:

$ nc 64.227.41.83 30836
[-MENU-]
[1] Start
[2] Help
[3] Exit
>

1 starts the math problems coming. We’re expected to solve 500 of these. 2 shows some help, and shows us the curve-balls they’ll be sending us:

Results
---
All results are rounded
to 2 digits after the point.
ex. 9.5752 -> 9.58

Error Codes
---
* Divide by 0:
This may be alien technology,
but dividing by zero is still an error!
Expected response: DIV0_ERR

* Syntax Error
Invalid expressions due syntax errors.
ex. 3 +* 4 = ?
Expected response: SYNTAX_ERR

* Memory Error
The remote machine is blazingly fast,
but its architecture cannot represent any result
outside the range -1337.00 <= RESULT <= 1337.00
Expected response: MEM_ERR

Now that we know the rules, time to write some Python. I don’t know Python especially well, so this was a good opportunity to learn more about how it works. The code below took me several hours of tinkering to write.

import telnetlib, re

def strip_bad_characters(instr):
    return re.sub("[^0-9\-\+\/\* \(\)]", "", instr)

def calculate_response(equation):
    safe_equation = strip_bad_characters(equation)
    try:
        answer = round(eval(safe_equation), 2)
    except ZeroDivisionError:
        return "DIV0_ERR"
    except SyntaxError:
        return "SYNTAX_ERR"

    if answer > 1337.00:
        return "MEM_ERR"
    if answer < -1337.00:
        return "MEM_ERR"

    return str(answer)

def parse_response(response):
    re_groups = re.search(b"[.|\n]*\[(\d+)\]\: (.*) =.*", response)
    question_number = int(re_groups.group(1))
    equation = str(re_groups.group(2).decode("ascii"))
    response = calculate_response(equation)
    return (question_number, response, equation)

telnet = telnetlib.Telnet("64.227.41.83","30836")

telnet.read_until(b">")
telnet.write(b'1\n')

# Get into the loop
question_number = 0
while question_number < 500:
    # Read question
    response = telnet.read_until(b">")
    question_number, answer, equation = parse_response(response)
    print("%03d" % question_number,": ", equation, " = ", answer)

    # Send response
    telnet.write(answer.encode("ascii"))
    telnet.write(b"\n")

# Read everything that it gives us after
print(str(telnet.read_until(b">").decode("ascii")))

telnet.close

I added in code to check to make sure that only numbers and equation-related characters would show up - since I was using eval() to calculate the equations, I was expecting to see an equation show up that ran some naughty code. No such code seemed to come in, but… now I don’t have to worry about it.

When it finishes, we get the flag.

496 :  22 * 9 * 2 + 16 * 20 / 15  =  417.33
497 :  9 + 22 * 18 * 25 - 12 - 17 - 27 * 14 * 16 + 26 + 3 / 26 * 6 / 19  =  MEM_ERR
498 :  13 / 9 / 23 - 19 - 3 / 4 * 24 - 6 - 8 + 13 / 10 + 19  =  -30.64
499 :  10 / 9 - 16 + 17 * 16 / 13 - 13 / 2 + 23 - 14 - 19 * 7 * 9 / 27 + 29  =  -6.8
500 :  19 * 7 - 20 + 6 + 26 / 6 / 12 - 26 + 14  =  107.36
 [*] Good job! HTB{d1v1d3_bY_Z3r0_3rr0r}