Rating:

## Wolf
### Challenge

When we connect to the server, it chooses a random length `niv`
between 1 and 11, and a random nonce of that length. We can request
the flag encrypted using AES-GCM with the key `HungryTimberWolf` and
that IV, and ask for the server to encrypt our input with the same
parameters.

```python
#!/usr/bin/env python3

from Cryptodome.Cipher import AES
import os, time, sys, random
from flag import flag

passphrase = b'HungryTimberWolf'

def encrypt(msg, passphrase, niv):
msg_header = 'EPOCH:' + str(int(time.time()))
msg = msg_header + "\n" + msg + '=' * (15 - len(msg) % 16)
aes = AES.new(passphrase, AES.MODE_GCM, nonce = niv)
enc = aes.encrypt_and_digest(msg.encode('utf-8'))[0]
return enc

def die(*args):
pr(*args)
quit()

def pr(*args):
s = " ".join(map(str, args))
sys.stdout.write(s + "\n")
sys.stdout.flush()

def sc():
return sys.stdin.readline().strip()

def main():
border = "+"
pr(border*72)
pr(border, " hi wolf hunters, welcome to the most dangerous hunting ground!! ", border)
pr(border, " decrypt the encrypted message and get the flag as a nice prize! ", border)
pr(border*72)

niv = os.urandom(random.randint(1, 11))
flag_enc = encrypt(flag, passphrase, niv)

while True:
pr("| Options: \n|\t[G]et the encrypted flag \n|\t[T]est the encryption \n|\t[Q]uit")
ans = sc().lower()
if ans == 'g':
pr(f'| encrypt(flag) = {flag_enc.hex()}')
elif ans == 't':
pr("| Please send your message to encrypt: ")
msg_inp = sc()
enc = encrypt(msg_inp, passphrase, niv).hex()
pr(f'| enc = {enc}')
elif ans == 'q':
die("Quitting ...")
else:
die("Bye ...")

if __name__ == '__main__':
main()
```

### Solution

Since `niv` is uniformly random, in one out of 11 connections the nonce will only be one byte long. If this happens, we can easily bruteforce the encrypted flag: we already know the key, and can try all 256 nonce values to see if one of them gives a plaintext that looks like a flag.

A quick Python script collects encrypted flags, which we can dump into a single file to process later:

```python
#! /usr/bin/env python
from pwn import *

serv = pwnlib.tubes.remote.remote('01.cr.yp.toc.tf', 27010)
serv.sendline('g')
serv.sendline('q')

for line in serv.recvall().decode('utf-8').split('\n'):
if 'encrypt(flag)' in line:
print(line.rstrip().split()[-1])
```

The solver isn't much longer:

```python
#! /usr/bin/env python
from Cryptodome.Cipher import AES
import binascii

def trysolve(line):
for iv in range(256):
a = AES.new(b'HungryTimberWolf', AES.MODE_GCM, nonce=bytes([iv]))
flag = a.decrypt(binascii.unhexlify(line))
if b'CTF' in flag:
print(flag)

with open('flags.txt', 'r') as f:
for line in f.readlines():
if not line.startswith('['):
trysolve(line.rstrip())
```

##### Flag

`CCTF{____w0lveS____c4n____be____dan9er0uS____t0____p3oplE____!!!!!!}`

Original writeup (https://blog.cryptohack.org/cryptoctf2021-medium#wolf).