Cette page vous donne les différences entre la révision choisie et la version actuelle de la page.
hackingweek_2014:crypto:crypto3 [2014/03/03 02:10] ganapati créée |
hackingweek_2014:crypto:crypto3 [2017/04/09 15:33] (Version actuelle) |
||
---|---|---|---|
Ligne 1: | Ligne 1: | ||
**Enoncé :** | **Enoncé :** | ||
- | Alice a envoyé un message chiffré à Bob en utilisant le système de chiffrement RSA. Pour cela, elle a d'abord transformé son message clair, une chaîne de caractères, en un entier de la façon suivante. À chaque lettre minuscule de l'alphabet latin ont fait correspondre un nombre entier de 1 à 26 (a=1, b=2, ...,z=26). Au caractère espace on fait correspondre 0. | + | {{:hackingweek_2014:crypto:lena.png?200|}} |
- | Puis, à la chaîne de caractères m0 m1... ml-1 (avec 0 ≤ mi ≤ 26), on fait correspondre l'entier: m= ∑ i=0 l-1 m i 27 i | + | **Solution :** |
- | Une fois cet entier m obtenu, Alice utilise la clef publique (n,e) de Bob pour calculer c=me mod n. L'entier c envoyé par Alice est: | + | Après analyse rapide (hexdump, etc) pas de données cachées dans un padding ou autre. |
+ | L'image est un png, donc sans compression, de plus, lena.png est souvent utilisée comme exemple en stéganographie pour le lsb. | ||
- | c=97313723999427158707313571074505809044734576227366074775197337179596924131890323110047188776214753462110672927375882648122238543395136397500411230385539389860460250957019288356953382932530827442895828951533573302647648238521279077394005914829458808700551912957892108347414768602246507965856863930813172801853 | + | On commence par rechercher l'image originale en l'uploadant sur google image (1 seul résultat) : |
- | L'exposant e était e=216+1. Le modulus n était un produit de deux nombres premiers distincts de 512 bits. Ce nombre n est l'un des 100 nombres contenus dans le fichier moduli.txt. | + | {{:hackingweek_2014:crypto:lenaoriginal.png?200|}} |
- | Retrouvez le message en clair envoyé par Alice, puis prenez son md5sum et vous obtiendrez la clef de cette épreuve. | + | On utilise la commande compare d'imagemagick pour détecter les pixels différents : |
+ | compare ./lena.png ./lenaOriginal.png ./lenaDiff.png | ||
- | **Solution :** | + | Le résultat montre un motif régulier de différences : |
+ | |||
+ | {{:hackingweek_2014:crypto:lenadiff.png?200|}} | ||
+ | |||
+ | (pixel rouge = pixel différent entre l'image de l'épreuve et l'image originale) | ||
+ | |||
+ | Le motif est le suivant : | ||
+ | * valeur rouge | ||
+ | * 3px plus loin : valeur vert | ||
+ | * 3 px plus loin : valeur bleu | ||
+ | * 4 px de décallage | ||
+ | * etc | ||
+ | |||
+ | petit script qui récupère les 4 bits de poids faible de chaque couleur et les rassemble 2 par 2 : | ||
+ | |||
+ | <code Python> | ||
+ | #!/usr/bin/env python | ||
+ | # encoding: utf-8 | ||
+ | |||
+ | import Image | ||
+ | import argparse | ||
+ | |||
+ | def get_value(challenge): | ||
+ | picture = Image.open(challenge) | ||
+ | (width, height) = picture.size | ||
+ | challenge = picture.load() | ||
+ | |||
+ | # Flatten 2d array (easier to parse after) | ||
+ | flatten_array = [] | ||
+ | for y in range(0,height): | ||
+ | for x in range(0, width): | ||
+ | flatten_array.append(challenge[x,y]) | ||
+ | |||
+ | response = "" | ||
+ | color_index = 0 | ||
+ | pixel_counter = 0 | ||
+ | index = 0 | ||
+ | byte = "" | ||
+ | while index < len(flatten_array): | ||
+ | |||
+ | binary_color = bin(flatten_array[index][color_index]) | ||
+ | r = "%s" % binary_color | ||
+ | r = r[2:] | ||
+ | while len(r) < 8: | ||
+ | r = "0" + r | ||
+ | if byte == "": | ||
+ | byte = r[4:] | ||
+ | else: | ||
+ | byte = r[4:] + byte | ||
+ | response = response + byte | ||
+ | byte = "" | ||
+ | |||
+ | |||
+ | # Switch color to check | ||
+ | color_index = color_index + 1 | ||
+ | if color_index > 2: | ||
+ | color_index = 0 | ||
+ | |||
+ | # Change pixel to check | ||
+ | index = index + 3 | ||
+ | pixel_counter = pixel_counter + 1 | ||
+ | if pixel_counter > 2: | ||
+ | pixel_counter = 0 | ||
+ | index = index + 1 | ||
+ | |||
+ | s = response | ||
+ | print ''.join([chr(int(s[8*i:8*i+8], 2)) for i in range(len(s) / 8)]) | ||
+ | |||
+ | if __name__ == '__main__': | ||
+ | parser = argparse.ArgumentParser(description='Simple steg tool)') | ||
+ | parser.add_argument("-c", action="store", dest="challenge", help="input file", required=True) | ||
+ | command = parser.parse_args() | ||
+ | |||
+ | get_value(command.challenge) | ||
+ | </code> | ||
+ | |||
+ | ganapati@goa:~/tools/stegano$ ./sploit.py -c lena.png > output | ||
+ | ganapati@goa:~/tools/stegano$ file ./output | ||
+ | ./output: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), for GNU/Linux 2.6.32, dynamically linked (uses shared libs), stripped | ||
+ | |||
+ | Bingo, le fichier est reconnu comme un executable ELF | ||
+ | |||
+ | ganapati@goa:~/tools/stegano$ chmod +x ./output | ||
+ | ganapati@goa:~/tools/stegano$ ./output | ||
+ | Enter input: | ||
+ | foobar | ||
+ | Wrong input | ||
+ | |||
+ | Il faut reverse l'ELF pour savoir quel est l'entrée attendue. | ||
+ | |||
+ | On remarque dans la string suivante dans le bin : | ||
+ | ############ #@# # ## # # # ## ##### # ## ## ##### #### # # ## # # ### ## # # ## ### #$# ############ | ||
+ | |||
+ | Le binaire place un curseur au niveau du '@', et la victoire est assurée si le curseur atteint le '$'. L'entrée passée permet de se déplacer dans la chaine. Selon le caractère rencontré, le curseur est déplacé d'un offset particulier : | ||
+ | * caractère 'n' : offset -12 | ||
+ | * caractère 's' : offset +12 | ||
+ | * caractère 'e' : offset +1 | ||
+ | * caractère 'w' : offset -1 | ||
+ | |||
+ | Tout autre caractère fait sortir du programme. De même, on ne continue que si le curseur se trouve sur un ' ', un '#' renvoyant à la fin du programme. | ||
+ | |||
+ | On devine alors (d'après les nsew => North / South / East / West, et les offsets de déplacement) que l'on est en présence d'un labyrinthe de 11x11 cases. | ||
+ | |||
+ | (j'ai remplacé les # par des blocks pour la lisibilité) | ||
+ | |||
+ | ███████████ | ||
+ | █ █@█ █ █ | ||
+ | █ █ █ █ █ | ||
+ | █ █████ █ █ | ||
+ | █ █ | ||
+ | █ █████ ███ | ||
+ | █ █ █ █ | ||
+ | █ █ █ ███ █ | ||
+ | █ █ █ █ | ||
+ | █ ███ █$█ █ | ||
+ | ███████████ | ||
+ | |||
+ | après avoir visualisé le chemin, on peut entrer la réponse : | ||
+ | <code> | ||
+ | seeneessswwwwwwsssseenneessees | ||
+ | </code> |