سبحان الله و بحمده سبحان الله العظيم ❤️
← BACK TO WRITEUPS
﴿وَقُلْ رَبِّ زِدْنِي عِلْمًا﴾ — طه: 114
Vulnerability
The Flask application uses a persistent MASTER_KEY and a static, hardcoded IV (12 bytes of nulls). The intern's implementation starts encryption at J₀ instead of J₁ = inc(J₀), meaning the first 16 bytes of keystream used for encryption are the same bytes used to blind the authentication tag.
def encrypt(self, P, A=b""):
J = self.iv + b"\x00"*(CTR_LEN-1) + b"\x01"
C = self.gctr(J, P)
T = self.build_tag(C, A, J)
return C, T
Exploitation
- Step 1: Register with known long username → recover keystream K by XORing known plaintext with ciphertext. First 16 bytes = Mask (E_K(J₀))
- Step 2: Recover GHASH key H by computing S = T ⊕ Mask, then finding roots of the GHASH polynomial over GF(2¹²⁸) using SageMath
- Step 3: Forge admin token: encrypt target JSON with recovered keystream, compute GHASH with recovered H, XOR with Mask for valid tag
Key Takeaways
- Never implement your own cryptographic primitives
- Nonce reuse in AES-GCM grants the attacker the authentication master key
- Respecting boundaries between encryption counters and authentication masks is vital
Flag
BZHCTF{ne_jamais_re-utiliser_le_nonce_e1d6ce70d3d1018c}