[GreHack 2023][Write Up – Crypto] Middle-Grade

 

middle-grade.py

 

from random import SystemRandom 
from Crypto.Cipher import AES 
from Crypto.Util.number import long_to_bytes , bytes_to_long 
from hashlib import sha256 
from functools 
import reduce random = SystemRandom() 

def encrypt(plain, key): 
    Ks = [(key >> (12*i)) & (pow(2, 12) - 1) for i in range(4)] 
    reduce(lambda D,K:print(D,K) , Ks, plain) 
    return reduce(lambda D,K:AES.new(sha256(long_to_bytes(K)).digest(), AES.MODE_ECB).encrypt(D) , Ks, plain) 

if __name__ == "__main__": 
    key = random.getrandbits(48) 
    flag = b"GH{__fakeflag__}" 
    assert (len(flag) == 16) 
    plain = b"iloveGH!"*2 
    print("plain = '{}'".format(plain.decode())) 
    print("cipher = '{}'".format(encrypt(plain, key).hex())) 
    print("encrypted_flag = '{}'".format(encrypt(flag, key).hex()))
    plain = 'iloveGH!iloveGH!' 
    cipher = '0f973d8234b8086847b9d423617a19b0' 
    encrypted flag = 'bc4daf41f71e4dd958a852bbbbf8dfec'

Explication du programme

 

Le programme génère une clé de taille 48 bits. Ce nombre est ensuite séparé en base 4096 (2**12):

>>> from random import SystemRandom 
>>> random = SystemRandom() 
>>> key = random.getrandbits(48) 
>>> key 146736011813222 
>>> Ks = [(key >> (12*i)) & (pow(2, 12) - 1) for i in range(4)] 
>>> Ks 
[358, 3522, 1187, 2135] 
>>> sum([Ks[i] * 4096**i for i in range(4)]) 
146736011813222

Chacun de ces nombres va être converti en bytes, puis hashé en sha256. L’ensemble va composer les 4 clefs AES, qui vont successivement chiffrer le clair, en mode ECB, dans la fonction encrypt.

 

Exploitation

 

De base, le nombre de possibilité est de 4096 * 4096 * 4096 * 4096 = 2**48.
Cependant, vu qu’on a accès à un clair et son chiffré, et vu le nombre faible de possibilité à chaque étape, il est possible d’effectuer une attaque dite « Meet in the middle« .
Pour cela, on va tester toutes les possibilités pour la moitié des étapes dans un sens (4096 * 4096 possibilités), puis dans l’autre (4096 * 4096).
Le nombre de possibilités devient alors 2 * 4096 * 4096 = 2**25, qui est nettement moins.

from Crypto.Cipher import AES
from Crypto.Util.number import long_to_bytes , bytes_to_long
from hashlib import sha256
import binascii

plain = b'iloveGH!iloveGH!'
cipher = binascii.unhexlify('0f973d8234b8086847b9d423617a19b0')

possibilities = ""
for i in range(4096):
s1 = AES.new(sha256(long_to_bytes(i)).digest(),AES.MODE_ECB).encrypt(plain)
for j in range(4096):
s2 = AES.new(sha256(long_to_bytes(j)).digest(),AES.MODE_ECB).encrypt(s1)
possibilities += "%s %d %d\n"%(s2.hex(),i,j)
with open('possibilities.txt','w') as f:
f.write(possibilities)

possibilities = ""
for i in range(4096):
s1 = AES.new(sha256(long_to_bytes(i)).digest(),AES.MODE_ECB).decrypt(cipher)
for j in range(4096):
s2 = AES.new(sha256(long_to_bytes(j)).digest(),AES.MODE_ECB).decrypt(s1)
possibilities += "%s %d %d\n"%(s2.hex(),i,j)
with open('possibilities_reverse.txt','w') as f:
f.write(possibilities)

Le script va nous générer l’ensembles des différentes possibilités (en chiffrant dans « possibilities.txt », et en déchiffrant dans « possibilities.txt »). Plus qu’à trouver l’élément commun:

# On trie les deux listes cat possibilities.txt |awk '{ print $1 }'|sort > p1.txt 
cat possibilities_reverse.txt.txt |awk '{ print $1 }'|sort > p2.txt 
# On récupère l'élément commun des deux listes comm -12 p1.txt p2.txt 
# 81e11c88273f0f7ea2fded6c389189c0 
# On récupère les clefs de chiffrement 
cat possibilities.txt possibilities_reverse.txt |grep 81e11c88273f0f7ea2fded6c389189c0 
# 81e11c88273f0f7ea2fded6c389189c0 638 2697 
# 81e11c88273f0f7ea2fded6c389189c0 2557 2561

On peut alors déchiffrer le flag avec Ks (638, 2697, 2561 et 2557).

from Crypto.Cipher import AES 
from Crypto.Util.number import long_to_bytes , bytes_to_long 
from hashlib import sha256 import binascii 
plain = b'iloveGH!iloveGH!' 
cipher = '0f973d8234b8086847b9d423617a19b0' 7
encrypted_flag = 'bc4daf41f71e4dd958a852bbbbf8dfec' 
Ks = [638,2697,2561,2557] 
tmp = binascii.unhexlify(encrypted_flag) 
for i in Ks[::-1]: 
    tmp = AES.new(sha256(long_to_bytes(i)).digest(),AES.MODE_ECB).decrypt(tmp) 
print(tmp)

Flag

 

GH{m33t_t1me_:)}

BDENNEUINGÉNIEUR SÉCURITÉ
Yolo

Add a comment

*Please complete all fields correctly