FCSC 2021 - Intro - La PIN
J’ai protégé le flag en le chiffrant avec des algorithmes modernes. Pourrez-vous le retrouver ?
Fichiers joints :
Résolution
Tout d’abord, lisons le script python lapin.py ayant servi à chiffrer le flag. Dans ce script nous remarquons un bloc permettant d’entrer un code pin compris entre 0 et 9999 :
while True:
pin = int(input(">>> PIN code (4 digits): "))
if 0 < pin < 9999:
break
La seconde partie gère le chiffrement du flag. La clé k
de chiffrement est générée grâce à une fonction de génération de clés scrypt ne dépendant que du PIN entré plus haut.
flag = open("flag.txt", "rb").read()
k = scrypt(long_to_bytes(pin), b"FCSC", 32, N = 2 ** 10, r = 8, p = 1)
Ensuite le flag est chiffré avec la clé k
sur AES en mode GCM et le message chiffré est sauvegardé sous format hexadécimal.
aes = AES.new(k, AES.MODE_GCM)
c, tag = aes.encrypt_and_digest(flag)
enc = aes.nonce + c + tag
print(enc.hex())
Maintenant que nous avons une idée de la manière dont le flag est chiffré, nous pouvons réfléchir à une attaque. La première idée qui vient est d’effectuer un bruteforce du PIN. En effet comme celui-ci est constitué de seulement 4 chiffres, le bruteforce sera très rapide.
Avant d’effectuer le bruteforce, nous devons lire le flag chiffré et extraire le nonce
de 16 bytes au début et le tag
de 16 bytes à la fin. Ensuite nous effectuons une boucle de 0 à 9999 pour généréer toutes les clés possible avec la fonction scrypt et nous tentons de déchiffrer et vérifier le message chiffré. Voici tout cela combiné dans un script python :
#!/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
Il ne reste plus qu’a lancer le script, et 2 minutes plus tard :
$ ./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
Et nous obtenons le flag :
FCSC{c1feab88e6c6932c57fbaf0c1ff6c32e51f07ae87197fcd08956be4408b2c802}