• STATISTIQUES
  • Il y a eu un total de 3 membres et 12196 visiteurs sur le site dans les dernières 24h pour un total de 12 199 personnes!


    2 membres se sont inscrits dans les dernières 24h!


    Membres: 2 447
    Discussions: 3 590
    Messages: 32 838
    Tutoriels: 77
    Téléchargements: 38
    Sites dans l'annuaire: 58


  • ANNUAIRE
  • [EN] HackQuest
    Logic: 12, JavaScript: 14, Applet: 6, CrackIt: 13, Crypto: 11, Internet: 3, Exploit: 7, Stegano: 12, Flash: 1, Programmi...
    Challenges
    [EN] Sabre Films
    Site de challenge présenté sous la forme d'une quête. Vous êtes un détective et devrez résoudre d...
    Challenges
    [EN] CS Tutoring Center
    Site de challenge spécialisé dans les challenges de programmation C++ et java cependant, d'autres langages pe...
    Challenges
    [EN] Exploit-db
    Une base de données d'exploits triés par genre (GHDB, Remote, Local, Web, DOS, ShellCode) à ...
    Vulnérabilités
    [EN] Reddit
    Subreddit dédié à la sécurité informatique.
    Hacking
    [EN] w3challs
    Ce site propose différents types de défis informatiques: piratage, craquage, cryptographie, stég...
    Hacking
    [EN] osix
    Site de challenge qui utilise un système de level on chaque épreuve doit être réussie avant d'accédÃ...
    Challenges

  • DONATION
  • Si vous avez trouvé ce site internet utile, nous vous invitons à nous faire un don du montant de votre choix via Paypal. Ce don servira à financer notre hébergement.

    MERCI!

    €



Note de ce sujet :
  • Moyenne : 0 (0 vote(s))
  • 1
  • 2
  • 3
  • 4
  • 5
[Python] La stéganographie BMP
02-07-2013, 13h00 (Modification du message : 02-07-2013, 13h06 par Kiwazaru.)
Message : #1
Kiwazaru Hors ligne
Padawan d'un super escargot
*



Messages : 284
Sujets : 26
Points: 139
Inscription : Mar 2012
[Python] La stéganographie BMP
Yop tout le monde !
Alors voilà, il y a quelques temps j'ai commencé à apprendre le python.
Langage qui pour moi et pour pas mal d'autre est un langage qui nous permet d'écrire des programmes très rapidement en CTF par exemple !
Après une semaine de RTFM et d'apprentissage des bases, j'ai décidé de me lancer dans un projet qui à la base.. ne devait pas en être un Big Grin

La stéganographie BMP Smile
J'avais voulu en faire une épreuve, mais après un fail total de celle-ci (seul Luxerails l'a pown x)), je décide de poster le code commenté.

Le code parle de lui même ! (J'ai essayé de le commenter le plus possible !)

Code PYTHON :

#!/usr/bin/python2.7
# -*- coding: utf-8 -*-
"""
        Usage: {} <options>".format(sys.argv[0]))
        Options:
        -p <picture_container> <file_to_hide> <eof> <xorkey> <output> (Pour coder l'image)
        -u <encoded_picture> <eof> <xorkey> <output> (Pour decoder l'image)
        -ns <port> <eof> <xorkey> <inc> <dec> (Pour lancer le serveur)
        -nc <ip> <port> <picture> <eof> <xorkey> <inc> <dec> (Pour lancer le client)
        --help (to get help)"""

       
"""
Le principe de la stéganographie , globalement est de cacher une donnée , une information dans une autre donnée lambda..
Nous allons voir dans ce code, la stéganographie BMP (Il est aussi possible de le faire pour le PNG, mais ce code n'est pas compatible).
Le but de la steganographie de ce format d'image, est de coder l'image à cacher, dans l'image que nous appellerons contenante.
Pour une image BMP par exemple, son codage est le suivant: R V B Padding (Octet R, Octet V, Octet B, Octet de padding).
Un octet est codé sur 8 bits. Dans ces 8 bits, nous avons un bit de poid fort (MSB) et un bit de poid faible (LSB). Vous vous en douterez,
le LSB aura beaucoup moins d'impact sur la couleur si nous le mondifions, que le MSB !
Le principe de cette stéganographie est donc tout simplement, de coder 8 bits d'un octet de l'image à cacher, sur les LSB de 8 octets de l'image contenante !
Petite dédicace à khaled, on va dire que ce code est sous licence WTFPL hein <img src="https://n-pn.fr/forum/images/smilies/biggrin.png" alt="Big Grin" title="Big Grin" class="smilie smilie_4" />
"""


import sys, struct, socket


def header(original_picture):

    if original_picture[0:2] != 'BM':
        print "The picture is not a bitmap !"
        sys.exit("System Exit with Error: Bad file !")
   
    # Liste les informations principales du fichier.
    print "- Name of file: " + str(sys.argv[2])
    print "- Type of file: " + original_picture[0:2] + " ( 2 bytes )"
    print "- Size of file: " + str(struct.unpack("<I", original_picture[2:6])[0] / 1000) + " kB (" + str(struct.unpack("<I", original_picture[2:6])[0]) + " bytes)  ( 4 bytes ) "
    print "- Width: " + str(struct.unpack("<I",original_picture[18:22])[0]) + " px ( 4 bytes )"
    print "- Heigth: " + str(struct.unpack("<I", original_picture[22:26])[0]) + " px ( 4 bytes )"
    print "- Compression: " + str(struct.unpack("<I", original_picture[30:34])[0]) + " ( 4 bytes )"
    print "- Horizontal Resolution: " + str(struct.unpack("<I", original_picture[38:42])[0]) + " ( 4 bytes )"
    print "- Vertical Resolution: " + str(struct.unpack("<I", original_picture[42:46])[0]) + " ( 4 bytes )"

def encode(original_picture, hidden_picture, eof_file, xor):
    """ ENCODE THE PICTURE """
   
    # Converti la chaîne en liste.
    hidden_picture = list(hidden_picture)
    original_picture = list(original_picture)
   
    # Padding pour avoir une taille de fichier BMP qui convient.
    hidden_picture += eof_file
    if len(hidden_picture) % 4 != 0:
        hidden_picture += 'F' *  (4 -(len(hidden_picture) % 4)) # On ajoute x* l'octet "F".
   

    # On vérifie la taille des images (*8 car nous allons coder un octet de l'image à cacher sur 8 octets de l'image contenante)
    if len(original_picture) < len(hidden_picture) * 8:
        print "The original picture is too short !"
        sys.exit("Picture too short !")

    # Les variables.. <img src="https://n-pn.fr/forum/images/smilies/smile.png" alt="Smile" title="Smile" class="smilie smilie_1" />
    i = 0 # Offset courant de l'image à cacher
    y = 0 # Offset courant de l'image contenante
    buf = ''.join(hidden_picture)
    hide = ""
    while i < len(buf):
        hide += struct.pack("I", (struct.unpack("I", buf[i:i+4])[0] ^ xor)) # On XOR notre image à cacher.
        i += 4
    hide = list(hide) # On fou notre hide qui contient notre image xoré
    i = 0
    while i < len(hidden_picture):
        key = 0x01 # La clé commence à 0x01 et on applique une opération SHL << 1 pour obtenir les valeurs croissantes -> 0x01 0x02 0x04 0x08 0x10 0x20 0x40 0x80 pour obtenir les bits 1 par 1
        for n in xrange(0, 8):
            original_picture[y] = chr((ord(original_picture[y]) & 0xFE) | ((ord(hide[i]) & key ) >> n) ^ 1) # AND 0xFE est utilisé pour obtenir le LSB de l'octet courant de l'image originale, FE != FF, l'opération OR est utilisée pour placer le bit dans le LSB, le SHR >> n est utilisé pour obtenir un et un seul bit de l'image à cacher.
            # On xor notre bit obtenu de l'octet courant de l'image à cacher et on le XOR par 1 pour l'inverser <img src="https://n-pn.fr/forum/images/smilies/smile.png" alt="Smile" title="Smile" class="smilie smilie_1" />
            key = key << 1 # On applique une opération SHL pour obtenir une clé de plus en plus grande pour obtenir nos bits dans l'ordre: LSB -> MSB
            y += 1 # On incrémente l'offset y pour coder sur le LSB de l'octet suivant
        i += 1 # Quand nous avons codé un octet de l'image à cacher (for n in xrange(0, 8)<img src="https://n-pn.fr/forum/images/smilies/smile.png" alt="Smile" title="Smile" class="smilie smilie_1" /> on incrémente l'offset i pour passer à l'octet suivant

    return ''.join(original_picture)

def decode(encoded_picture, eof_file, xor):
    """ DECODE THE PICTURE """

    encoded_picture = list(encoded_picture)

    buf = ""
    rFile = "" # L'image décodée sera contenue dans cette variable
    bit_X = [] # Liste des bits (sera utilisé plus tard)
    i = 0
    try:
        while i < len(encoded_picture):
            for x in xrange(0, 4): # Pour pouvoir xor 4 octets par la suite
                for n in xrange(0, 8): # On prend les 8 LSB d'un octet de l'image contenante
                    bit_X.append( str((ord(encoded_picture[i]) & 0x1) ^ 1) ) # On ajoute le bit xoré par 1 pour réinverser l'inversion du codage à bit_X...
                    i += 1 # On incrémente de 1 l'offset i pour obtenir l'octet suivant
                buf += chr(int(''.join(bit_X)[::-1], 2)) # On obtient la valeur ASCII du binaire obten. [::-1] est utilisé pour inverser la chaine puisque nous avons codé LSB -> MSB <img src="https://n-pn.fr/forum/images/smilies/smile.png" alt="Smile" title="Smile" class="smilie smilie_1" />
                bit_X = []
            buf = struct.unpack("I", buf)[0]
            buf = buf ^ xor # On xor 4 octets pour obtenir le bout d'image complètement décodé // On pourrait faire octet par octet pour éviter la boucle for x in xrange(0, 4).
            buf = struct.pack("I", buf)
            rFile += buf # On ajoute le bout d'image à la variable finale.
            buf = ""
    except:
        """ EXCEPT !"""
    return rFile[:rFile.rfind(eof_file)] # On retourne l'image jusqu'à l'occurence de son EOF, pour ne pas casser l'image <img src="https://n-pn.fr/forum/images/smilies/smile.png" alt="Smile" title="Smile" class="smilie smilie_1" />

# Cette partie était pour le challenge, le principe est d'envoyer un message codé dans l'image BMP et de faire croire à un envoi d'image <img src="https://n-pn.fr/forum/images/smilies/smile.png" alt="Smile" title="Smile" class="smilie smilie_1" />
   
def server(src_port, eof_file, xorkey, inc, dec):
    """ SOCKET HERE """
    # On obtient les arguments..
    xorkey = int(xorkey)
    src_port = int(src_port)
    bRecv = b""
    i = 0
    # On défini la partie socket
    #bRecv = sClient.recv(4096)
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    s.bind(('0.0.0.0', src_port))
    s.listen(5)
    print "Socket listen on port: " + str(src_port)
    sClient, info = s.accept()
    print "Connexion reçue: " + str(info)
    buf = ""
    data = ""
    while True:
        while not "EOF" in buf: # Trick pour éviter les bugs rencontré avec la fonction recv() <img src="https://n-pn.fr/forum/images/smilies/smile.png" alt="Smile" title="Smile" class="smilie smilie_1" /> On se base sur le fait que le message ne contiendra pas EOF..
            buf = sClient.recv(8048)
            data += buf
        data = data[:len(data) - 3] # On vire l'eof
       
        # Le trick suivant est tout con, mais je le trouve sympa <img src="https://n-pn.fr/forum/images/smilies/smile.png" alt="Smile" title="Smile" class="smilie smilie_1" /> On pourrait qualifier ça d'une transmition de données chiffrée asymétriquement même si ce n'est pas vraiment
        # le cas. En fait, le principe est de définir des deux coté (client/serveur) une incrémentation de xorkey & une décrémentation de xorkey.
        # Ainsi le programme alternera entre incrémenter la xorkey & la décrémenter, il deviendra alors quasiment impossible à un pirate ayant sniffé le réseau au moment
        # de la transmition, de decoder le message.
        # L'algorithme ci-dessous parle de lui même <img src="https://n-pn.fr/forum/images/smilies/wink.png" alt="Wink" title="Wink" class="smilie smilie_2" />
        if i == 0:
            xorkey += inc
            data = decode(data[54:], eof_file, xorkey) # On appelle bien evidemment la fonction decode pour décoder le bouzin :p
            i += 1
        else:
            xorkey -= dec
            data = decode(data[54:], eof_file, xorkey) # Same
            i -= 1

        print data # On affiche le message
        data = ""
        buf = ""
    s.close()

def client(dst_ip, dst_port, picture, header_bmp, eof_file, xorkey, inc, dec):
    # On obitent les arguments ..
    xorkey = int(xorkey)
    dst_port = int(dst_port)
    nickname = raw_input("Nickname: ")
    nickname = "[" + nickname + "] : "
    bSend = b""
    i = 0
   
    # On défini la partie socket
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.connect((dst_ip, dst_port))
    print "Connected to " + dst_ip + ":" + str(dst_port) + "  -- Linux (CTRL+D) to escape :: Windows (CTRL+C) to escape" # Je ne suis pas sûr des raccourcis x)
    try:
        while True:
            bSend = nickname + raw_input("Post: ")
            if i == 0:
                xorkey += inc
                s.send(header_bmp + encode(picture, bSend, eof_file, xorkey) + "EOF") # On envois le message codé avec "EOF" rajouté à la fin pour le trick anti bug recv() :p
                i += 1
            else:
                xorkey -= dec
                s.send(header_bmp + encode(picture, bSend, eof_file, xorkey) + "EOF") # Same
                i -= 1

    except:
        s.close()
        sys.exit("Socket error")

def usage():
    if len(sys.argv) < 3:
        print ("Usage: {} <options>".format(sys.argv[0]))
        print ("Options:")
        print ("-p <picture_container> <file_to_hide> <eof> <xorkey> <output> (to encode a picture)")
        print ("-u <encoded_picture> <eof> <xorkey> <output> (to decode a picture)")
        print ("-ns <port> <eof> <xorkey> <inc> <dec> (to start server)")
        print ("-nc <ip> <port> <picture> <eof> <xorkey> <inc> <dec> (to start the client)")
        print ("--help (to get help)")
        sys.exit("")

if __name__ == '__main__':

    print sys.version

    if len(sys.argv) < 2:
        usage()

    elif sys.argv[1] == '--help':
        usage()

    elif len(sys.argv) == 7 and sys.argv[1] == '-p': # len(sys.argv) == 6 , si vous lancez sans donner l'emplacement de python.exe !
        #def encode(original_picture, hidden_picture, eof_file, xor):
        try:
            # On get les deux images.
            original = open(sys.argv[2], 'rb')
            original_picture = ''.join(original.readlines())
            original.close()

            hidden = open(sys.argv[3], 'rb')
            hidden_picture = ''.join(hidden.readlines())
            hidden.close()
           
            # On prend le header BMP pour l'écriture en sortie.
            header(original_picture) # On affiche les infos du fichier BMP
            header_bmp = original_picture[:54]
            original_picture = original_picture[54:]


            output_file = open(sys.argv[6], 'wb+')
            output_file.write(header_bmp + encode(original_picture, hidden_picture, sys.argv[4], int(sys.argv[5]))) # On passe les deux images à la fonction encode() <img src="https://n-pn.fr/forum/images/smilies/smile.png" alt="Smile" title="Smile" class="smilie smilie_1" />
            print "[+] File " + sys.argv[6] + " was encoded !"
            output_file.close()
        except IOError:
            print "No file !"
            sys.exit("IOError")

    elif len(sys.argv) == 6 and sys.argv[1] == '-u': # len(sys.argv) == 5 si vous lancez sans donner l'emplacement de python.exe !
        #def decode(encoded_picture, eof_file, xor):
        try:
            # On get
            encoded_pic = open(sys.argv[2], "rb")
            encoded_picture = ''.join(encoded_pic.readlines())
            encoded_pic.close()
            header(encoded_picture) # On affiche les infos du fichier BMP
            encoded_picture = encoded_picture[54:]


            output_file = open(sys.argv[5], 'wb+')
            output_file.write(decode(encoded_picture, sys.argv[3], int(sys.argv[4]))) # On passe l'image à la fonction decode() <img src="https://n-pn.fr/forum/images/smilies/smile.png" alt="Smile" title="Smile" class="smilie smilie_1" />
            print "[+] File " + sys.argv[5] + " was decoded !"
            output_file.close()

        except IOError:
            print "No file !"
            sys.exit("IOError")

    elif len(sys.argv) == 7 and sys.argv[1] == '-ns':
        #def server(src_port, eof_file, xorkey, inc, dec):
        server(int(sys.argv[2]), sys.argv[3], int(sys.argv[4]), int(sys.argv[5]), int(sys.argv[6])) # On lance le serveur

    elif len(sys.argv) == 9 and sys.argv[1] == '-nc':
        #def client(dst_ip, dst_port, picture, header_bmp, eof_file, xorkey, inc, dec):
       
        # On obtient les arguments..
        picture = open(sys.argv[4], 'r')
        tPicture = ''.join(picture.readlines())
        header_bmp = tPicture[:54]
        tPicture = tPicture[54:]
        picture.close()
        client(sys.argv[2], int(sys.argv[3]), tPicture, header_bmp, sys.argv[5], int(sys.argv[6]), int(sys.argv[7]), int(sys.argv[8])) # On lance le client <img src="https://n-pn.fr/forum/images/smilies/smile.png" alt="Smile" title="Smile" class="smilie smilie_1" />

    else:
        usage()
 


Tout les remarques sont les bienvenues ! Je dis sûrement des bêtises dans mon truc et le bitwises operator ne me sont pas encore totalement familier !
Toucher au Kernel, c'est un peut comme se shooter au LSD, on pense pouvoir tout faire mais ça finit souvent mal.
+1 (0) -1 (0) Répondre
02-07-2013, 23h29
Message : #2
oosfalte Hors ligne
Flying Cloud
*



Messages : 47
Sujets : 3
Points: 8
Inscription : Jan 2013
RE: [Python] La stéganographie BMP
Merci, je commence à décortiquer et déjà bien intéressant.
+1 (0) -1 (0) Répondre


Sujets apparemment similaires…
Sujet Auteur Réponses Affichages Dernier message
  [Python]Situer mon niveau. InforMods 19 8,359 10-11-2016, 00h03
Dernier message: ZeR0-@bSoLu
  [PYTHON] un bot IRC basique darcosion 1 1,476 13-06-2016, 20h40
Dernier message: Yttrium
  [python] ANBU ::: TCP Session Hunter St0rn 2 1,789 25-02-2016, 18h45
Dernier message: otherflow
  [Python] Une autre façon de gérer les Virtualenv et Packages thxer 2 1,591 18-01-2016, 12h06
Dernier message: thxer
  [Python] rot script ark 9 4,057 08-03-2015, 00h37
Dernier message: ark
  [Python] Todo Manager ark 5 2,519 03-03-2015, 10h55
Dernier message: ark
  [python] Un décorateur pour inventorier les objets b0fh 1 1,681 04-12-2014, 17h50
Dernier message: thxer
  [python] UPnP Scanner St0rn 2 1,665 29-10-2014, 14h50
Dernier message: St0rn
  [python] Buffer Overflow : EBP et EIP St0rn 0 1,130 25-10-2014, 12h58
Dernier message: St0rn
  [Python] QuickHex thxer 9 3,653 15-08-2014, 20h26
Dernier message: sakiir

Atteindre :


Utilisateur(s) parcourant ce sujet : 1 visiteur(s)
N-PN
Accueil | Challenges | Tutoriels | Téléchargements | Forum | Retourner en haut