HackTheBox: Account

Contact: [email protected]

Follow me on: X

Check My: Github

W1seGuy

W1seGuy

Last modified: 2024-08-12 11:46:26

Machine name OS IP Difficulty
W1seGuy ? 10.10.191.163:1337 Easy

First flag

  1. Review the Python script

Since we have access to the script running on the other side of the connection, we can inspect how the encryption works:

for i in range(0,len(flag)):
    xored += chr(ord(flag[i]) ^ ord(key[i%len(key)]))
hex_encoded = xored.encode().hex()

| NOTE This image illustrates how the XOR cipher works (source - https://i.pcmag.com/imagery/encyclopedia-terms/xor-xor.fit_lim.size_1050x.gif):

  1. Retrieve the encryption key

XOR encrypts character by character, making it a stream cipher. We also know that the encrypted text starts with THM{ (in TryHackMe flag format).

As the server returns the ciphered text, we can extract the first 4 bytes (each byte is represented by 2 HEX characters) and deduce the first 4 characters of the key. This can be accomplished using the following script:

import socket
import string

HOST = "10.10.191.163"
PORT = 1337 

def setup(key, flag, encode):
    xored = ""

    for i in range(0,len(flag)):
        xored += chr(ord(flag[i]) ^ ord(key[i%len(key)]))

    if encode:
        return xored.encode().hex()

    return xored


def main():
    with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
        s.connect((HOST, PORT))
        data = s.recv(1024).decode('utf-8')
        xor_text = ""

        while not "What is the encryption key?" in data:
            if "This XOR encoded text has flag 1" in data:
                xor_text = data.split(":")[1].strip()

            data = s.recv(1024).decode('utf-8')

        final_key = ""

        for character in (string.ascii_letters + string.digits):
            if setup(character, "T", True) == str(xor_text[0:2]):
                final_key = final_key + character

        for character in (string.ascii_letters + string.digits):
            if setup(character, "H", True) == str(xor_text[2:4]):
                final_key = final_key + character

        for character in (string.ascii_letters + string.digits):
            if setup(character, "M", True) == str(xor_text[4:6]):
                final_key = final_key + character

        for character in (string.ascii_letters + string.digits):
            if setup(character, "{", True) == str(xor_text[6:8]):
                final_key = final_key + character

        print(final_key)

if __name__ == "__main__":
    main()

Next, we need to guess the last character. We can simply brute-force it and check if the last character is equal to } (since the flag follows the format THM{<whatever>}), and automate the process with the following script:

import socket
import string

HOST = "10.10.191.163"
PORT = 1337 

def setup(key, flag, encode):
    xored = ""

    for i in range(0,len(flag)):
        xored += chr(ord(flag[i]) ^ ord(key[i%len(key)]))

    if encode:
        return xored.encode().hex()

    return xored


def main():
    with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
        s.connect((HOST, PORT))
        data = s.recv(1024).decode('utf-8')
        xor_text = ""

        while not "What is the encryption key?" in data:
            if "This XOR encoded text has flag 1" in data:
                xor_text = data.split(":")[1].strip()

            data = s.recv(1024).decode('utf-8')

        final_key = ""

        for character in (string.ascii_letters + string.digits):
            if setup(character, "T", True) == str(xor_text[0:2]):
                final_key = final_key + character

        for character in (string.ascii_letters + string.digits):
            if setup(character, "H", True) == str(xor_text[2:4]):
                final_key = final_key + character

        for character in (string.ascii_letters + string.digits):
            if setup(character, "M", True) == str(xor_text[4:6]):
                final_key = final_key + character

        for character in (string.ascii_letters + string.digits):
            if setup(character, "{", True) == str(xor_text[6:8]):
                final_key = final_key + character

        for character in (string.ascii_letters + string.digits):
            tmp_key = final_key + character

            flag = setup(tmp_key, bytes.fromhex(xor_text).decode('utf-8'), False)
            if flag[-1] == "}":
                print("The flag is {} with key {}".format(flag, tmp_key))

if __name__ == "__main__":
    main()

| NOTE To decrypt the XOR cipher, we simply need to encrypt it again with the same key. That’s the fundamental principle of XOR. If we XOR 1 and 1, we get 0. However, if we XOR 0 with a key where the bit is set to 1, the XOR operation between 1 and 0 results in 1. | NOTE 2 When decrypting the final message, there's no need to encode it into HEX format.

After running this script, we retrieve the encryption key, which is used to decrypt the message, and we obtain the first flag.

Second flag

  1. Locate the second flag

The script sends the encryption key to the connection, and the second flag is returned in the response text. This process can be automated using the following script:

import socket
import string

HOST = "10.10.191.163"
PORT = 1337 

def setup(key, flag, encode):
    xored = ""

    for i in range(0,len(flag)):
        xored += chr(ord(flag[i]) ^ ord(key[i%len(key)]))

    if encode:
        return xored.encode().hex()

    return xored


def main():
    with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
        s.connect((HOST, PORT))
        data = s.recv(1024).decode('utf-8')
        xor_text = ""

        while not "What is the encryption key?" in data:
            if "This XOR encoded text has flag 1" in data:
                xor_text = data.split(":")[1].strip()

            data = s.recv(1024).decode('utf-8')

        final_key = ""

        for character in (string.ascii_letters + string.digits):
            if setup(character, "T", True) == str(xor_text[0:2]):
                final_key = final_key + character

        for character in (string.ascii_letters + string.digits):
            if setup(character, "H", True) == str(xor_text[2:4]):
                final_key = final_key + character

        for character in (string.ascii_letters + string.digits):
            if setup(character, "M", True) == str(xor_text[4:6]):
                final_key = final_key + character

        for character in (string.ascii_letters + string.digits):
            if setup(character, "{", True) == str(xor_text[6:8]):
                final_key = final_key + character

        for character in (string.ascii_letters + string.digits):
            tmp_key = final_key + character

            flag = setup(tmp_key, bytes.fromhex(xor_text).decode('utf-8'), False)
            if flag[-1] == "}":
                s.sendall((tmp_key + "\n").encode('utf-8'))
                data = s.recv(1024).decode('utf-8')
                print("Returned text: {}".format(data))

if __name__ == "__main__":
    main()

Retrieve both flags using the script

  1. Full script

With the following script, we can retrieve both flags:

import socket
import string

HOST = "10.10.191.163"
PORT = 1337 

def setup(key, flag, encode):
    xored = ""

    for i in range(0,len(flag)):
        xored += chr(ord(flag[i]) ^ ord(key[i%len(key)]))

    if encode:
        return xored.encode().hex()

    return xored


def main():
    with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
        s.connect((HOST, PORT))
        data = s.recv(1024).decode('utf-8')
        xor_text = ""

        while not "What is the encryption key?" in data:
            if "This XOR encoded text has flag 1" in data:
                xor_text = data.split(":")[1].strip()

            data = s.recv(1024).decode('utf-8')

        final_key = ""

        for character in (string.ascii_letters + string.digits):
            if setup(character, "T", True) == str(xor_text[0:2]):
                final_key = final_key + character

        for character in (string.ascii_letters + string.digits):
            if setup(character, "H", True) == str(xor_text[2:4]):
                final_key = final_key + character

        for character in (string.ascii_letters + string.digits):
            if setup(character, "M", True) == str(xor_text[4:6]):
                final_key = final_key + character

        for character in (string.ascii_letters + string.digits):
            if setup(character, "{", True) == str(xor_text[6:8]):
                final_key = final_key + character

        for character in (string.ascii_letters + string.digits):
            tmp_key = final_key + character

            flag = setup(tmp_key, bytes.fromhex(xor_text).decode('utf-8'), False)
            if flag[-1] == "}":
                s.sendall((tmp_key + "\n").encode('utf-8'))
                data = s.recv(1024).decode('utf-8')
                print("Returned text: {}".format(data))
                print("The flag is {} with key {}".format(flag, tmp_key))

if __name__ == "__main__":
    main()

Table of Contents

Back to home