by reading the file metadata, we were able to determine the file creation date and time down to the second. there are only 1000 candidates for the seed so that brute-forcing is a practical approach.
solver
from Crypto.Cipher import AES
from pwn import *
from tqdm import *
class WindowsRand:
def __init__(self, seed: int):
self.seed = seed
def rand(self):
self.seed = (self.seed * 214013 + 2531011) & 0xFFFFFFFF
return (self.seed >> 16) & 0x7FFF
def srand(self, seed: int):
self.seed = seed
def sub_1400015D0(rander: WindowsRand, a1: int, a2: int) -> int:
v3 = rander.rand()
v4 = rander.rand() * v3
return int(((rander.rand() * v4) & 0xffffffff) // (0xffffffff // (a2 - a1 + 1) + 1) + a1) & 0xffffffff
def rev_sub_140001650(a1,a2,rander: WindowsRand):
v5s:list[int] = []
for i in range(a2):
v5s.append(sub_1400015D0(rander,0, a2 - 1))
for i in reversed(range(len(v5s))):
v5 = v5s[i]
v3 = a1[i]
a1[i] = a1[v5]
a1[v5] = v3;
return bytes(a1)
year = 2024
month = 9
day_of_week = 2
day = 17
hour = 12
minute = 49
second = 20
for i in tqdm(range(1000)):
with open("flag.png.laika", "rb") as f:
data = list(f.read())
milliseconds = i
constant = 0x200ab
seed = (((((((((year + constant) * constant + month) * constant + day_of_week) * constant + day)
* constant + hour) * constant + minute) * constant + second) * constant + milliseconds) & 0xffffffff)
print(f"Seed: {seed}")
rand_gen = WindowsRand(seed)
key = bytes([(rand_gen.rand() & 0xFF) for _ in range(0x20)])
iv = bytes([(rand_gen.rand() & 0xFF) for _ in range(0x10)])
print(f"[{hex(seed)}] key @ {len(key)} , iv @ {len(iv)}")
print(f"Generated AES Key: {key}")
print(f"Generated IV: {iv}")
revData = rev_sub_140001650(data, len(data),rand_gen)
flag_data = b""
aeser = AES.new(key, AES.MODE_CBC, iv)
flag_data = aeser.decrypt(bytes(revData))
with open("out/myflag"+str(i) + ".png", "wb") as f:
f.write(flag_data)
execute the solver and I successfully decrypted the flag.png.laika