The seed is hardcoded in seed.txt. It is read and used. Then a list is accepted as input. The given list must be at most of length 8. Then, 624 random 32-bit numbers are generated. If their index is present in the given list, they will be printed out.
Then, the key and nonce are generated (again using random.getrandbits), and the flag is encrypted.
In order to retrieve the seed, we need to retrieve all 624 numbers. Since the seed is hardcoded, we can repeatedly connect to the server to retrieve all of them. Each time we would retrieve a different idx from the server. Then, using randcrack, we can work out the Mersenne Twister seed, generate the key and nonce, and decrypt the flag.
from pwn import*from randcrack import RandCrackfrom Crypto.Cipher import AESfrom Crypto.Util.Padding import pad, unpadfrom hashlib import sha256context.log_level ='debug'rc =RandCrack()curr_idx =0for i inrange(78): conn =remote("vsc.tf", 5001) payload =b"["for j inrange(8): payload +=str(curr_idx).encode() payload +=b"," curr_idx +=1 payload +=b"]" conn.sendlineafter(b">>> ", payload)for j inrange(8): x = conn.recvline()info(x) x =int(x[:-1].decode()) rc.submit(x) conn.close()conn =remote("vsc.tf", 5001)conn.sendlineafter(b">>> ", b"[0]")conn.recvline()ct =bytes.fromhex(conn.recvline()[:-1].decode())# receive ciphertext in hex, convert to number in bytesconn.close()key = rc.predict_getrandbits(256)nonce = rc.predict_getrandbits(256)aes_key =sha256(str(key).encode()).digest()[:16]aes_nonce =sha256(str(nonce).encode()).digest()[:16]cipher = AES.new(aes_key, AES.MODE_GCM, nonce=aes_nonce)pt = cipher.decrypt(ct)print(unpad(pt, 16))# b'vsctf{dream_luck???_5e3ec2f2d338fc9f}'