Welcome to my new verifier system, hope to be safe ;P
Wolves are social animals
Solution
Given code below
from Crypto.Util.number import*from random import getrandbitsSIZE=64FLAG=bytes_to_long(b'NHNC{FAKE_FLAG}')e =37p, q =getPrime(1024),getPrime(1024)while((p-1)*(q-1))% e ==0: p, q =getPrime(1024),getPrime(1024)N = p*qprint("=== ICEDTEA Verifier 1.0 ===")whileTrue:OTP=getrandbits(SIZE)print(f"signed: {pow(OTP, e, N)}")TRIAL=int(input("OTP: "))ifTRIAL==OTP:print(f"signed: {pow(FLAG, e, N)}")continueprint(f"Invalid OTP, {OTP}")
From code above we can see that we can try many OTP as we want and if the OTP is incorrect we can get the valid OTP. The OTP is 64 bit, by requesting 312 times OTP we can predict the next OTP using randcrack.
Each valid OTP will give us the encrypted version of flag which is m^e mod n_i, since we can reconnect multiple times and the flag is static we can request different modulus that will produce different ciphertext (c_i). Last, we can just implement CRT on known ciphertext (c_i) and modulus (n_i) to get the actual m^e with N > m^e.
To get the modulus, we can do the following equation
Next, by using two different ciphertext and plaintext we can recover the modulus by implementing GCD to those values. Following is my script to solve the challenge
Well ... those wolves don't know how to patch their verifier, so they implemented the new Wolves' Verifier + to keep you out from message plaintexts !
Solution
Given code below
The highlighted lines in the code above are the codes that were changed or added. Getrandbits changed from 64 bit to 65, in general we know that to predict getrandbits value we need to use 624 * 32 bit value. But in this case we got partial value which is 32 bit, 32 bit, and 1 bit. Looking at https://rbtree.blog/posts/2021-05-18-breaking-python-random-module/ we know that we can recover partial random value. The next problem is there is limitation 5 minutes for each connection to the service, using the python script given it takes more than 5 minutes to just recovering the state. So i decided to convert the python code to CPP to reduce the time to recover.
For the second part, there is random added to the flag but we can predict it also. So basically we can get the ciphertext, modulus, and the super_secret value. To get the flag we can utilize franklin reiter attack with a few changes of equation (m + r1 and m + r2 instead of m+0 and m+r1).
Following is the script i used to solve the challenge
πΊ Verifier Max (499 pts)
Description
Welcome to the (maybe) last journey in cracking Wolves' Verifier, why are you so persist in sniffing their secrets??
Solution
Given code below
The different with previous version is the signed OTP is shifted right 65 bit so we can't recover modulus using the same equations. But in this case we can use approximate GCD to recover the modulus with r_i is 65 bit.