FCSC 2021 - Intro - La PIN

Table of contents :

I protected the flag by encrypting it with modern algorithms. Can you find it?

Files :


Solving the challenge

First, read the python script rabbit.py which was used to encrypt the flag. In this script we notice a code block allowing to enter a pin code between 0 and 9999:

while True:
	pin = int(input(">>> PIN code (4 digits): "))
	if 0 < pin < 9999:
		break

The second part manages the flag encryption. The encryption key k is generated using a key generation function scrypt depending only of the PIN entered above.

flag = open("flag.txt", "rb").read()
k = scrypt(long_to_bytes(pin), b"FCSC", 32, N = 2 ** 10, r = 8, p = 1)

Then the flag is encrypted with the key k on AES in GCM mode and the encrypted message is saved in hexadecimal format.

aes = AES.new(k, AES.MODE_GCM)
c, tag = aes.encrypt_and_digest(flag)

enc = aes.nonce + c + tag
print(enc.hex())

Now that we have an idea of ​​how the flag is encrypted, we can think about an attack. The first idea that comes up is to brute force the PIN. Indeed as this one consists of only 4 digits, the bruteforce will be very fast.

Before doing bruteforce, we need to read the encrypted flag and extract the 16 byte nonce at the beginning and the 16 byte tag at the end. Then we make a loop from 0 to 9999 to generate all the keys possible with the function scrypt and we let’s try to decrypt and verify the encrypted message. Here is all of that combined in a python script:

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import binascii
from Crypto.Cipher import AES
from Crypto.Protocol.KDF import scrypt
from Crypto.Util.number import long_to_bytes

data = binascii.unhexlify("f049de59cbdc9189170787b20b24f7426ccb9515e8b0250f3fc0f0c14ed7bb1d4b42c09d02fe01e0973a7233d99af55ce696f599050142759adc26796d64e0d6035f2fc39d2edb8a0797a9e45ae4cd55074cf99158d3a64dc70a7e836e3b30382df30de49ba60a")
nonce, encrypted, tag = data[:16], data[16:-16], data[-16:]

print(' Nonce : %s' % nonce)
print(' tag   : %s' % tag)

for pin in range(0,9999):
	print('\r[>] Trying PIN %04d' % pin,end="")
	key = scrypt(long_to_bytes(pin), b"FCSC", 32, N = 2 ** 10, r = 8, p = 1)
	try:
		cipher = AES.new(key, AES.MODE_GCM, nonce=nonce)
		print(cipher.decrypt_and_verify(encrypted, tag))
	except Exception as e:
		pass

All that’s left to do is run the script, and 2 minutes later:

$ ./bf.py
 Nonce : b'\xf0I\xdeY\xcb\xdc\x91\x89\x17\x07\x87\xb2\x0b$\xf7B'
 tag   : b'M\xc7\n~\x83n;08-\xf3\r\xe4\x9b\xa6\n'
[>] Trying PIN 6273
 b'FCSC{c1feab88e6c6932c57fbaf0c1ff6c32e51f07ae87197fcd08956be4408b2c802}\n'
[>] Trying PIN 9998

And we get the flag:

FCSC{c1feab88e6c6932c57fbaf0c1ff6c32e51f07ae87197fcd08956be4408b2c802}