Informations

  • Catégorie : Crypto
  • Niveau : Hard
  • Auteurs : SKIP et Hiruko
  • Flag : `MB{d0_n0t_us3_th3s3_k3ys_1n_pr0duct10n!}'

Intitulé

Un binaire étrange, une page de code obscur, qu'est ce qui pourrait mal se passer ?


🎯 Objectif

L'objectif ici est de déchiffrer le binaire fourni avec le challenge et de renvoyer le flag. Pour cela, on va passer par plusieurs étapes.

Write-up

L'idée du challenge est de reverse le code ASM donné et de comprendre les différents mécanismes de chiffrement appliqués, qui sont pour la plus part des xor sous différentes formes : un xor simple, un chiffrement de César, un autre xor simple mais obfusqué, et un xor qui prend sa partie du flag à l'envers et qui xor la fin de sa partie avec le début de la clé. La clé est soit prédéfinie, soit elle s'appuie sur le timestamp, qui est à bruteforce.

Script de déchiffrement du flag à partir du texte chiffré fourni : 1) On découpe l’hexadécimal en 4 blocs de 20 caractères (chaque bloc représente 10 octets chiffrés). 2) On applique l’inverse des 4 opérations décrites en assembleur : - Part1 : XOR avec xorK = 0x53 - Part2 : soustraction de polyK = 9 (mod 256) - Part3 : XOR avec optK = 113 - Part4 : XOR avec genK = 0x51 3) On réassemble le flag en intercalant les 4 sous-parties (P1, P2, P3, P4) pour reconstituer l’ordre original des 40 octets du flag. """ def hex_to_bytes(hexstr: str) -> bytes: """Convertit une chaîne hex en bytes.""" return bytes.fromhex(hexstr) def decrypt_part1(c1: bytes, xorK: int) -> bytes: """Inverse de : C1[i] = P1[i] XOR xorK ⟹ P1[i] = C1[i] XOR xorK.""" return bytes([b ^ xorK for b in c1]) def decrypt_part2(c2: bytes, polyK: int) -> bytes: """ Inverse de : C2[i] = (P2[i] + polyK) mod 256 ⟹ P2[i] = (C2[i] - polyK) mod 256 """ return bytes([(b - polyK) & 0xFF for b in c2]) def decrypt_part3(c3: bytes, optK: int) -> bytes: """Inverse de : C3[i] = P3[i] XOR optK ⟹ P3[i] = C3[i] XOR optK.""" return bytes([b ^ optK for b in c3]) def decrypt_part4(c4: bytes, genK: int) -> bytes: """Inverse de : C4[i] = P4[i] XOR genK ⟹ P4[i] = C4[i] XOR genK.""" return bytes([b ^ genK for b in c4]) def interleave_parts(p1: bytes, p2: bytes, p3: bytes, p4: bytes) -> bytes: """ Reconstitue le flag complet (40 octets) en intercalant les 4 sous-parties de 10 octets chacune : flag = [ p1[0], p2[0], p3[0], p4[0], p1[1], p2[1], p3[1], p4[1], ... p1[9], p2[9], p3[9], p4[9] ] """ flag = bytearray(40) for i in range(10): flag[4*i + 0] = p1[i] flag[4*i + 1] = p2[i] flag[4*i + 2] = p3[i] flag[4*i + 3] = p4[i] return bytes(flag) def main(): # Texte chiffré (hexadécimal) tel que donné dans l'énoncé cipher_hex = ( "1E63276060380C232663" # part1 (10 octets chiffrés) "4B6868687C3C3A7B6C77" # part2 (10 octets chiffrés) "0A1F040542081F410550" # part3 (10 octets chiffrés) "356122390E220E35602C" # part4 (10 octets chiffrés) ) # 1) On découpe en 4 blocs de 20 hex-chars (=> 10 octets chacun) blocs = [cipher_hex[i:i+20] for i in range(0, len(cipher_hex), 20)] c1 = hex_to_bytes(blocs[0]) # Partie 1 (10 octets) chiffrés c2 = hex_to_bytes(blocs[1]) # Partie 2 (10 octets) chiffrés c3 = hex_to_bytes(blocs[2]) # Partie 3 (10 octets) chiffrés c4 = hex_to_bytes(blocs[3]) # Partie 4 (10 octets) chiffrés # 2) On applique l’inverse des clés découvertes par rétro-ingénierie: xorK = 0x53 # clé unique utilisée pour la partie 1 (assembleur fixe à 83d) polyK = 9 # clé additif utilisée pour la partie 2 (9d) optK = 113 # clé XOR utilisée pour la partie 3 (113d) genK = 0x51 # clé XOR utilisée pour la partie 4 (81d) p1 = decrypt_part1(c1, xorK) p2 = decrypt_part2(c2, polyK) p3 = decrypt_part3(c3, optK) p4 = decrypt_part4(c4, genK) # Affichage intermédiaire (pour vérification) : print("Partie 1 (déchiffrée) :", p1.decode('ascii', errors='ignore')) print("Partie 2 (déchiffrée) :", p2.decode('ascii', errors='ignore')) print("Partie 3 (déchiffrée) :", p3.decode('ascii', errors='ignore')) print("Partie 4 (déchiffrée) :", p4.decode('ascii', errors='ignore')) print() # 3) On réassemble en intercalant pour obtenir le flag complet flag = interleave_parts(p1, p2, p3, p4) print("Flag reconstitué :", flag.decode('ascii')) if __name__ == "__main__": main()