Bonjour à tous !

Je présente dans cet article le challenge SSTIC 2016 ainsi que la méthodologie que j’ai employé pour résoudre les épreuves qui m’ont permis de passer les diffèrents niveaux.

Cette année, le challenge ést organisé sous la forme de 3 niveaux de jeu. Chaque niveau contient plusieurs épreuves, chaque épreuve donne 1 clé, et il faut 2 clés pour valider le niveau et passer au suivant. Certaines épreuves étant plus dures que les autres du même niveau, leur clé en valent 2. Génial, ça ira plus vite ! (ou pas)

Voici un récapitulatif des différentes épreuves:
  • Niveau 1:

    • (1) calc.zip: CrackMe sous la forme d’un programme d’une calculatrice TI-83

    • (1) SOS-Fant0me.zip: Capture réseau du RAT Gh0st

    • (2) radio.zip: C’est 2 barbus qui rentrent dans un bar. L’un dit à l’autre: "Hey! Tu sais c’est quoi la diffèrence entre la radio et la peste ?"

  • Niveau 2:

    • (1) foo.zip: CrackMe DLL32 EFI

    • (1) huge.zip: CrackME ELF64

    • (1) loader.zip

  • Niveau 3:

    • (1) screensaver

    • (1) FeSes.zip

    • (2) strange.zip: CrackME en IA-64 bits faisant de l’OCR à partir d’un réseau neuronal multi-couches

    • (2) ring3

Contexte

On commence avec un PCAP récupéré sur http://static.sstic.org/challenge2016/challenge.pcap.

yfrancou@panda$ ll challenge.pcap
    53448495  challenge.pcap
yfrancou@panda:$ file challenge.pcap
    challenge.pcap: tcpdump capture file (little-endian) - version 2.4 (Ethernet, capture length 32767)

On l’ouvre avec WireShark, on extrait les fichiers (File > Export Objects > HTTP). Un fichier challenge.zip sauvage apparaît.

yfrancou@panda$ ll challenge.zip
    52331069  challenge.zip

Une fois dézippé, on voit que le challenge est sous la forme d’une plateforme 2D développée avec rpgjs. On le lance donc dans notre navigateur préféré.

L’aventure commence dans une auberge. On va parler à la tenancière blonde de l'établissement qui nous indique les règles du challenge.

"Salut voyageur ! Pour arriver au bout de challenge, il te faudra résoudre des épreuves. Tu auras le choix entre plusieurs épreuves à chaque niveau, donc choisis bien celles que tu préfères. Il suffit d’atteindre le nombre de points requis pour passer au niveau suivant. Chaque épreuve te fournira une clé de 16 octets, qu’il faudra donner au garde du niveau sous forme héxadécimale pour la faire prendre en compte. Si tu lui donnes suffisamment de clés, le garde te laissera passer. Tu rencontreras peut-être d’autres personnages bizarres en cours de route (toute ressemblance avec des personnes existantes serait purement fortuite). Ne t’y attarde pas trop, sauf si tu aimes troller. Bonne chance !"

start01

Niveau 1

calc.zip

"Quand j'étais encore jeune, j’ai caché ma clé dans un instrument que j’ai ramené du Texas. Malheureusement, j’ai oublié comment la récupérer depuis…"

On commence par dézipper le fichier et on y trouve un fichier SSTIC16.8xp. Un file nous indique qu’il s’agit d’un programme fait pour une calculatrice Texas Instrument TI-83+:

file SSTIC16.8xp
  SSTIC16.8xp: TI-83+ Graphing Calculator (program)

"Cool ça à l’air marrant, mais j’ai pas de TI-83 sous la main moi .. Remarque, même si j’en avais une .. "

Bon. Google, premier lien. On tombe sur le site cemetech qui émule des TI-83+ pour peu qu’on lui fournisse la bonne ROM. Donc on lui donne le fichier SSTIC16.8xp à manger, on appuie sur la touche "PRGM" pour voir les programmes chargés et on lance le programme SSTIC.

N1 calc start

On a un émulateur qui fonctionne, mais ça serait bien de pouvoir regarder le code aussi. Tiens ça tombe bien, il y a un compilateur / décompilateur pour TI-83+ sur le même site.

Le code source étant chiant à lire et n’apportant pas grand chose, voici l'équivalent en python:

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

keys = [
    0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3, 0x0EDB8832,
    0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, 0x1DB71064, 0x6AB020F2,
    0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, 0x136C9856, 0x646BA8C0, 0xFD62F97A,
    0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172,
    0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3,
    0x45DF5C75, 0xDCD60DCF, 0xABD13D59, 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423,
    0xCFBA9599, 0xB8BDA50F, 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB,
    0xB6662D3D, 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
    0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01, 0x6B6B51F4,
    0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, 0x65B0D9C6, 0x12B7E950,
    0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, 0x4DB26158, 0x3AB551CE, 0xA3BC0074,
    0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0,
    0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525,
    0x206F85B3, 0xB966D409, 0xCE61E49F, 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81,
    0xB7BD5C3B, 0xC0BA6CAD, 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615,
    0x73DC1683, 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
    0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7, 0xFED41B76,
    0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, 0xD6D6A3E8, 0xA1D1937E,
    0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6,
    0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236,
    0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7,
    0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F,
    0x72076785, 0x05005713, 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7,
    0x0BDBDF21, 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
    0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, 0xA00AE278,
    0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, 0xAED16A4A, 0xD9D65ADC,
    0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, 0xBDBDF21C, 0xCABAC28A, 0x53B39330,
    0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF, 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94,
    0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D
]

user_input = 0x05571C16  # Le password passé en INPUT à la calculatrice
a = 0xFFFFFFFF

for i in range(4):
    input_i = ((user_input >> (i * 8)) & 0xFF)
    key_index = input_i ^ (a & 0xFF)
    key = keys[key_index]
    a = (a >> 8) ^ key


if a ^ 0xFFFFFFFF == 0xC49AB257:
    print "GAGNE!"
else:
    print "PERDU"

Comme on veut aller vite et qu’on préfère quand c’est dégueu, on résoud ce problème à la main.

[1]
A = 0xFFFFFFFF
KEY_INDEX = (INPUT[3] ^ A[3]) = (0x?? ^ 0xFF) = 0x??
A = ((A >> 8) ^ KEYS[KEY_INDEX]) = (0x00FFFFFF ^ 0x????????) = 0x????????

[2]
A = 0x????????
KEY_INDEX = (INPUT[2] ^ A[3]) = (0x?? ^ 0x??) = 0x??
A = ((A >> 8) ^ KEYS[KEY_INDEX]) = (0x00?????? ^ 0x????????) = 0x????????

[3]
A = 0x????????
KEY_INDEX = (INPUT[1] ^ A[3]) = (0x?? ^ 0x??) = 0x??
A = ((A >> 8) ^ KEYS[KEY_INDEX]) = (0x00?????? ^ 0x????????) = 0x????????

[4]
A = 0x????????
KEY_INDEX = (INPUT[0] ^ A[3]) = (0x?? ^ 0x??) = 0x??
A = ((A >> 8) ^ KEYS[KEY_INDEX]) = (0x00?????? ^ 0x????????) = 0x3B654DA8

Il faut que A soit égal à 0x3B654DA8 (0x0xC49AB257 ^ 0xFFFFFFFF) à la fin. Donc on part de la fin, et on remonte.

Pour que A soit égal à 0x3B654DA8, il faut que la clé soit de la forme 0x3B??????. La seule clé qui match dans la liste est la clé 0x3B6E20C8 en position 0x20. On peut maintenant calculer (A>>8) qui fait 0x000b6d60. Ca nous donne:

[1]
A = 0xFFFFFFFF
KEY_INDEX = (INPUT[3] ^ A[3]) = (0x?? ^ 0xFF) = 0x??
A = ((A >> 8) ^ KEYS[KEY_INDEX]) = (0x00FFFFFF ^ 0x????????) = 0x????????

[2]
A = 0x????????
KEY_INDEX = (INPUT[2] ^ A[3]) = (0x?? ^ 0x??) = 0x??
A = ((A >> 8) ^ KEYS[KEY_INDEX]) = (0x00?????? ^ 0x????????) = 0x????????

[3]
A = 0x????????
KEY_INDEX = (INPUT[1] ^ A[3]) = (0x?? ^ 0x??) = 0x??
A = ((A >> 8) ^ KEYS[KEY_INDEX]) = (0x00?????? ^ 0x????????) = 0x0B6D60??

[4]
A = 0x0B6D60??
KEY_INDEX = (INPUT[0] ^ A[3]) = (0x?? ^ 0x??) = 0x20
A = ((A >> 8) ^ KEYS[KEY_INDEX]) = (0x000B6D60 ^ 0x3B6E20C8) = 0x3B654DA8

A ce niveau, on ne connait pas la valeur de INPUT[0] ni celle de A[3], mais c’est pas grave. On continue de remonter. On sait maintenant que le A du 3ème tour de boucle doit être égale à 0x0B6D60??. Ce qui fait que la clé doit avoir la forme 0x0B??????. La seule qui match est 0x0BDBDF21.

Bon vous voyez le truc, on remonte jusqu’en haut comme ça. Ce qui nous donne:

[1]
A = 0xFFFFFFFF
KEY_INDEX = (INPUT[3] ^ A[3]) = (0x?? ^ 0xFF) = 0xE9
A = ((A >> 8) ^ KEYS[KEY_INDEX]) = (0x00FFFFFF ^ 0xD9D65ADC = 0xD9??????

[2]
A = 0xD9??????
KEY_INDEX = (INPUT[2] ^ A[3]) = (0x?? ^ 0x??) = 0x3F
A = ((A >> 8) ^ KEYS[KEY_INDEX]) = (0x00D9???? ^ 0xB6662D3D = 0xB6BF????

[3]
A = 0xB6BF????
KEY_INDEX = (INPUT[1] ^ A[3]) = (0x?? ^ 0x??) = 0xCF
A = ((A >> 8) ^ KEYS[KEY_INDEX]) = (0x00B6BF?? ^ 0x0BDBDF21 = 0x0B6D60??

[4]
A = 0x0B6D60??
KEY_INDEX = (INPUT[0] ^ A[3]) = (0x?? ^ 0x??) = 0x20
A = ((A >> 8) ^ KEYS[KEY_INDEX]) = (0x000B6D60 ^ 0x3B6E20C8) = 0x3B654DA8

Une fois arrivé tout en haut, on connaît le A de départ, soit 0xFFFFFFFF. Donc A[3] = 0xFF. Ce qui fait que INPUT[3] = 0xE9 XOR 0xFF = 0x16. On calcule la valeur de A (0x00FFFFFF XOR 0xD9D65ADC) qui est du coup égale à 0xD929A523. Et on redescend tout en bas.

[1]
A = 0xFFFFFFFF
KEY_INDEX = (INPUT[3] ^ A[3]) = (0x16 ^ 0xFF) = 0xE9
A = ((A >> 8) ^ KEYS[KEY_INDEX]) = (0x00FFFFFF ^ 0xD9D65ADC = 0xD929A523

[2]
A = 0xD929A523
KEY_INDEX = (INPUT[2] ^ A[3]) = (0x1C ^ 0x23) = 0x3F
A = ((A >> 8) ^ KEYS[KEY_INDEX]) = (0x00D929A5 ^ 0xB6662D3D = 0xB6BF0498

[3]
A = 0xB6BF0498
KEY_INDEX = (INPUT[1] ^ A[3]) = (0x57 ^ 0x98) = 0xCF
A = ((A >> 8) ^ KEYS[KEY_INDEX]) = (0x00B6BF?? ^ 0x0BDBDF21 = 0x0B6D6025

[4]
A = 0x0B6D6025
KEY_INDEX = (INPUT[0] ^ A[3]) = (0x05 ^ 0x25) = 0x20
A = ((A >> 8) ^ KEYS[KEY_INDEX]) = (0x000B6D60 ^ 0x3B6E20C8) = 0x3B654DA8

Et voilà, on a l’INPUT qu’il faut rentrer dans la calculatrice: 0x05571C16.

N1 calc key
Note
Il s’agissait bien évidemment d’un CRC32, mais c'était plus classe de le résoudre à la main que de faire un bruteforcer. Les bruteforcers, c’est pour les n00bs.

SOS-Fant0me.zip

"On suspecte une machine d'être hantée par un fantôme mais cette fois ce n’est pas Casper. Tiens, voici une capture du champ électromagnétique… en gros une capture réseau? Tu pourras peut-être en tirer quelque chose !"

On dézippe le fichier et on trouve un fichier SOS-Fant0me.pcap de 232ko. En l’ouvrant avec WireShark, on s’aperçoit qu’il s’agit d’une capture réseau de la communication entre un RAT Gh0st et son C&C.

N1 ghost start

"Rhooo les cons ! C’est cadeau :D" se dit-on en se frottant les mains. On lance le tool qu’on a en interne chez Airbus qui nous ressort toutes les infos et on passe au challenge suivant. On lance ChopShop, qui a justement un module pour déchiffrer les communications de Gh0st.

Allez, la commande pour le fun:

  chopshop -f ./SOS-Fant0me.pcap -M modules/ -E ext_libs/ "gh0st_decode" -s CARVED

Le module nous extrait aussi les fichiers échangés.

  2759  C__Users_sstic_Documents_Challenge SSTIC 2016_how_to_rule_the_world.txt
   234  C__Users_sstic_Documents_Challenge SSTIC 2016_Stage 1_sstic2016-stage1-solution.zip
193968  C__Users_sstic_Documents_Challenge SSTIC 2016_visio_stage2.mp4

Le fichier C__Users_sstic_Documents_Challenge SSTIC 2016_Stage 1_sstic2016-stage1-solution.zip est chiffré. On retrouve le mot de passe dans les communications (paquets de type Keylogger) qui est: Cyb3rSSTIC_2016.

Le zip contient la clé du challenge qui est: 368B E8C1 CC7C C70C 2245 0309 3430 1C15

Niveau 2

huge.zip

"C’est vraiment très indigeste ce challenge…"

Ce challenge commence avec un ZIP contenant un TAR.

yfrancou@panda$ unzip huge.zip
    Archive:  huge.zip
        inflating: huge.tar
yfrancou@panda$ tar xvf huge.tar
    Huge
    tar: Huge: Cannot seek to 25297854992384: Invalid argument
    tar: Exiting with failure status due to previous errors

Erreur sur l’extraction du TAR quand il veut se positionner en +25To. C’est sûrement dû à mon FS en ext4 qui est limité à des fichiers de 16To, mais j’ai un peu la flemme de l’ouvrir sur un autre FS.

On regarde rapidement le fichier Huge généré:

yfrancou@panda$ ll Huge
    11168083824640  Huge
yfrancou@panda$ file Huge
    Huge: ELF 64-bit LSB  executable, x86-64, version 1 (SYSV), statically linked, corrupted section header size

On a un fichier ELF 64bits de 11To corrompu. Cool.

Le fichier huge.tar contient des sparses. Pour résumé, si un fichier de 100To contient 99.9To de zéros, ca sert à rien de les copier sur le disque. C’est là qu’interviennent les sparses en décrivant où sont les gros blocs de zéros.

En extrayant les sparses headers, on voit que le fichier original fait pas loin de 130To.

24 size=128574140715008
30 ctime=1456948527.914039536
30 atime=1456948548.569742108
22 GNU.sparse.major=1
22 GNU.sparse.minor=0
24 GNU.sparse.name=Huge
39 GNU.sparse.realsize=128574140715008

Bon. Toujours pas envie de l’extraire correctement sur un autre FS ? Bof .. Le fichier entier pourrait nous permettre de le debugger avec gdb, mais … les analyses dynamiques c’est pour les noobs. #TeamAnalyseStatique

Un coup de hexedit sur le huge.tar nous montre qu’il semble y avoir des bouts de code valides. "Un bon point pour moi et ma flemme".

On ouvre huge.tar en RAW dans IDA. Ce qui veut dire qu’on connaît juste les offsets des instructions mais qu’on a aucune idée des adresses virtuelles. Pratique pour tous les sauts.

N2 huge main
"Bah c'est easy ce challenge, il y a les trucs bleus à côté qui disent ce que font les fonctions !"
"Ahah ahah .. PAN !"

Bon, ça résout pas notre problème d’adresses virtuelles ça, mais cette fonction ressemble au point d’entrée.

Un coup de readelf sur le fichier Huge nous donne les infos suivantes:

yfrancou@panda$ readelf -a Huge
ELF Header:
  Magic:   7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00
  Class:                             ELF64
  Data:                              2's complement, little endian
  Version:                           1 (current)
  OS/ABI:                            UNIX - System V
  ABI Version:                       0
  Type:                              EXEC (Executable file)
  Machine:                           Advanced Micro Devices X86-64
  Version:                           0x1
  Entry point address:               0x51466a42e705
  Start of program headers:          64 (bytes into file)
  Start of section headers:          0 (bytes into file)
  Flags:                             0x0
  Size of this header:               64 (bytes)
  Size of program headers:           56 (bytes)
  Number of program headers:         3
  Size of section headers:           0 (bytes)
  Number of section headers:         0
  Section header string table index: 0

L’entry point se situe à l’adresse virtuelle 0x51466a42e705, et il s’agit probablement de celle de la fonction précédente.

Maintenant, on va s’aider des sparses pour identifier les adresses virtuelles de toutes les autres fonctions. Ce qui nous donne le joli schéma suivant:

                       Adresse Virtuelle    Function                       Parties checkées
                                                                 00010203 04050607 08090A0B 0C0D0E0F
            |----------> 0x06F4B0E0000C   <check_6>            [........ ........ ......8C ........]
            |                         .   <check_6>            [........ ........ ......8C ........]
            |                         .   <check_6>            [........ ........ ......8C ........]
         |--|----------- 0x06F4B0E0F370   <check_6>            [........ ........ ......8C ........]
         |  |            0x06F4B0E0F38F   <jmp_exit_13000>
         |  |                         .   <jmp_exit_13000>
         |  |                         .   <jmp_exit_13000>
         |  |            0x099A38050000   <jmp_exit_13000>
         |  |     |----> 0x099A3805000C   <chall_end>          [........ ........ ........ ........]
         |  |     |                   .   <chall_end>          [........ ........ ........ ........]
         |  |     |                   .   <chall_end>          [........ ........ ........ ........]
         |  |     |      0x099A380575A6   <chall_end>  EXIT    [........ ........ ........ ........]
         |  |     |  |-> 0x10F338CF000C   <decode_hex_min>     [........ ........ ........ ........]
         |  |     |  |                .   <decode_hex_min>     [........ ........ ........ ........]
         |  |     |  |                .   <decode_hex_min>     [........ ........ ........ ........]
         |  |     |  |   0x10F338CF7548   <decode_hex_min> RET [........ ........ ........ ........]
|--------|--|-----|--|-> 0x2A7EE24A000C   <check_7>            [........ D4D68C99 ........ ........]
|        |  |     |  |                .   <check_7>            [........ D4D68C99 ........ ........]
|        |  |     |  |                .   <check_7>            [........ D4D68C99 ........ ........]
|        |  |     |--|-- 0x2A7EE24AAE24   <check_7>            [........ D4D68C99 ........ ........]
|        |  |        |   0x2A7EE24AAE7E   <jmp_exit_1000>
|        |  |        |                .   <jmp_exit_1000>
|        |  |        |                .   <jmp_exit_1000>
|        |  |        |   0x2C7AFFEF0000   <jmp_exit_1000>
|        |  |        |   0x2C7AFFEF000C   <sub_22AC>           [........ ........ ........ ........]
|        |  |        |                .   <sub_22AC>           [........ ........ ........ ........]
|        |  |        |                .   <sub_22AC>           [........ ........ ........ ........]
|        |  |        |   0x2C7AFFEF62AC   <sub_22AC> RET       [........ ........ ........ ........]
|        |  |        |   0x2C7AFFEF630A   <jmp_exit_3000>
|        |  |        |                .   <jmp_exit_3000>
|        |  |        |                .   <jmp_exit_3000>
|        |  |        |   0x42021DA90000   <jmp_exit_3000>
|     |--|--|--------|-> 0x352845AB000C   <check1>             [........ ........ ........ 89341BEC]
|     |  |  |        |                .   <check1>             [........ ........ ........ 89341BEC]
|     |  |  |        |                .   <check1>             [........ ........ ........ 89341BEC]
|  |--|--|--|--------|-- 0x352845AB3BCE   <check1>             [........ ........ ........ 89341BEC]
|  |  |  |  |        |   0x352845AB3BF9   <jmp_exit_5000>
|  |  |  |  |        |                .   <jmp_exit_5000>
|  |  |  |  |        |                .   <jmp_exit_5000>
|  |  |  |  |        |   0x42021DA90000   <jmp_exit_5000>
|  |  |  |  |        |   0x42021DA9000C   <exit>               [........ ........ ........ ........]
|  |  |  |  |        |                .   <exit>               [........ ........ ........ ........]
|  |  |  |  |        |                .   <exit>               [........ ........ ........ ........]
|  |  |  |  |        |   0x43ABDB4A0000   <exit>               [........ ........ ........ ........]
|  |  |  |  |     |--|-> 0x43ABDB4A000C   <check2>             [29...... ........ ........ ........]
|  |  |  |  |     |  |                .   <check2>             [29...... ........ ........ ........]
|  |  |  |  |     |  |                .   <check2>             [29...... ........ ........ ........]
|  |  |  |  |  |--|--|-  0x43ABDB4A0AEE   <check2>             [29...... ........ ........ ........]
|  |  |  |  |  |  |  |   0x43ABDB4A0B0B   <jmp_exit_8000>
|  |  |  |  |  |  |  |                .   <jmp_exit_8000>
|  |  |  |  |  |  |  |                .   <jmp_exit_8000>
|  |  |  |  |  |  |  |   0x49E7E5410000   <jmp_exit_8000>
|  |  |  |--|--|--|--|-> 0x49E7E541000C   <check_3_1>          [..89.... ........ ........ ........]
|  |  |     |  |  |  |                .   <check_3_1>          [..89.... ........ ........ ........]
|  |  |     |  |  |  |                .   <check_3_1>          [..89.... ........ ........ ........]
|  |  |     |  |  |  |   0x49E7E541BE18   <check_3_1>          [..89.... ........ ........ ........]
|  |  |     |  |  |  |                .   <0jmp_check3_0000>
|  |  |     |  |  |  |   0x49E7E541BE38   <check_3_2>          [..89.... ........ ........ ........]
|  |  |     |  |  |  |                .   <check_3_2>          [..89.... ........ ........ ........]
|  |  |     |  |  |  |                .   <check_3_2>          [..89.... ........ ........ ........]
|  |  |-----|--|--|--|-- 0x49E7E541C038   <check_3_2>          [..89.... ........ ........ ........]
|  |        |  |  |  |   0x49E7E541C056   <jmp_exit_B000>
|  |        |  |  |  |                .   <jmp_exit_B000>
|  |        |  |  |  |                .   <jmp_exit_B000>
|  |        |  |  |  |   0x4A1706820000   <jmp_exit_B000>
|  |        |  |--|--|-> 0x4A170682000C   <check_4>            [....7ED1 ........ ........ ........]
|  |        |     |  |                .   <check_4>            [....7ED1 ........ ........ ........]
|  |        |     |  |                .   <check_4>            [....7ED1 ........ ........ ........]
|  |        |-----|--|-- 0x4A170682EDE0   <check_4>            [....7ED1 ........ ........ ........]
|  |              |  |   0x4A170682EE02   <jmp_exit_0D6F9>
|  |              |  |                .   <jmp_exit_0D6F9>
|  |              |  |                .   <jmp_exit_0D6F9>
|  |              |  |   0x51466A42E6F9   <jmp_exit_0D6F9>
|  |              |--|-- 0x51466A42E705   <main> (ENTRY POINT) [........ ........ ........ ........]
|  |-------------------> 0x59CB440C000C   <check_5>            [........ ........ D54EC08C ........]
|                                     .   <check_5>            [........ ........ D54EC08C ........]
|                                     .   <check_5>            [........ ........ D54EC08C ........]
|----------------------- 0x59CB440C4524   <check_5>            [........ ........ D54EC08C ........]
                         0x59CB440C4556   <jmp_exit_11000>
                                      .   <jmp_exit_11000>
                                      .   <jmp_exit_11000>
                         0x06F4B0E00000   <jmp_exit_11000>

                                                 USER INPUT    [29897ED1 D4D68C99 D54EC08C 89341BEC]
                                                   XOR KEY     [CCFDCBC5 B2A9E62B 0D7E8737 0E2E4F19]
                                                                -------- -------- -------- --------
                                                  FINAL KEY    [E574B514 667F6AB2 D83047BB 871A54F5]

Pour résumer, le programme récupère une clé de 16 octets en entrée. Il la met en minuscule et la convertit en hexadécimal.

Il va ensuite appeler plusieurs fonctions qui vont checker différentes parties de la clé de plusieurs manières.

Check1: check_2()

N2 huge check2

Cette fonction check si le premier octet de la clé est bien 0x29. Si oui, elle passe à check_4(), sinon elle exit.

Check2: check_4()

N2 huge check4

Cette fonction check si le 2ème et le 3ème octet de la clé sont bien 0x7E et 0xD1.

Check3: check_3()

N2 huge check3

Cette fonction initialise à 0 un octet X quelque part après la clé en mémoire. Ce octet est pointé par RAX.

Ensuite, le 2ème octet de la clé est utilisé comme index pour faire un saut en 0x9E38 + 2 * INDEX. Entre les fonctions check_3_1 et check_3_2 se situe un bloc de 0x200 zéros. Sauter dans des zéros.. WTF ? Elle est où l’erreur ?

Non, pas d’erreur, l’instruction 0000 existe bien et correspond à un ADD BYTE PTR [rax], al. C’est l’octet X qui est affecté.

La fonction check_3_2 check si l’octet X est égal à 0x65. La question est donc de savoir à combien d’instructions avant check_3_2 il faut sauter pour que X = 0x65.

AL étant initialisé à 3, chaque instruction ajoute 3 à X. Regardons:

    X = 0x0065  =>  Pas divisible pas 3
    X = 0x0165  =>  0x165 / 3.0 = 0x77     => 0x200 - 0x77 * 2 = 0x112
                                              0x112 / 2.0 = 0x89

Il faut donc sauter en 0x89 * 2 pour que X = 0x65. C’est notre clé.

Check4: check_1()

N2 huge check1

RBX vaut 0x352845AB4BD5, l’adresse virtuelle de loc_4BD5.

La fonction check si le 4ème DWORD de la clé est bien égal à 0xA9B00F5C une fois xoré avec 0x45AB4BD5.

Il doit donc être égal à 0xEC1B3489, soit "89341BEC".

Check5: check_5()

N2 huge check5

Encore un xor. La valeur attendue est 0x8CC04ED5, soit "D54EC08C".

Check6: check_7()