Affichage des articles dont le libellé est hack. Afficher tous les articles
Affichage des articles dont le libellé est hack. Afficher tous les articles

mercredi 21 septembre 2011

CTF Hack.lu 2011 - Unknown Planet

Hello tout le monde !

un petit writeup sur un challenge de CTF Hack.lu 2011.

Description
We got this file. Can you find the name of this planet?
Voici l’image qu’on peut télécharger en cliquant sur le lien :



1. Analyse

Comme l’indique la description du challenge, un nom de planète se cache quelque part dans cette image Jpeg.
On commence par ouvrir l’image avec un éditeur héxadécimal (Hex Workshop ici) et on remarque très vite une chose troublante.
En effet, le code héxadécimal d’une image Jpeg commence toujours par FF D8 et se termine toujours par FF D9. Voici ce qu’on peut observer avec cette image :
Début du code hexadécimal


Fin du code hexadécimal



Le code débute bien par FF D8 mais par contre les deux octets FF D9 ne sont pas présents à la fin du code. En faisant, une recherche sur ces 2 octets, on parvient néanmoins à les trouver.


On vient de trouver la fin du code hexadécimal servant à la représentation de l’image. Tout ce qui suit pourrait être supprimé sans que cela n’ait d’impact sur l’image elle-même.
Ce code hexadécimal supplémentaire mérite donc qu’on se penche dessus pour y dénicher quelque info confidentielle comme le nom d’une planète par exemple.
On récupère donc ce code et on l’insère dans une nouvelle page de l’éditeur pour une analyse plus poussée. Voici un extrait du code :


On remarque deux choses :
  • - Des chaînes de 13 caractères se terminant toutes par UT (encadrées en bleu).
  • - La présence des caractères PK tout au long du code (entourés en rouge).
Les caractères PK sont caractéristiques des fichiers zip : Ce sont les initiales de Phil Katz, le créateur du format.
On peut donc enregistrer notre code hexadécimal en tant que fichier .zip pour voir ce qu’on obtient.

2. Travail sur l'archive Zip

L’archive nouvellement créée contient 9 fichiers dont les noms rappellent les chaînes de caractères mentionnées plus haut.



Si on ouvre le premier avec notepad voici ce qu’on peut voir :


L’entête nous indique qu’il s’agit d’un fichier wav. On l’enregistre alors en tant que tel et on le lance avec VLC par exemple.
On entend clairement le début d’un code Morse (un point et deux traits) et on se doute qu’il va falloir concaténer les 9 fichiers dans le bon ordre afin d’obtenir l’enregistrement complet en Morse censé nous révéler le nom de cette planète (du moins on l’espère).
On connaît déjà le premier fichier : celui qui contient l’entête, mais on sait aussi que le dernier est celui dont la taille est nettement inférieure à celle des autres (on a 8 fichiers de 20 000 octets et un seul de 1324 octets).
On remarque que cet ordre est respecté lorsqu’on classe les fichiers par ordre décroissant selon la valeur de la colonne « Compressé » dans Winrar (voir capture plus haut).
On peut alors penser qu’il faudra tester deux possibilités à cause des deux fichiers à 72.
Pourtant les enregistrements ne donnent rien de probant : ils comportent notamment des coupures brèves qui nous amènent à penser que cette façon d’ordonner les fichiers n’était pas la bonne.

3. Analyse des blocs de code hexadécimal récurrents

On va alors se placer à un niveau plus bas en ouvrant les 9 fichiers dans Hex Workshop pour analyser le code hexadécimal plus en détail.
On remarque que les 9 fichiers sont composés de deux types de blocs :
1er type de bloc (Bloc A)


2ème type de bloc (Bloc B)


Si compte le nombre d’octets qui composent chacun de ces blocs dans les 9 fichiers, on constate qu’on a deux tailles possibles pour chaque bloc. Le bloc A peut faire 5761 octets ou 1921 octets alors que le bloc B peut faire 5759 octets ou 1919 octets.
On va pouvoir reconstituer ce puzzle en regardant la taille des blocs A et B inachevés en début et fin de fichiers et en cherchant le bloc complémentaire à chacun qui donnera un bloc total correspondant à l’une des tailles possibles.
Cette séance de collage nous donnera l’ordre de fichiers suivants :
  1. uvlSlG3Tgow
  2. 5IIUED7GheR
  3. rySOWi4fZkA
  4. 87F1s5POUJc
  5. 6JXtwsTTh9k
  6. Uw105aD3qYh
  7. BPiIOASG_Z6
  8. Yui5oq58hlx
  9. nLPA8X0UJqf
On concatène alors ces 9 fichiers dans un seul qu’on enregistre en tant que fichier wav.
Maintenant place au décodage !!!!


4. Décodage

L’enregistrement est plutôt net et on obtient facilement le code Morse suivant :
.--. …. . .. -.- -.-- --- …
On décode alors le mot de 8 lettres : PHEIKYOS
On connaît enfin le nom de notre planète et on valide ce challenge en rentrant le flag : Pheikyos.

5. Tools

  • Hex Workshop
  • Winrar
  • Notepad
  • VLC

6. Référence




lundi 27 juin 2011

CTF Public NDH2K11 – Crackme1

Hello !

On continue dans les writeups de la NDH 2011 avec celui pour le crackme1. Gogogo !

  1. Analyse


    On nous a fourni un exécutable, safecrypt.exe, ainsi qu'un fichier PNG chiffré.
    On se doute bien du but de l'épreuve, c'est à dire, déchiffrer cette image qui doit contenir le flag.
    On lance alors ce safecrypt.exe pour voir, ça ne coûte rien (pour un crackme :))

    D:\Devs\NDH2K11>SafeCrypt.exe
    Use : [1/2] SafeCrypt.exe input output
    1 : Crypt
    2 : UnCrypt

    On apprend qu'il veut 3 arguments, le mode, le fichier d'entrée et le fichier de sortie. Rien de particulier.
    Un petit coup de PeID pour voir s'il est packé ou s’il utilise des fonctions crypto (md5, base64...). Mais non, toujours rien :)


    C’est fini pour les préliminaires, on passe aux choses sérieuses ! On l’ouvre avec notre ImmunityDbg préféré et on obtient ceci :


    On voit 3 blocs de code, puis le saut vers une certaine adresse. Ensuite plus rien.
    On reconnait tout de suite un code qui unpack par les routines qui déchiffrent les sections, puis un saut vers l'OEP.
    L'adresse de début de la section est mise dans EAX, la fin dans ECX, ensuite on xor chaque octet avec 2D (la clé). Et on fait ça pour les 3 sections.
    On peut le vérifier en comparant avec les adresses des sections avec LordPE (VOffset et RSize) :


    On unpack ou pas ? On verra si il y besoin, pour le moment on laisse comme ça.
    Quelques touches F7/F8 plus tard, on arrive bien au début de notre programme.


  2. Reverse


    On descend un peu et on tombe sur des choses plus intéressantes.


    Il vérifie si le nombre d’arguments est au moins 3, si c’est bon on demande le mot de passe sinon ça affiche le message "usage".


    Une partie importante, après avoir lu le mot de passe, on calcule sa taille (avec strlen), puis on passe le tout à la fonction SafeCryp.00401637.
    Cette fonction calcule un hash du mot de passe sur 4 octets, qui sera ensuite utilisé (heureusement :) ) pour le chiffrement/déchiffrement.


    On ouvre notre fichier d’entrée, de même pour la sortie. Pour calculer la taille du fichier d’entrée, on utilise lseek en se plaçant à la fin du fichier, puis on revient au début.
    Avec cette taille, on alloue un buffer qui servira surement à mettre notre version chiffrée/déchiffrée du fichier. Tout est prêt ! go !


    Voilà la partie du chiffrement, au début on compare le paramètre à "1", si ça correspond on chiffre, sinon on le compare avec "2" pour le déchiffrement, et si ça correspond toujours pas, ben ... tant pis, on continue quand même :).
    La partie finale, on ne va pas la détailler, on écrit notre buffer dans le fichier de sortie, on dit « Finished! » et voilà.
    Si vous avez bien suivi, dans le cas d’une opération inconnue, on aura des valeurs indéfinies dans le fichier de sortie, et ui, mais on s’en fou et l'auteur du chall aussi :)

    Revenons à notre chiffrement, au début on lit notre fichier et on met dans le buffer. ok.
    Ensuite pour chaque DWORD du buffer, on XOR avec le hash précédemment calculé, ce qui donne notre DWORD chiffré, puis on met à jour la « clé » en utilisant la même fonction qu'au début, SafeCryp.00401637 et le DWORD en clair. Un genre de mode CBC sauf qu’on utilise le clair.

    Donc voilà, c’est juste un XOR avec une clé de 4 octets. On pourrait bruteforcer, mais bon, c’est une épreuve de crackme, il doit y avoir plus simple ou en-tout-cas moins long :) . Avant d’utiliser le brain, regardons le déchiffrement.


    Le début est le même, on met tout le fichier dans le buffer. Ensuite pour chaque DWORD chiffré, on le XOR avec le hash du mot de passe, on retrouve notre octet clair.
    On garde ce DWORD déchiffré pour mettre à jour le hash et on passe au DWORD suivant.
    Ainsi de suite …

  3. Brain


    Voici donc pour résumer l’algorithme utilisé :

    fonction chiffre(buffer, hash){
        pour chaque DWORD i du buffer {
            tmp = buffer[i]
            buffer[i] = buffer[i] XOR hash
            hash = updateHash(hash, tmp)
        }

    }

    fonction dechiffre(buffer, hash)
        pour chaque octet i du buffer {
            buffer[i] = buffer[i] XOR hash
            hash = updateHash(hash,
    buffer[i])
        }

    }

    Bon alors, comment qu’on fait maintenant ? :)
    Il faut remarquer que le hash de départ est le seul à utiliser le mot de passe, donc c’est sur celui-là qu’il faudra jouer.
    Le reste des hashs dépend des octets déchiffrés et des hashs précédents, si le premier est bon, les autres le seront.
    Donc il faudrait forcer le premier hash à être bon, peut importe la clé qu’on entre.
    On se rappelle qu’on a : clair = hash XOR chiffré, le chiffré on l’a, le clair on l’a ….? Et UI ! C’est un fichier png donc l’entête est standard et vaut 89 50 4E 47.
    Donc on peut calculer le hash pour déchiffrer les premiers octets. Pour trouver le mot de passe derrière, c’est un autre problème, mais on n’en a pas besoin ici.
    Pas besoin de rappeler comment marche le XOR, on sait que hash = chiffré XOR clair.

    #include <stdio.h>

    unsigned int sw(unsigned int x){
        return (x>>24) |
               ((x<<8) & 0x00FF0000) |
               ((x>>8) & 0x0000FF00) |
               (x<<24);
    }

    int main(int argc, char* argv[]){
        FILE* in = fopen("Challenge.png", "r");
        int b, hash;
        if (in){
            fread(&b, 4, 1, in);
            printf("First dword is %.08x and first hash should be %.08x\n", b, b ^ sw(0x89504e47));
            fclose(in);
        }
        return 0;
    }

    Quelques lignes de C ou une ligne de Python plus tard, on sait que le hash doit être 80ce21e8.
    (J'ai rajouté une fonction swap, ça peut toujours être utile à quelqu'un :) )

  4. Crack


    On va patcher la valeur du hash avec Immunity, c'est la méthode la plus rapide.
    Pour cela, il faut déjà mettre les arguments au programme (Debug > Arguments) et on met quelque chose du genre : 2 Challenge.png Flag.png.
    Avant de run le programme, on met un breakpoint à l'adresse 0x00401347, c'est à cette adresse que le programme récupère la valeur du hash (depuis EAX) et la sauvegarde quelque part.
    Maintenant c'est bon, on trace à fond, on donne un mot de passe comme demandé, ensuite on arrive à notre breakpoint. On modifie la valeur d'EAX par 0x80ce21e8 puis on laisse le programme finir.


    Et voilà, le flag est dans Flag.png :)

    Une autre méthode ?
    On peut aussi patcher safecrypt.exe, pour faire simple, faut unpacker, éditer le fichier et remplacer le call juste avant 0x00401347 (offset 0x1342) par un mov eax, 0x80ce21e8 (qui donne B8E821CE80) en héxa.

  5. Références & tools


    [1] - PeID
    [2] - LordPE
    [3] - ImmunityDbg
    [4] - Unpack d'UPX, mais la méthode est la même ici

CTF Public NDH2K11 – Stega4

Nous revoilà avec les write-ups du CTF Public de la NDH 2011, cette fois c'est le Stega4 !

  1. Analyse


    On nous donne uniquement une grosse (~6mo) image SVG :(
    On l'affiche et... rien de spécial.
    On l'ouvre avec ce bon vieux Notepad++ par exemple et on découvre, au milieu, un gros paquet de données encodé en base64.

    <meta name="geturflaghere" value="Vm0...

    Avec le nom "geturflaghere" on en sûr ! Le flag est là !

    Après un premier décodage, on s’aperçoit que le flag a été encodé de nombreuses fois :(
    Il va falloir automatiser ça !

  2. Décodage


    Chacun sa méthode pour le décodage, en voici 2 :

    • Batch + base64.exe

      Cette méthode nécessite d'avoir extrait la partie base64 du fichier avant.

      @echo off

      if "%1" == "" goto usage
      if not exist "%1" goto usage

      copy %1 %TEMP%\%~n1.tmp 1> NUL

      :l
      base64.exe -d %TEMP%\%~n1.tmp %TEMP%\%~n1.tmp.dec 2> NUL
      if %ERRORLEVEL% == 1 goto flag
      del %TEMP%\%~n1.tmp
      ren %TEMP%\%~n1.tmp.dec %~n1.tmp
      goto l
      goto exit

      :usage
      echo Usage: %~n0 file.b64
      goto exit

      :flag
      type %TEMP%\%~n1.tmp
      del %TEMP%\%~n1.tmp
      goto exit

      :exit

       

    • Python

      Petite astuce pour extraire les données, on cherche juste une chaine assez longue contenant uniquement les caractères d'un base64 :

      import re
      import base64

      image = re.findall('[\w+/=]{100,}',
          open("stega4.svg").read().replace(" ", ""))[0]
         
      try:
          while 1:
              image = base64.b64decode(image)
      except TypeError:
          print image
       

    Dans les 2 cas, on obtient : G1rl1en3x7d00rIz9:]

    Et voilà vous avez le flag ! Gogo next challenge !

  3. Références & tools


    [1] - Base64.exe for Windows