TryHackMe: Industrial Intrusion - auth (9005)

TryHackMe Industrial Intrusion CTF writeup. Reverse engineering challenge involving XOR decoding and memory comparison using Ghidra to retrieve the flag from a remote industrial gateway authentication module.

Earlier today, I played the TryHackMe Industrial Intrusion CTF with the ByteStorm team. One of the easy reverse engineering challenges I tackled, titled “auth”, had us unpacking a stripped-down authentication module running on a simulated industrial gateway.

Description

ZeroTrace intercepts a stripped-down authentication module running on a remote industrial gateway. Assembly scrolls across glowing monitors as she unpacks the logic behind the plant’s digital checkpoint.

Solution

Static Analysis

Using Ghidra, I analyzed the stripped binary and found that it accepts 8 bytes of input, applies a XOR transformation, and checks it against a specific hardcoded value.

Here’s the key logic from main:

undefined8 main(void) {
    ...
    local_160 = 0xefcdab8967452301;  // Target value in little-endian
    fgets((char *)local_158, 0x40, stdin);
    sVar4 = strnlen((char *)local_158, 0x40);
    if (sVar4 == 8) {
        local_168 = local_158[0];
        transform(&local_168, 8);
        if (memcmp(&local_168, &local_160, 8) == 0) {
            FILE* f = fopen("flag.txt", "r");
            fgets(local_118, 0x100, f);
            printf("[+] Access Granted! Flag: %s", local_118);
        } else {
            puts("[!] Access Denied!");
        }
    } else {
        puts("[!] Access Denied!");
    }
    ...
}

The transform() function used in this comparison is a simple XOR loop:

void transform(long param_1, ulong param_2) {
    for (int i = 0; i < param_2; i++) {
        *(byte *)(param_1 + i) ^= 0x55;
    }
}

Reversing the XOR

To pass the check, the XOR can simply be reversed.

# XOR the target bytes with 0x55
target = bytes([0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef])
payload = bytes([b ^ 0x55 for b in target])

Remote Interaction

The service was hosted at 10.10.195.10:9005. Since the input includes raw bytes, we used a Python script:

import socket

host = '10.10.195.10'
port = 9005

target = bytes([0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef])
payload = bytes([b ^ 0x55 for b in target])

with socket.create_connection((host, port)) as sock:
    sock.sendall(payload + b'\n')
    response = sock.recv(4096)
    print("[Server Response] ", response.decode(errors='ignore'))

Result

Executing the script triggered [+] Access Granted! and printed the flag from the remote system.