Ceci est une ancienne révision du document !
Enoncé :
Solution :
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.
On commence par rechercher l'image originale en uploadant sur google image l'image (1 seul résultat) :
On utilise la commande compare d'imagemagick pour détecter les pixels différents :
compare ./lena.png ./lenaOriginal.png ./lenaDiff.png
Le résultat montre un motif régulier de différences :
(pixel rouge = pixel différent entre l'image de l'épreuve et l'image originale)
Le motif est le suivant :
petit script qui récupère les 4 bits de poids faible de chaque couleur :
#!/usr/bin/env python # encoding: utf-8 import os 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)
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 :
############ #@# # ## # # # ## ##### # ## ## ##### #### # # ## # # ### ## # # ## ### #$# ############
en découpant la chaine tous les 11 chars (premiere série de #), on vois une sorte de labyrinthe. on devine que le @ correspond au joueur et le $ à l'arrivée.
(j'ai remplacé les # par des blocks pour la lisibilité)
███████████ █ █@█ █ █ █ █ █ █ █ █ █████ █ █ █ █ █ █████ ███ █ █ █ █ █ █ █ ███ █ █ █ █ █ █ ███ █$█ █ ███████████
après avoir visualisé le chemin, on peut essayer de voir sous quel format entrer la réponse :
le 4e test ouvre un shell /bin/sh, c'est le flag