# Hidden Handshake

## OVERVIEW

---

Start The Instance and Download The Given Files:

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1758269727499/05ac3a0d-f151-4b13-9cf0-ab60143a68c2.png align="center")

**Let’s see the given server.py**

```python
import random, hashlib, string
from Crypto.Cipher import AES

def kdf(pass1, pass2):
    return hashlib.sha256(pass1 + pass2).digest()

def generate_password(length):
    alphabet = string.ascii_lowercase + string.digits + '!'
    return ''.join(random.choice(alphabet) for _ in range(length))

def encrypt(pass1, pass2, plaintext):
    key = kdf(pass1, pass2)
    cipher = AES.new(key, AES.MODE_CTR, nonce=pass2)
    ciphertext = cipher.encrypt(plaintext)
    return ciphertext

FLAG = open("flag.txt").read().strip()

print("=== Task Force Phoenix - Operation Blackout Interface ===")
print("Welcome, agent. Secure communications are now active.")
print("----------------------------------------------------------")

server_secret = generate_password(8)
while True:
    try:
        pass2 = input("Enter your secure access key: ")
        user = input("Enter your Agent Codename: ")
        assert len(pass2) == 8, "Secure access key must be 8 characters long."
        assert len(user) < 1337, "Codename too long."

        print("Establishing secure communication channel...")

        shared_secret = f"Agent {user}, your clearance for Operation Blackout is: {FLAG}. It is mandatory that you keep this information confidential."
        ciphertext = encrypt(server_secret.encode(), pass2.encode(), shared_secret.encode())

        print(f"Encrypted transmission: {ciphertext.hex()}")
        print("--- End of Transmission ---")
    except Exception as e:
        print(e)
        print("Transmission error.")
```

* So I analyzed it with the help of chatgpt and came to know that:  
    `server_secret` is generated once per server execution and used as the AES key derivation input. The server prints an encrypted message using `encrypt(server_secret.encode(), pass2.encode(), shared_secret.encode())`.
    
* The `encrypt` function derives a key with `kdf(pass1, pass2)` and creates an AES-CTR cipher with `nonce=pass2`.
    
* The important detail is that the **same** `pass2` value is used for every encryption made during that connection (the program reads `pass2` from input each loop, but the exploit keeps the TCP connection open and reuses the single `pass2` for multiple requests).
    
* So we exploit this by first obtaining the ciphertext that contains the flag, then requesting additional ciphertexts where we control the codename (sending carefully sized `"A"` strings so an `'A'` aligns with each target flag byte), and finally XORing the target ciphertext with each controlled ciphertext to cancel the keystream — since `C1 ⊕ C2 = P1 ⊕ P2` and `P2` is `'A'`, the flag bytes are recovered by `(C_target ⊕ C_known)[pos] ⊕ 0x41`
    

**So the below script is used to retrieve the flag** *(Be sure to change the required fields such as HOST , PORT)*

```python
#!/usr/bin/env python3
import socket
import time
import binascii
import sys

HOST = "Use Your Host Here"   #for eg "94.237.57.115"
PORT = <Use Your Port Here> #for eg 1337
PASS2 = "pass123!"
USER_TARGET = ""
MAX_FLAG_BYTES = 120
RECV_TIMEOUT = 3.0

PREFIX = "Agent "
MID = ", your clearance for Operation Blackout is: "
SUFFIX = ". It is mandatory that you keep this information confidential."

def recv_until(sock, marker, timeout=RECV_TIMEOUT):
    sock.settimeout(0.7)
    buf = ""
    tstart = time.time()
    while True:
        if marker in buf:
            return buf
        if time.time() - tstart > timeout:
            return buf
        try:
            data = sock.recv(4096)
            if not data:
                return buf
            buf += data.decode(errors="ignore")
        except socket.timeout:
            continue

def send_and_get_cipher(sock, pass2, user):
    recv_until(sock, "Enter your secure access key:")
    sock.sendall((pass2 + "\n").encode())
    recv_until(sock, "Enter your Agent Codename:")
    sock.sendall((user + "\n").encode())
    out = recv_until(sock, "--- End of Transmission ---", timeout=5.0)
    if "Transmission error." in out:
        return None
    for line in out.splitlines():
        if line.strip().startswith("Encrypted transmission:"):
            _, hx = line.split("Encrypted transmission:", 1)
            return hx.strip()
    return None

def hex_to_bytes(hx):
    return binascii.unhexlify(hx)

def xor_bytes(a, b):
    return bytes(x ^ y for x, y in zip(a, b))

def recover_flag_online(host, port, pass2, user_target, max_bytes=MAX_FLAG_BYTES):
    print(f"[+] connecting to {host}:{port} ...")
    sock = socket.create_connection((host, port))
    sock.settimeout(1.0)
    banner = recv_until(sock, "Enter your secure access key:", timeout=4.0)
    print(banner, end="")
    print(f"[+] requesting target ciphertext with user='{user_target}' ...")
    c_target_hex = send_and_get_cipher(sock, pass2, user_target)
    if not c_target_hex:
        print("[-] failed to get target ciphertext. Check pass2 and connectivity.")
        sock.close()
        return
    c_target = hex_to_bytes(c_target_hex)
    print(f"[+] got target ciphertext (len={len(c_target)} bytes)")
    start_target = len(PREFIX) + len(user_target) + len(MID)
    print(f"[+] computed FLAG start offset in plaintext = {start_target}")
    recovered = bytearray()
    for i in range(max_bytes):
        absolute_pos = start_target + i
        needed_user_len = absolute_pos - len(PREFIX) + 1
        if needed_user_len <= 0:
            needed_user_len = 1
        user_known = "A" * needed_user_len
        c_known_hex = send_and_get_cipher(sock, pass2, user_known)
        if not c_known_hex:
            print(f"[-] failed to get ciphertext for user_known length {needed_user_len}.")
            break
        c_known = hex_to_bytes(c_known_hex)
        if absolute_pos >= len(c_target) or absolute_pos >= len(c_known):
            print(f"[-] reached end of ciphertexts at pos {absolute_pos}. Stopping.")
            break
        pxor = xor_bytes(c_target, c_known)
        recovered_byte = pxor[absolute_pos] ^ ord('A')
        recovered.append(recovered_byte)
        ch = chr(recovered_byte) if 32 <= recovered_byte <= 126 else f"\\x{recovered_byte:02x}"
        print(f"[{i:03d}] pos={absolute_pos} -> {ch}")
        if recovered_byte == ord('}') or (len(recovered) > 5 and recovered[-1] == 10):
            print("[+] heuristic stop: found '}' or newline, stopping.")
            break
    sock.close()
    flag = recovered.decode(errors="ignore")
    print("\n[+] recovered bytes (best-effort):")
    print(flag)
    return flag

if __name__ == "__main__":
    print("CTR keystream-reuse exploit script")
    print("Make sure HOST/PORT and PASS2 are set at the top of this script.")
    try:
        recovered_flag = recover_flag_online(HOST, PORT, PASS2, USER_TARGET, MAX_FLAG_BYTES)
        print("\nDone.")
    except KeyboardInterrupt:
        print("\nInterrupted by user.")
    except Exception as e:
        print("Error:", e)
        raise
```

Use it as :

```python
python3 filename.py  #for kali linux, you can use python also in windows/linux 
```

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1758270732109/7ad48f48-bc7d-4278-95ba-e8dd43cd6592.png align="center")

**And Here We Got The Flag !!**

## **WE FINALLY DID IT !!!! CHALLENGE SOLVED !!**

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1758270794977/4e20ac66-aa1b-42fe-8229-36b10d623250.png align="center")

For Any Query Or Problem Either Leave A Comment Or Contact At [**reapsec.com**](http://reapsec.com/)

**THANKS FOR READING !!!**
