gcm-nonce-reuse
GCM Nonce Reuse
Challenge: https://pentesterlab.com/exercises/gcm-nonce
Galois/Counter Mode (GCM) is a modern authenticated encryption mode that provides both confidentiality and integrity. It works by combining counter mode encryption with a Galois field authentication tag. A critical requirement in GCM is that the nonce or IV must never be reused with the same key. If the same nonce is used more than once, the security of the encryption completely breaks.
When nonce reuse happens, the encryption behaves similarly to CTR mode. The keystream generated from the key and nonce becomes identical for multiple encryptions. Because of this, an attacker can XOR two ciphertexts encrypted with the same nonce and recover relationships between the plaintexts. If one plaintext is known or controllable, the attacker can recover the other plaintext or even forge valid messages. This makes nonce reuse a severe cryptographic flaw that can lead to full compromise of confidentiality and authenticity.
Attack Flow
- Register and obtain encrypted data: First, create an account in the application and send a message. The server encrypts this message using GCM and returns the ciphertext along with the nonce and authentication tag. Save this encrypted output.
- Trigger nonce reuse: Send another message and observe whether the same nonce is reused. In this challenge, the application encrypts multiple messages using the same key and nonce. This is the main weakness that allows the attack. Collect at least two ciphertexts that share the same nonce.
- Recover the keystream: Since GCM internally uses counter mode, encrypting two plaintexts with the same nonce produces the same keystream. XOR one ciphertext with its known plaintext to recover the keystream.
Keystream = Ciphertext ⊕ Plaintext - Decrypt the target message: Use the recovered keystream and XOR it with the second ciphertext. This reveals the unknown plaintext.
Plaintext = Ciphertext ⊕ Keystream - Extract sensitive data or key: In this challenge, the decrypted plaintext contains secret information. By repeating the process, you can recover the hidden data and solve the challenge.
import base64
string = b'HACKFORGOODHACKFORGOODHACKFORGOODHACKFORGOODHACKFORGOODHACKFORGOODHACKFORGOOD'
encrypted_str = base64.b64decode(
'Roaf++rvZTjMg9tI8IPrZqdpnAme9vGOlnvI6g75lWt9eF5Y63Z7v6ALLq8jodQVmRswYJSFCOAbRo0HjymsDeWmZID4PcEnT0IpCIM='
)
required_value_to_decrypt = base64.b64decode(
'N/K/gMqTARuuqaYzhO2URo0K9iez1Nvi5QO/wT/cvhIMA3p/'
)
def xor(str1, str2):
return [(a ^ b) for a, b in zip(str1, str2)]
print("".join(chr(c) for c in xor(xor(encrypted_str, required_value_to_decrypt), string)))