Post

W1seGuy - tryhackme, hadrian3689, DrGonz0

W1seGuy - tryhackme, hadrian3689, DrGonz0

A w1se guy 0nce said, the answer is usually as plain as day.

wiseguy.png

The challenge requires solving a cryptographic puzzle using the provided source code and an open port (1337) on the target machine. Our objective is to thoroughly analyze the given resources, decipher the encryption mechanism, and ultimately retrieve the key needed to capture Flag 2.


First, I attempted to establish a connection to the target machine using Netcat on the provided port (1337). This initial step was crucial in interacting with the challenge service and understanding how it responds to incoming requests.

1
2
3
4
5
nc w1seguy.thm 1337
This XOR encoded text has flag 1:
26392c421143100d571537091578150645025202331f130a001e3d185134000518091400092e4b1c
What is the encryption key? key?
Nope nope nope

Analysis

In the provided source code, source.py

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
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
import random
import socketserver 
import socket, os
import string

flag = open('flag.txt','r').read().strip()

def send_message(server, message):
    enc = message.encode()
    server.send(enc)

def setup(server, key):
    flag = 'THM{thisisafakeflag}' 
    xored = ""

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

    hex_encoded = xored.encode().hex()
    return hex_encoded

def start(server):
    res = ''.join(random.choices(string.ascii_letters + string.digits, k=5))
    key = str(res)
    hex_encoded = setup(server, key)
    send_message(server, "This XOR encoded text has flag 1: " + hex_encoded + "\n")
    
    send_message(server,"What is the encryption key? ")
    key_answer = server.recv(4096).decode().strip()

    try:
        if key_answer == key:
            send_message(server, "correct key! Here is flag 2: " + flag + "\n")
            server.close()
        else:
            send_message(server, 'Close but no cigar' + "\n")
            server.close()
    except:
        send_message(server, "Something went wrong. Please try again. :)\n")
        server.close()

class RequestHandler(socketserver.BaseRequestHandler):
    def handle(self):
        start(self.request)

if __name__ == '__main__':
    socketserver.ThreadingTCPServer.allow_reuse_address = True
    server = socketserver.ThreadingTCPServer(('0.0.0.0', 1337), RequestHandler)
    server.serve_forever()

I observe that XOR encryption is used. Specifically, each character of the flag is XORed with the corresponding character of a repeating key. The key is 5 characters long, and if the plaintext exceeds this length, the key loops back to the beginning. Our objective is to accurately derive the key and reconstruct the plaintext flag from the given ciphertext. Since we have both the ciphertext and knowledge of the plaintext format, we can recover the key by XORing the encrypted characters with their plaintext equivalents.

\[C = P \oplus K\]

Where:

  • 𝐶 represents the ciphertext.
  • 𝑃 is the plaintext.
  • 𝐾 is the key.

Assuming the flag follows the standard TryHackMe format, starting with THM{, we can determine the first four characters of the key. To find the fifth character, we have two approaches.

  1. Brute-force Attack: Try all possible ASCII characters and check for validity.
  2. Pattern Matching: If the flag length is a multiple of 5, the last plaintext character } would have been XORed with the last character of the key. This helps me infer the missing key character.

Decryption Script

With this understanding, i construted a simple Python decrypt.py.

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
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
import socket

def derive_key_part(hex_encoded, known_plaintext, start_index):
    encrypted_bytes = bytes.fromhex(hex_encoded)
    derived_key = ""
    
    for i in range(len(known_plaintext)):
        derived_key += chr(encrypted_bytes[start_index + i] ^ ord(known_plaintext[i]))
    
    return derived_key

def xor_decrypt(hex_encoded, key):
    encrypted_bytes = bytes.fromhex(hex_encoded)
    decrypted_message = ""
    
    for i in range(len(encrypted_bytes)):
        decrypted_message += chr(encrypted_bytes[i] ^ ord(key[i % len(key)]))
    
    return decrypted_message

def connect_to_server(host, port):
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.connect((host, port))

    response = s.recv(1024).decode()
    print(f"[SERVER]: {response.strip()}")

    hex_encoded = response.split(":")[-1].strip()

    known_start = "THM{"
    known_end = "}"
    derived_key_start = derive_key_part(hex_encoded, known_start, 0)
    derived_key_end = derive_key_part(hex_encoded, known_end, len(hex_encoded) // 2 - 1)

    derived_key = (derived_key_start + derived_key_end)[:5] 
    print(f"Extracted Key: {derived_key}")

    decrypted_flag = xor_decrypt(hex_encoded, derived_key)
    print(f"Decrypted Flag 1: {decrypted_flag}")

    print(f"[INFO] Sending extracted key: {derived_key}")
    s.sendall((derived_key + "\n").encode())  

    server_response = s.recv(1024).decode()
    print(f"[SERVER RESPONSE]: {server_response.strip()}")

    while True:
        additional_data = s.recv(1024).decode()
        if not additional_data:
            break
        print(f"[SERVER RESPONSE]: {additional_data.strip()}")

    s.close() 

if __name__ == "__main__":
    SERVER_IP = "[REDACTED]" 
    SERVER_PORT = 1337          
    connect_to_server(SERVER_IP, SERVER_PORT)

With a straightforward execution of our Python script, I was able to successfully decrypt the ciphertext and capture both flags. The script efficiently leveraged the XOR decryption method, utilizing the reconstructed key to reveal the plaintext flags in a matter of seconds.

1
2
3
4
5
6
7
python3 decrypt.py
[SERVER]: This XOR encoded text has flag 1: 1e003f4e147b291e5b100f300.....
[INFO] Extracted Key: JHr5d
[+] Decrypted Flag 1: [REDACTED]
[SERVER RESPONSE]: What is the encryption key?
[INFO] Sending extracted key: JHr5d
[SERVER RESPONSE]: Congrats! That is the correct key! Here is flag 2: [REDACTED]

After capturing the both flags, solved-w1seGuy.jpeg i successfully solved W1seGuy room!


Happy hacking !

Here are some resources:

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