W1seGuy
W1seGuy
Platform: tryhackme | Category: Crypto | Type: Challenge | Difficulty: Easy | OS: NA | Author: XESXOR | Date: 2026-07-14 | Status: Solved Techniques: flag_prefix_key_recovery, known_plaintext_attack, repeating_key_xor_recovery
Summary
Task: TCP service XOR-encrypts a THM{...} flag with a random 5-char repeating key and hex-encodes it, revealing a second flag if you submit the correct key. Solution: known-plaintext attack using the THM{ prefix and trailing } to recover all 5 key bytes instantly, then replay the key to obtain flag 2.
W1seGuy — tryhackme
Description
A w1se guy 0nce said, the answer is usually as plain as day.
A Python source file and a live TCP service on port 1337 are provided. The service XOR-encrypts the real flag with a random 5-character key, hex-encodes it, and sends it as "flag 1". It then asks for the encryption key; submitting the correct key reveals a second flag. There are two flags to recover.
The title/description hint — "the answer is usually as plain as day" — points directly at a plaintext (known-plaintext) attack.
Recon / Analysis
The relevant server logic:
python read-only • copy alloweddef setup(server, key): flag = 'THM{thisisafakeflag}' xored = "" for i in range(0, len(flag)): xored += chr(ord(flag[i]) ^ ord(key[i % len(key)])) return xored.encode().hex() def start(server): res = ''.join(random.choices(string.ascii_letters + string.digits, k=5)) key = str(res) # random 5-char key from [A-Za-z0-9] 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() if key_answer == key: send_message(server, "Congrats! ... Here is flag 2: " + flag + "\n")
Key observations:
- The flag is encrypted with repeating-key XOR,
key[i % len(key)], wherelen(key) == 5. - The output is hex-encoded and sent in plaintext over the socket.
- The flag format
THM{...}is known, so the first 4 characters and the closing}are known plaintext.
Vulnerability
Repeating-key XOR with a short key plus a known flag format is a textbook
known-plaintext attack. Given ciphertext C and known plaintext P at position
i, the key byte is k[i % 5] = C[i] XOR P[i].
THM{(indices 0–3) directly recovers key bytesk0..k3.- The trailing
}(last index) recovers the remaining byte. For a 40-byte ciphertext, index39 → 39 % 5 = 4, givingk4.
All 5 key bytes are recovered with zero brute force. (Brute-forcing the
62^5 ≈ 916M key space is possible but unnecessary.)
Exploitation steps
- Connect to the service and read "flag 1" (the hex string).
- Hex-decode it to get the raw XOR ciphertext (40 bytes here).
- Recover
k0..k3from theTHM{prefix andk4from the trailing}. - XOR the ciphertext with the recovered repeating key → flag 1.
- Submit the recovered key string back to the service → flag 2.
Live run against 10.114.139.134:1337:
This XOR encoded text has flag 1: 322f0829335706293c37231f311337125326392027093761220a2b3c3a1614133c6236141f0a203e
Ciphertext is 40 bytes; recovered key = fgERC.
- Flag 1 (decrypting the hex):
THM{p1alntExtAtt4ckcAnr3alLyhUrty0urxOr} - Submitting key
fgERC→ Flag 2:THM{REDACTED}
Solver script
python read-only • copy allowed#!/usr/bin/env python3 import socket, sys HOST = sys.argv[1] PORT = int(sys.argv[2]) def recv_until(s, marker, timeout=10): s.settimeout(timeout) buf = b"" while marker not in buf: d = s.recv(4096) if not d: break buf += d return buf s = socket.create_connection((HOST, PORT)) data = recv_until(s, b"key?").decode(errors="replace") hexstr = None for line in data.splitlines(): if "flag 1:" in line: hexstr = line.split("flag 1:")[1].strip() break ct = bytes.fromhex(hexstr) # Known-plaintext recovery of the 5-byte repeating key known_prefix = b"THM{" key = [None] * 5 for i, ch in enumerate(known_prefix): key[i % 5] = ct[i] ^ ch li = len(ct) - 1 key[li % 5] = ct[li] ^ ord('}') # trailing '}' -> last key byte keystr = ''.join(chr(k) for k in key) flag1 = bytes(ct[i] ^ key[i % 5] for i in range(len(ct))).decode(errors="replace") print("KEY:", keystr, "FLAG1:", flag1) # Replay the key to unlock flag 2 s.sendall(keystr.encode() + b"\n") resp = recv_until(s, b"flag 2", timeout=10).decode(errors="replace") print(resp) s.close()
Run: python3 solve.py 10.114.139.134 1337
Flags
THM{p1alntExtAtt4ckcAnr3alLyhUrty0urxOr}
THM{REDACTED}
Key Indicators / Takeaways
Use this technique when:
- A service uses repeating-key XOR with a short key (
key[i % len(key)]). - The flag format prefix is known (
THM{,FLAG{, etc.), giving free known-plaintext bytes. - The ciphertext ends in a predictable character (
}) whose modular index maps onto the remaining key byte — this recovers the last key position without brute force. - Ciphertext is hex-encoded and delivered over a plaintext TCP channel.
- The challenge hint literally says "plain as day" → plaintext attack.