Catégories
ENISA Hackfest Reverse Write-ups

s3 simple secure system

Ce challenge fait partie de l’ENISA Hackfest 2020, un CTF organisé par l’European Union Agency for Cybersecurity ayant pour vocation de “remplacer” l’ECSC (European Cybersecurity Challenge) auquel je me suis qualifié suite au FCSC (French Cybersecurity Challenge).

Description du challenge

During an investigation we noticed that one of the employees used to this tool to encrypt some sensitive information. However, we were not able to recover the original information to see what has been leaked. Can you develop a decryptor for this?

Flag format: CTF{sha256}

Fichiers du challenge

Deux fichiers étaient joints au challenge et sont téléchargeables ici :
– Le binaire à reverse : chall
– Un fichier chiffré : encrypted2.txt

Première approche

Comme d’habitude on commence par prendre des informations rapides pour voir à quoi on a affaire.

$ xxd encrypted2.txt 
00000000: 3f32 d148 0860 05d2 7652 15b2 3714 9c35  ?2.H.`..vR..7..5
00000010: 6bd7 83ac 2de2 aec1 b7cd ce08 5cc3 8023  k...-.......\..#
00000020: 56ea 4a03 f78f 2f3b 58b4 334d b705 d60e  V.J.../;X.3M....
00000030: e3d9 f0f9 d7af 0c52 5b38 6e34 417c ffb1  .......R[8n4A|..
00000040: fb6d 8713 8e60 f210 3ade a29e edd1 5b1c  .m...`..:.....[.
00000050: 0b3d c88d a872 d233 9e17 06f9 00d2 6e09  .=...r.3......n.
00000060: 026b a5f4 c548 9d60 3cb9 f51a a85a e502  .k...H.`<....Z..
00000070: b7ff 0019 25f8 1bfb 371f a917 f6ff 6b96  ....%...7.....k.
00000080: 1e44 9c79 3141 8510 5f4d 2094 7be3 47fb  .D.y1A.._M .{.G.
00000090: aa44 e746 8d4d 45e7 4723 6715 dfa0 96d0  .D.F.ME.G#g.....
000000a0: ec67 feb4 d690 394e 53f1 bc3e ea04 c1ac  .g....9NS..>....
000000b0: b024 2a6e 204a 4bee 4cd6 af1b 0045 08e5  .$*n JK.L....E..
000000c0: aeda 50ce 499e 3d97 7cb3 a015 6ffb 8ad2  ..P.I.=.|...o...
000000d0: dad4 2559 0a87 e401 09a0 a8fe b1f1 9dbb  ..%Y............
000000e0: 6b43 1887 ada7 f116 eddd e9be a6bf c143  kC.............C
000000f0: 6275 1168 01e1 e1f8 8d1c 5575 e3fa f99d  bu.h......Uu....

On a ici un fichier chiffré qui fait exactement 256 octets… Intéressant, on continue avec le binaire.

$ file chall
chall: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 3.2.0, BuildID[sha1]=043e518baf912a1805f9efc7b74b64166d58a541, stripped

On a donc ici un binaire en x86_64 linké dynamiquement et stripped, c’est-à-dire sans symboles de debug (pas cool).
Pour avoir une première idée du contenu du programme on peut alors regarder la section .dynsym (Dynamic Symbol Table) ou bien la section .rela.dyn (Dynamic Relocations Records) du programme pour voir les librairies et fonctions importées dynamiquement.

$ objdump -R chall

chall:     format de fichier elf64-x86-64

DYNAMIC RELOCATION RECORDS
OFFSET           TYPE              VALUE 
0000000000201d40 R_X86_64_RELATIVE  *ABS*+0x0000000000000ab0
0000000000201d48 R_X86_64_RELATIVE  *ABS*+0x0000000000000a70
0000000000202008 R_X86_64_RELATIVE  *ABS*+0x0000000000202008
0000000000201fd8 R_X86_64_GLOB_DAT  __gmon_start__
0000000000201fe0 R_X86_64_GLOB_DAT  __libc_start_main@GLIBC_2.2.5
0000000000201fe8 R_X86_64_GLOB_DAT  _ITM_deregisterTMCloneTable
0000000000201ff0 R_X86_64_GLOB_DAT  _ITM_registerTMCloneTable
0000000000201ff8 R_X86_64_GLOB_DAT  __cxa_finalize@GLIBC_2.2.5
0000000000201f68 R_X86_64_JUMP_SLOT  __isoc99_fscanf@GLIBC_2.7
0000000000201f70 R_X86_64_JUMP_SLOT  fopen@GLIBC_2.2.5
0000000000201f78 R_X86_64_JUMP_SLOT  strlen@GLIBC_2.2.5
0000000000201f80 R_X86_64_JUMP_SLOT  RSA_check_key@OPENSSL_1_1_0
0000000000201f88 R_X86_64_JUMP_SLOT  BIO_new_mem_buf@OPENSSL_1_1_0
0000000000201f90 R_X86_64_JUMP_SLOT  __stack_chk_fail@GLIBC_2.4
0000000000201f98 R_X86_64_JUMP_SLOT  BIO_free_all@OPENSSL_1_1_0
0000000000201fa0 R_X86_64_JUMP_SLOT  fclose@GLIBC_2.2.5
0000000000201fa8 R_X86_64_JUMP_SLOT  RSA_public_encrypt@OPENSSL_1_1_0
0000000000201fb0 R_X86_64_JUMP_SLOT  EVP_PKEY_free@OPENSSL_1_1_0
0000000000201fb8 R_X86_64_JUMP_SLOT  d2i_PrivateKey_bio@OPENSSL_1_1_0
0000000000201fc0 R_X86_64_JUMP_SLOT  RSA_free@OPENSSL_1_1_0
0000000000201fc8 R_X86_64_JUMP_SLOT  fwrite@GLIBC_2.2.5
0000000000201fd0 R_X86_64_JUMP_SLOT  EVP_PKEY_get1_RSA@OPENSSL_1_1_0

On voit donc ici que des fonctions sont importées de la libc (rien d’étonnant ici) mais surtout de OpenSSL : des fonctions en rapport avec le chiffrement asymétrique RSA (https://fr.wikipedia.org/wiki/Chiffrement_RSA).

Reverse

Flowchart

Bon ! Il est temps de se frotter à ce binaire et de voir ce qu’il nous cache. On dirait que tout se passe dans le main et le flowchart n’annonce pas de difficulté particulière.

En effet on voit ici quelques checks qui convergent, à priori pas de junk code ou de code obfusqué : ça devrait être facile !

On va commencer par faire un tour d’horizon du flow d’exécution, pour voir le fonctionnement global du programme.

Survolons le main

En survolant la fonction main on remarque différents checks avec des sauts conditionnels.

En effet on peut voir ici la gestion de l’error code avec le registre EAX : si le programme s’exécute correctement, EAX sera à 0 au moment du call de la fonction que j’ai appelée _canary_check. Sinon, EAX prendra au choix les valeurs 0xFFFFFFFF, 0xFFFFFFFE, 0xFFFFFFFD ou 0xFFFFFFFC c’est à dire -1, -2, -3 ou -4 (c’est le return du main avec des error codes custom).

La fonction _canary_check sert quand à elle à vérifier qu’il n’y a pas de buffer overflow. En effet, cela consiste à pousser une valeur sur la stack (qui, dans l’idéal, est aléatoire) en début de fonction et à ensuite vérifier que cette valeur n’aie pas changé. Ici, notre stack canary est donc var_8, mais ceci fera l’objet d’un prochain article 😀

Clé privée RSA

Dans le deuxième bloc du main on remarque le call à la fontion _BIO_new_mem_buf d’OpenSSL qui est souvent significatif du stockage d’une clé en mémoire.

Les deux arguments passés ici sont dans RDI et ESI : on va stocker le buffer var_24D0 sur 1193 octets, ce qui pourrait correspondre à notre clé privée RSA.

On va donc chercher à quel moment le buffer var_24D0 est initialisé pour retrouver notre clé RSA en analyse statique (comme le code n’est pas obfusqué, binaire non packé etc ce devrait être facile).

On remonte alors dans le premier bloc du main (partie “initialisation”) et on remarque plusieurs MOVSQ qui a pour effet de copier le QWORD contenu dans DS:RSI dans ES:RDI.

On voit donc ici que dans le premier MOVSQ effectué RSI pointera vers un buffer appelé unk_E20 et que RDI pointera vers notre buffer var_24DO. La clé privée doit donc se trouver dans le buffer unk_E20 !

Bingo ca y ressemble bien ! On extrait donc cette clé privée RSA en hexa et on se prépare à solve ce challenge 🙂

Solve avec python

from Crypto.PublicKey import RSA
from Crypto.Cipher import PKCS1_v1_5

private_key = [
    0x30, 0x82, 0x04, 0xA5, 0x02, 0x01, 0x00, 0x02, 0x82, 0x01, 0x01, 0x00, 0xC3, 0x7C, 0x4A, 0x39, 0x6E, 0xAA, 0x92, 0x65, 0x8D, 0x46, 0xD8, 0x87, 0x40, 0xC2, 0xFD, 0x40, 0x80, 0xE4, 0x5E, 0x56, 0x28, 0xDA, 0x8C, 0x6D, 0x32, 0xDB, 0x9A, 0xBC, 0xC7, 0x3E, 0xDF, 0xEF, 0x6D, 0x60, 0x6A, 0x90, 0xEC, 0xA9, 0xBA, 0xD7, 0xF1, 0x57, 0xC3, 0xB9, 0x60, 0x84, 0x53, 0xD2, 0x21, 0x4B, 0x07, 0x25,
    0x76, 0x28, 0xED, 0x44, 0xD6, 0x6F, 0x1E, 0x82, 0xDA, 0x1C, 0xF3, 0xFF, 0xF0, 0xE0, 0x66, 0x0F, 0x1E, 0x8C, 0xC4, 0x5F, 0x77, 0x33, 0x5E, 0xAA, 0x2E, 0x0C, 0xCE, 0x00, 0xCE, 0xE5, 0x9D, 0xE8, 0x68, 0x79, 0xCD, 0x7A, 0x5E, 0x66, 0x3A, 0x5C, 0x9D, 0x4D, 0x4F, 0x9F, 0xDE, 0x2B, 0xAC, 0x86, 0x0B, 0xCA, 0x6C, 0x49, 0x31, 0xB6, 0x1D, 0x9C, 0xD6, 0xD9, 0x28, 0x3C, 0x1A, 0x48, 0xDE, 0x68, 0x69, 0x92, 0xC3, 0x65, 0x47, 0x63, 0xE0, 0x53, 0x7D, 0x69, 0x14, 0x2A, 0x14, 0xCC, 0x0E, 0xD5, 0x0F, 0x63, 0xC4, 0x43, 0xF3, 0xB5, 0x2C, 0x32, 0x94, 0x06, 0xBD, 0x2D, 0x3F, 0x2E, 0xE6, 0xFC,0x22, 0xA5, 0x9A, 0x8B, 0xA4, 0x3E, 0x12, 0x98, 0x36, 0xA6, 0xDC, 0x15, 0x74, 0x21, 0x9A, 0xFA,
    0x59, 0x6B, 0x7A, 0xD9, 0x08, 0x5F, 0x3F, 0xFD, 0x97, 0x72, 0x8A, 0x6B, 0x74, 0xE7, 0x14, 0x25, 0x28, 0x0E, 0x24, 0xA2, 0xE3, 0xDF, 0x4D, 0xA6, 0x81, 0x87, 0xE9, 0x26, 0x89, 0x42, 0x54, 0x2B, 0x43, 0x0B, 0x4D, 0xFB, 0x80, 0x71, 0xCE, 0x98, 0xD9, 0xCF, 0x5C, 0xDC, 0xCF, 0xCB, 0x80, 0x11, 0xA5, 0xC9, 0x8E, 0x53, 0xA0, 0xC0, 0x11, 0x06, 0x3C, 0x06, 0xE1, 0x3D, 0xF5, 0x00, 0x13, 0x77, 0x47, 0x13, 0x4B, 0x5B, 0xE9, 0xEB, 0xF8, 0xB6, 0xE7, 0xDC, 0x4A, 0xAA, 0xC0, 0xA7, 0x1B, 0x12, 0xA9, 0x51, 0x79, 0x23, 0x50, 0x48, 0x3D, 0x3D, 0xEC, 0xD4, 0x6C, 0xF5, 0x02, 0x03, 0x01, 0x00,0x01, 0x02, 0x82, 0x01, 0x00, 0x68, 0xE7, 0x2C, 0xE9, 0xAF, 0x12, 0x87, 0xE7, 0x49, 0x2E, 0x28,
    0x8A, 0x44, 0x5D, 0x9F, 0x0B, 0xDB, 0x5F, 0x31, 0xA4, 0xA8, 0xDD, 0xC7, 0x17, 0xDE, 0x7F, 0xEC, 0x84, 0xBB, 0xA3, 0x69, 0x06, 0x92, 0x3A, 0x78, 0x55, 0x77, 0x3B, 0x0A, 0x12, 0x51, 0xE8, 0x18, 0x17, 0x45, 0xCD, 0x1D, 0x32, 0x19, 0x3D, 0xAB, 0x03, 0x16, 0x6A, 0x96, 0x11, 0x27, 0xC5, 0x8F, 0xA9, 0x06, 0xA5, 0x1C, 0xE7, 0x4E, 0xFB, 0x0C, 0xA9, 0xB6, 0x6A, 0x32, 0x03, 0x4C, 0xF3, 0x5B, 0x2C, 0x95, 0xF3, 0xB7, 0x24, 0xC5, 0xE2, 0x80, 0x9F, 0xB4, 0x59, 0x10, 0xC4, 0x47, 0x1E, 0x32, 0xD9, 0x7A, 0x6C, 0x7F, 0x7B, 0x39, 0xFD, 0x53, 0xE2, 0xC7, 0x37, 0x04, 0x6F, 0x2E, 0xE7, 0x1C,0xF3, 0x0A, 0x74, 0x94, 0x5B, 0xD4, 0x7B, 0x20, 0x27, 0x05, 0xE8, 0x85, 0x44, 0xB7, 0x4F, 0xC8,
    0x94, 0xE5, 0x2A, 0xDB, 0x6F, 0x5D, 0x30, 0x5B, 0x57, 0x3A, 0x53, 0x3F, 0xF9, 0xD6, 0xB1, 0x3F, 0x18, 0xE7, 0x03, 0x75, 0x49, 0x30, 0x2D, 0xCC, 0x21, 0x6D, 0xF6, 0xC3, 0xEA, 0xBF, 0xE2, 0xE9, 0x93, 0x9C, 0x71, 0xA1, 0xDF, 0x7E, 0x43, 0x39, 0x5B, 0x7A, 0x70, 0x79, 0x2C, 0xC7, 0xB0, 0xB6, 0x85, 0xEA, 0xD0, 0x14, 0xE6, 0xE3, 0x37, 0x0C, 0x75, 0xCF, 0x7E, 0xB8, 0x92, 0x29, 0x7F, 0xFF, 0x26, 0x20, 0xD3, 0x3F, 0xCF, 0xE8, 0xFF, 0x4A, 0x24, 0x39, 0xD3, 0x94, 0xDF, 0x6B, 0xFC, 0xE7, 0x13, 0x39, 0x17, 0x37, 0x95, 0xE7, 0x47, 0x9C, 0xDB, 0xA4, 0xE5, 0x80, 0x32, 0x51, 0x49, 0xC6,0xAB, 0xEF, 0x53, 0xFA, 0xE4, 0x0F, 0x17, 0xEF, 0x4F, 0xD8, 0xA1, 0x82, 0x80, 0x8F, 0xF6, 0x8B,
    0x3F, 0xC3, 0x24, 0x1A, 0x37, 0x9B, 0x31, 0x6A, 0x18, 0x1F, 0x30, 0xFB, 0x9E, 0xE3, 0xB6, 0xED, 0xC0, 0x03, 0x14, 0x43, 0x01, 0x02, 0x81, 0x81, 0x00, 0xEC, 0x2C, 0xD8, 0x58, 0x85, 0x95, 0xCD, 0xFA, 0x4B, 0x3D, 0x24, 0x7E, 0x55, 0x56, 0x76, 0x05, 0xF9, 0x1C, 0xDB, 0x0C, 0xAA, 0xA5, 0x6E, 0x85, 0x6F, 0x74, 0x72, 0x41, 0xBA, 0x12, 0x10, 0x01, 0xB1, 0x83, 0x39, 0xDB, 0xF0, 0x5A, 0x15, 0x0C, 0xA0, 0x7E, 0x91, 0x6B, 0xB0, 0x63, 0x12, 0x82, 0x91, 0x2E, 0x6A, 0xE5, 0x4C, 0x35, 0x69, 0x5D, 0x2A, 0x72, 0xFE, 0xAD, 0xFC, 0x3F, 0x64, 0xD7, 0xEF, 0x64, 0x8D, 0xD9, 0x0C, 0x84, 0x72,0x20, 0xC9, 0xB7, 0x1A, 0x34, 0x6B, 0xCD, 0xC6, 0xA3, 0xB4, 0x8F, 0x89, 0xF0, 0x7E, 0x2B, 0xBD,
    0x65, 0xC6, 0x6A, 0x67, 0x03, 0x8C, 0x4F, 0x5A, 0xAE, 0xD5, 0x1E, 0xCD, 0xBB, 0x22, 0x6D, 0x64, 0x03, 0x15, 0x0B, 0x47, 0x5C, 0x48, 0x7A, 0xF3, 0x0F, 0x2F, 0x1E, 0xE9, 0x9E, 0xF6, 0x2C, 0xA0, 0xEC, 0x9C, 0x46, 0x69, 0xE1, 0xD5, 0xD9, 0xDB, 0xC1, 0x02, 0x81, 0x81, 0x00, 0xD3, 0xE5, 0x11, 0x1E, 0x4F, 0xF2, 0x4C, 0x1D, 0x8A, 0xA9, 0x01, 0x73, 0x41, 0x84, 0x7D, 0xE3, 0x48, 0x7E, 0x9A, 0xFD, 0x9C, 0x86, 0xA5, 0xCB, 0x0E, 0xAF, 0x0B, 0xFC, 0x35, 0xEB, 0xBE, 0x82, 0x09, 0xC6, 0x38, 0x8A, 0x2D, 0xF6, 0x32, 0xC5, 0x15, 0x7D, 0x21, 0x80, 0xC0, 0x1F, 0xD3, 0xA2, 0x65, 0xC3, 0x7A,0xF4, 0x85, 0x20, 0x59, 0xB9, 0xB9, 0x60, 0xD4, 0xF3, 0x1E, 0xA5, 0x09, 0x8C, 0xED, 0x28, 0xF7,
    0x98, 0xDF, 0x2F, 0x91, 0xCF, 0x99, 0x7C, 0x95, 0x83, 0x66, 0xB7, 0x71, 0xA1, 0x45, 0x96, 0x78, 0x20, 0x32, 0x18, 0xED, 0x71, 0x5C, 0x8C, 0xE9, 0xBD, 0xCF, 0xAA, 0x68, 0x32, 0x90, 0x29, 0x24, 0xC6, 0xCE, 0xB8, 0xF7, 0x7F, 0xB6, 0x9C, 0x3B, 0x1F, 0xBE, 0xFE, 0x99, 0x1D, 0x61, 0xB3, 0x5D, 0x18, 0x00, 0x9D, 0x72, 0x5B, 0x8E, 0x13, 0xAD, 0x8F, 0x41, 0x8D, 0x6E, 0x35, 0x02, 0x81, 0x81, 0x00, 0x8D, 0x82, 0x81, 0x4E, 0xE9, 0x1B, 0xCD, 0x83, 0x3F, 0x39, 0xAF, 0x78, 0x12, 0xE1, 0xEF, 0x6D, 0xBC, 0xC9, 0xD1, 0x66, 0x51, 0x89, 0x36, 0x23, 0xB5, 0x98, 0x6C, 0x2D, 0x7D, 0xB3, 0xFC,0xEB, 0x46, 0xD5, 0x7E, 0x01, 0x8E, 0x8E, 0x2B, 0x36, 0x99, 0xA3, 0xBC, 0xB6, 0x6D, 0xC5, 0xAE,
    0xFD, 0x94, 0xC7, 0xDF, 0x3C, 0xEC, 0xE0, 0xC3, 0xF5, 0x12, 0xCE, 0x3C, 0x53, 0x3B, 0x65, 0x30, 0xA3, 0x41, 0xC9, 0x5A, 0x44, 0xC6, 0xFF, 0x44, 0xF2, 0xE8, 0x6A, 0x51, 0xC5, 0x3F, 0x22, 0xD8, 0xF6, 0x95, 0xE5, 0xBB, 0x9C, 0xE1, 0xBC, 0x8B, 0x8B, 0x43, 0xCB, 0xD5, 0x55, 0x86, 0xE8, 0xB5, 0x49, 0x34, 0x61, 0x74, 0x9B, 0xC0, 0x11, 0x13, 0x6F, 0xD5, 0x58, 0x20, 0xB5, 0xE6, 0xA7, 0xE4, 0xA3, 0x20, 0x74, 0xC1, 0x3E, 0x81, 0xFA, 0x53, 0xA1, 0xF2, 0x31, 0x2E, 0x98, 0x26, 0x6E, 0x97, 0x01, 0x02, 0x81, 0x81, 0x00, 0xA1, 0x9A, 0xFF, 0xCE, 0x4D, 0x8C, 0xEF, 0x0E, 0x4C, 0xD5, 0x8E,0xDC, 0x97, 0x68, 0x74, 0x16, 0xA7, 0x10, 0xA0, 0x26, 0xB2, 0x7D, 0x62, 0xEF, 0x16, 0x38, 0xDC,
    0xFC, 0x33, 0x27, 0xA3, 0xF9, 0x4B, 0x79, 0x19, 0x60, 0x11, 0xA3, 0xC6, 0x9E, 0xD7, 0x3F, 0xC3, 0x10, 0x8D, 0xF6, 0xF8, 0x12, 0xD0, 0x68, 0x21, 0x5B, 0x62, 0x39, 0x05, 0x15, 0x87, 0xD3, 0xD9, 0x35, 0xBE, 0xF6, 0x81, 0xED, 0x30, 0x67, 0x61, 0x46, 0xFF, 0x59, 0x29, 0x6C, 0xDA, 0x93, 0xD0, 0xF8, 0x11, 0x9B, 0xF1, 0x16, 0xDD, 0x9A, 0xDF, 0xED, 0x36, 0x28, 0x1A, 0xD7, 0xAD, 0x8D, 0x6F, 0x2B, 0xAB, 0xB9, 0x3C, 0x94, 0xEB, 0xAB, 0xE5, 0x77, 0x96, 0xEC, 0x2D, 0x1F, 0x03, 0x67, 0xEE, 0x13, 0xCD, 0x38, 0x22, 0x10, 0xED, 0x95, 0xBD, 0x77, 0x73, 0xE8, 0xA0, 0xF2, 0x40, 0xCE, 0xB3,0x3D, 0x21, 0xF2, 0xBA, 0xCD, 0x02, 0x81, 0x81, 0x00, 0xE8, 0x1C, 0x93, 0x52, 0x86, 0x9D, 0x5A,
    0xC3, 0xE3, 0x0B, 0x33, 0xCC, 0x90, 0x91, 0xC8, 0xE4, 0xEC, 0x4B, 0x66, 0xB1, 0x2C, 0xE4, 0x3C, 0x28, 0xD3, 0x32, 0xB4, 0xE4, 0xB9, 0x06, 0xAE, 0x25, 0x81, 0xDF, 0xB5, 0x31, 0x79, 0x7A, 0x12, 0x1D, 0x10, 0x00, 0x77, 0x2B, 0x0F, 0x03, 0x02, 0xEB, 0x82, 0xC1, 0x42, 0x96, 0x93, 0x8F, 0x0F, 0x94, 0xA5, 0x60, 0xC5, 0xA9, 0x0A, 0xD4, 0xEA, 0xF5, 0xA7, 0x37, 0xFB, 0xB4, 0xDB, 0x5A, 0x7F, 0xA7, 0x08, 0xF4, 0x78, 0xBE, 0xCC, 0x15, 0x3A, 0x3E, 0x00, 0xC4, 0x51, 0x4D, 0x2C, 0x40, 0x0B, 0x56, 0xAB, 0x87, 0xCE, 0x49, 0x25, 0x14, 0x75, 0x65, 0x97, 0xDB, 0x32, 0x5E, 0x15, 0x8B, 0x1C,0xF2, 0x8C, 0xB0, 0xC7, 0xD8, 0xCA, 0x47, 0xE0, 0xE8, 0xCC, 0x56, 0x47, 0xA6, 0x58, 0x8E, 0x7B,
    0xBC, 0x6F, 0x7A, 0xA2, 0x51, 0x41, 0xE1, 0x65, 0xDC
]
private_key = bytearray(private_key)

enc_file = open('encrypted2.txt', "r")
enc_data = enc_file.read()

key = RSA.import_key(private_key)
cipher = PKCS1_v1_5.new(key)
flag = cipher.decrypt(enc_data, "[-] FAIL")

print("\n[+] FLAG : "+flag)

On exécute alors le script et on trouve le flag.

$ python solveur.py 

[+] FLAG : CTF{67131493f75e92a06c5524b7c4c2be3513d992dafeb03e0e0296df0c5716155b}

Si on ne sait pas utiliser python (ou que comme moi on a bien souvent la flemme), on peut utiliser ce que j’appellerais la méthode -tout aussi efficace !- du paresseux…

Solve avec des outils online

Pourquoi s’embêter avec python alors qu’il y a internet me direz-vous ? Eh bien c’est très simple c’est parce que… Parce que…. Hum…… Ok on va le faire avec internet, vous avez gagné.

On doit commencer par convertir notre clé privée (actuellement en hexadécimal) en base64. Pour cela on peut utiliser le site suivant : https://holtstrom.com/michael/tools/hextopem.php.

Ok super on a une belle clé privée en base64 ! Maintenant on va également convertir notre fichier “encrypted2.txt” en base64.
Bon pour le coup c’est faisable avec une ligne de commande de deux mots…

$ base64 encrypted2.txt
PzLRSAhgBdJ2UhWyNxScNWvXg6wt4q7Bt83OCFzDgCNW6koD948vO1i0M023BdYO49nw+devDFJb
OG40QXz/sftthxOOYPIQOt6inu3RWxwLPciNqHLSM54XBvkA0m4JAmul9MVInWA8ufUaqFrlArf/
ABkl+Bv7Nx+pF/b/a5YeRJx5MUGFEF9NIJR740f7qkTnRo1NRedHI2cV36CW0Oxn/rTWkDlOU/G8
PuoEwaywJCpuIEpL7kzWrxsARQjlrtpQzkmePZd8s6AVb/uK0trUJVkKh+QBCaCo/rHxnbtrQxiH
rafxFu3d6b6mv8FDYnURaAHh4fiNHFV14/r5nQ==

Mais booon on a dit full online ! On sort alors cyberchef (https://gchq.github.io/CyberChef/#recipe=To_Base64(‘A-Za-z0-9%2B/%3D’)) et on met notre fichier en input.

Dernière étape : déchiffrer ce fichier pardi !
On peut alors utiliser le site 8gwifi.org (https://8gwifi.org/RSAFunctionality?keysize=4096) pour déchiffrer notre fichier. On sélectionne bien une clé de 4096 bits et la fonction “decrypt RSA Message”.

On entre alors notre clé privée en base64 et notre fichier en base64 dans les zones correspondantes et on obtient le flag ! Facile 🙂