$ cat writeup.md…
$ cat writeup.md…
hackthebox
Task: ChaCha20 stream cipher encrypts a known message and a flag using the same key and nonce. Solution: Recover keystream by XORing known plaintext with its ciphertext, then decrypt the flag.
The challenge provides a Python script that encrypts a known message and a secret flag using the ChaCha20 stream cipher. Both encryptions use the same key and the same nonce.
ChaCha20 is a stream cipher. It generates a keystream based on a key and a nonce. The ciphertext is produced by XORing the plaintext with this keystream:
C = P ⊕ KS
If the same key and nonce are used to encrypt two different messages ($P_1$ and $P_2$), the same keystream ($KS$) is generated for both:
Since we know $P_1$ (the known message) and $C_1$ (its ciphertext), we can recover the keystream: $KS = C_1 ⊕ P_1$
Once we have the keystream, we can decrypt the flag ($P_2$) using its ciphertext ($C_2$): $P_2 = C_2 ⊕ KS$
from Crypto.Cipher import ChaCha20 from secret import FLAG import os def encryptMessage(message, key, nonce): cipher = ChaCha20.new(key=key, nonce=iv) ciphertext = cipher.encrypt(message) return ciphertext if __name__ == "__main__": message = b"Our counter agencies have intercepted your messages and a lot " message += b"of your agent's identities have been exposed. In a matter of " message += b"days all of them will be captured" key, iv = os.urandom(32), os.urandom(12) encrypted_message = encryptMessage(message, key, iv) encrypted_flag = encryptMessage(FLAG, key, iv) data = iv.hex() + "\n" + encrypted_message.hex() + "\n" + encrypted_flag.hex() # ... write to out.txt
#!/usr/bin/env python3 def xor(a, b): return bytes([x ^ y for x, y in zip(a, b)]) message = b"Our counter agencies have intercepted your messages and a lot " message += b"of your agent's identities have been exposed. In a matter of " message += b"days all of them will be captured" with open("out.txt", "r") as f: nonce_hex = f.readline().strip() enc_message_hex = f.readline().strip() enc_flag_hex = f.readline().strip() enc_message = bytes.fromhex(enc_message_hex) enc_flag = bytes.fromhex(enc_flag_hex) # Recover keystream by XORing known plaintext with its ciphertext keystream = xor(enc_message, message) # Decrypt flag by XORing its ciphertext with the recovered keystream flag = xor(enc_flag, keystream) print(flag.decode())
Use this technique when:
$ cat /etc/motd
Liked this one?
Pro unlocks every writeup, every flag, and API access. $9/mo.
$ cat pricing.md$ grep --similar