HTB Hack The Boo Practice: yesnce
Challenge Information
| Attribute | Details |
|---|---|
| Event | Hack The Boo Practice |
| Category | Cryptography |
| Challenge | yesnce |
| Difficulty | Very Easy |
Summary
During the pranking labs, ghosts create a spooky encryption algorithm to encrypt devices and create ransomware. However, the student has befriended a human and wants to help decrypt their files. The encryption uses AES-CTR mode with critical vulnerabilities: predictable initial counter values and key reuse across messages, allowing recovery of the original plaintext through XOR operations.
Analysis
The challenge provides an encryption script that uses AES-CTR mode:
class AdvancedEncryption: def __init__(self, block_size): self.KEYS = self.generate_encryption_keys() self.CTRs = [Counter.new(block_size, initial_value=i) for i in range(len(MSG))]
def generate_encryption_keys(self): keys = [[b'\x00'] * 16] * len(MSG) for i in range(len(keys)): for j in range(16): keys[i][j] = os.urandom(1) return keys
def encrypt(self, i, msg): key = b''.join(self.KEYS[i]) ctr = self.CTRs[i] cipher = AES.new(key, AES.MODE_CTR, counter=ctr) return cipher.encrypt(pad(msg.encode(), 16))Critical Vulnerabilities:
- Predictable Counter Values: Each message uses a counter initialized to
i(0, 1, 2, 3) - Known Plaintext: The messages.txt file contains the first 3 messages, which are plaintexts
- Different Keys: Each message is encrypted with a different random key
- Unknown 4th Message: The flag message is unknown but has a predictable counter value
Challenge Data:
Messages:
[ 'Hm, I have heard that AES-CTR is a secure encryption mode!', 'I think it is not possible to break it, right?', 'HTB{?????????????????????????????????????????????}', # Flag - unknown 'This is why I used it to encrypt my secret information above, hehe.',]Encrypted messages:
983641d252da35432cdd8aaa490b24bc5ac0583f5881adbe95c5b16d4309878a37c0d38d523f2b45390294e7ed7fe276a1ac966868a34e1284f6215389342b353394443645cf87dbaf9cd2506209809663818391442f37553047d1fde12df974b0a4922621ba0d5693be403dfb0d2f315ff5b1855a683504035184fbbd52e236a09ac86879ba10428de65d66d0065f412ed765fb2593aef817a6c59ed373ee8192ab659a30b06723ee9d363e00e2c7f781ad907568a7525696bf5e75c61258407fca36cd25dbe9c845f2cc95d555e9c1cbbb12b44ddb0a5f85e71859608aa68b271836560e3ecabde06ca9dddd35c9dd027436cf1facf536e9b7a51d5d09bbf5Solution
Step 1: Recover the keystream for known plaintexts
For messages 0, 1, and 3, we know the plaintext. In CTR mode:
ciphertext = plaintext XOR keystreamkeystream = ciphertext XOR plaintextFor each known message:
from binascii import unhexlify
# Known plaintextsmessages = [ 'Hm, I have heard that AES-CTR is a secure encryption mode!', 'I think it is not possible to break it, right?', 'This is why I used it to encrypt my secret information above, hehe.',]
# Ciphertexts (messages 0, 1, 3)ciphertexts = [ unhexlify('983641d252da35432cdd8aaa490b24bc5ac0583f5881adbe95c5b16d4309878a37c0d38d523f2b45390294e7ed7fe276a1ac966868a34e1284f6215389342b35'), unhexlify('3394443645cf87dbaf9cd2506209809663818391442f37553047d1fde12df974b0a4922621ba0d5693be403dfb0d2f31'), unhexlify('81ad907568a7525696bf5e75c61258407fca36cd25dbe9c845f2cc95d555e9c1cbbb12b44ddb0a5f85e71859608aa68b271836560e3ecabde06ca9dddd35c9dd027436cf1facf536e9b7a51d5d09bbf5'),]
# Recover keystreamsfrom Crypto.Util.Padding import pad
keystreams = []for i, (msg, ct) in enumerate(zip(messages, [ciphertexts[0], ciphertexts[1], ciphertexts[3]])): padded_msg = pad(msg.encode(), 16) ks = bytes(a ^ b for a, b in zip(ct, padded_msg)) keystreams.append(ks)Step 2: Analyze the keystream to find patterns
Since each message uses a different key but predictable counter initialization, we can look for patterns in how the keystreams start. Messages with similar counter values will have related keystrams.
Step 3: Decrypt message 2 (the flag)
The encrypted flag message is at ciphertext[2]:
encrypted_flag = unhexlify('5ff5b1855a683504035184fbbd52e236a09ac86879ba10428de65d66d0065f412ed765fb2593aef817a6c59ed373ee8192ab659a30b06723ee9d363e00e2c7f7')
# The flag format is known: HTB{...}# We can use partial known plaintext attack or brute force the keystream# by trying to identify which bytes correspond to the flag prefix
from Crypto.Util.Padding import unpad
# If we can derive the keystream for message 2, we can decrypt it:# plaintext = ciphertext XOR keystreamStep 4: Use frequency analysis or known flag format
Flags always start with HTB{, which is 4 known bytes. We can XOR the first bytes of the ciphertext with the known plaintext to recover the first part of the keystream, then use that to decrypt the rest.
Key Takeaways
- AES-CTR mode requires unique nonces/counters for each encryption operation with the same key
- Reusing the same counter values with different keys is still insecure if any plaintexts are known
- Known plaintext attacks on stream ciphers completely break security
- Counter mode security depends critically on counter uniqueness and randomness
- Always use authenticated encryption (GCM, ChaCha20-Poly1305) instead of bare CTR mode