diff --git a/content/secu_logicielle/td9-hackme/index.md b/content/secu_logicielle/td9-hackme/index.md index 1c2a61e..1eed4bf 100644 --- a/content/secu_logicielle/td9-hackme/index.md +++ b/content/secu_logicielle/td9-hackme/index.md @@ -11,7 +11,7 @@ author: ### Première exécution du programme -Le programme demande à l'utilisateur une saisir, lorsque je rentre un texte, il +Le programme demande à l'utilisateur une saisie, lorsque je rentre un texte, il répond `Nope`: ``` @@ -41,7 +41,7 @@ retour. ### avec strings -L'exécution de `strings hackme` montre des choses interessantes. On y voit des +L'exécution de `strings hackme` montre des choses intéressantes. On y voit des traces des fonctions `wprintf` (qui pourrait être utile pour la suite), `strlen`. `getline`. On voit aussi tout un tas d'autres chaines qui semble être des mots de passe: @@ -51,8 +51,8 @@ des mots de passe: GLIBC_2.2 GLIBC_2.0 __gmon_start__ -ZYh< -ZYh0 +ZYh< +ZYh0 8Eureu% UWVS [^_] @@ -65,8 +65,8 @@ GCC: (Debian 8.3.0-6) 8.3.0 [...] ``` -`IAmSuperSecure` parait relativement intéressant. mais à ce state rien n'est -sûr. Mais juste comme ça essayons tout de même un `lstrace` sur nore programme: +`IAmSuperSecure` parait relativement intéressant. Mais à ce stade rien n'est +sûr. Mais juste comme ça essayons tout de même un `lstrace` sur notre programme: ``` ltrace ./hackme @@ -84,10 +84,10 @@ exit(1 La sortie de `ltrace` une fois la saisie effectuée, montre qu'elle est comparée avec `IAmSuperSecure`, un essai le confirme. Comme dirait Bernard dans Day of -the Tentacle: *This is all too easy!* : +the Tentacle: *"This is all too easy!"* : ``` -./hackme +./hackme This is level 0, welcome! What do you have to say? IAmSuperSecure Ok, that was easy! @@ -136,7 +136,7 @@ $2 = 0x804d030

"HelloDad" ``` Nous avons notre mot de passe `HelloDad`. Mais cette chaine ne figure pas dans -la liste des chaines données par la commande `strings`, elle est donc obsurcie. +la liste des chaines données par la commande `strings`, elle est donc obscurcie. Essayons donc de comprendre comment. Recommençons l'exécution avec un `watch` la chaine contenue sur le programme: @@ -184,12 +184,12 @@ Dump of assembler code for function z: En observant le contenu de cette fonction, on comprend alors que le déchiffrement du mot de passe du niveau 2 se fait en retirant `0x9` à chaque -caractère de la chaine contenue dans le programme. On retrouv +caractère de la chaine contenue dans le programme. ## Level 2 -C'est reparti pour un tour! Nouvelle exécution du programme en plaçant un point -d'arrêt sur `srtcmp@plt` et on arrive jusqu'au niveau 2: +C'est reparti pour un tour! Nouvelle exécution du programme avec *gdb* en +plaçant un point d'arrêt sur `srtcmp@plt` et on arrive jusqu'au niveau 2: ``` On to level 2! So what do you want? @@ -202,18 +202,18 @@ Breakpoint 1, 0x08049030 in strcmp@plt () #2 0x080490cd in main () ``` -Cette fois-ci c'est la fonction `r2()` qui s'occupe du "déchiffrement, voici son -code désassemblé : +Cette fois-ci c'est la fonction `r2()` qui s'occupe du "déchiffrement", voici +son code désassemblé : ``` (gdb) frame 1 #1 0x080493ca in r2 () (gdb) disass Dump of assembler code for function r2: - 0x080493a0 <+0>: push %ebx - 0x080493a1 <+1>: sub $0x14,%esp - 0x080493a4 <+4>: push $0x804a280 - 0x080493a9 <+9>: call 0x8049060 + 0x080493a0 <+0> push %ebx + 0x080493a1 <+1>: sub $0x14,%esp + 0x080493a4 <+4>: push $0x804a280 + 0x080493a9 <+9>: call 0x8049060 0x080493ae <+14>: call 0x8049220 0x080493b3 <+19>: mov %eax,%ebx 0x080493b5 <+21>: mov %eax,(%esp) @@ -251,7 +251,7 @@ Code de `x1()` qui "chiffre" la saisie utilisateur du troisième mot de passe. C'est le chiffrement inverse de celui vu au niveau 1, ici on ajoute `0x9` à chaque caractère. -Pour déchiffrer le mote de passe écrit dans le programme, j'ai écris un script +Pour déchiffrer le mot de passe écrit dans le programme, j'ai écris un script Python : ```python @@ -267,7 +267,7 @@ ce qui nous donne `IWantTea` ### Level 3 Après avoir lancé le programme et atteint la saisie du niveau 3, `Ctrl+c` envoi -le signal `SIGINT` au programme, donne la main à l'invite de commande. voici le +le signal `SIGINT` au programme, donne la main à l'invite de commande. Voici le résultat de la commande `bt`: ``` @@ -277,10 +277,9 @@ résultat de la commande `bt`: #7 0x080490d2 in main () ``` -`r()` se se charge de la saisie, mais que fait `wut()`, interessons nous +`r()` se se charge de la saisie, mais que fait `wut()`? Intéressons nous à cette fonction d'abord passant dans sa frame puis en la désassemblant: - ``` (gdb) frame 6 #6 0x08049403 in wut () @@ -310,7 +309,7 @@ End of assembler dump. ``` Voici deux comparaisons intéressantes. La première s'effectue sur les 4 octets à -l'adresse contenur dans `%eax`. La suivante sur le contenu à l'adresse de +l'adresse contenue dans `%eax`. La suivante sur le contenu à l'adresse de `%eax + 0x4`. Un script Python permet encore une fois de transformer ces deux valeurs en @@ -339,15 +338,15 @@ print('Level 3 text: {}'.format(finaltext)) ``` La seconde série de boucles de ce script sert à remettre les octets dans le bon -ordre. En effet les données sont mises sur la pile et chaque élément de 4 octets -doit être inversé. +ordre. En effet les données sont mises sur la pile donc chaque élément de 4 +octets doit être inversé. Le mot de passe est `EureKa!` ## Level 4 -comme pour le niveau 3, il faut utiliser la technique du `ctrl+c` pour utiliser -`bt`: +Comme pour le niveau 3, il faut exécuter notre programme dans gdb, utiliser la +technique du `ctrl+c` puis `bt`: ``` ... @@ -356,11 +355,12 @@ comme pour le niveau 3, il faut utiliser la technique du `ctrl+c` pour utiliser #7 0x080490d7 in main () ``` - -C'est la fonction `aa()` qui appelle `r()` (fonction de saicie), Interessons -nous à elle en la désassamblant : +C'est la fonction `aa()` qui appelle `r()` (fonction de saisie), intéressons +nous à elle en la désassemblant : ``` +(gdb) frame 6 +[...] (gdb) disass Dump of assembler code for function aa: 0x080494d0 <+0>: push %ebx @@ -393,10 +393,9 @@ Dump of assembler code for function aa: End of assembler dump. ``` -Cette fonction appelle une autre foncion : `bb()`. C'est elle qui semble se -charger de la vérification de la saisie. - -Mais avant ça `aa()` met les élements en place: +Cette fonction appelle une autre : `bb()`. C'est elle qui semble se charger de +la vérification de la saisie. Avant de l'étudier, voyons comment `aa()` met les +éléments en place avant de l'appeler : * mets l'adresse vers la zone mémoire contenant la saisie utilisateur dans l'adresse contenue dans `%esp` @@ -405,17 +404,18 @@ Mais avant ça `aa()` met les élements en place: `%ebx` * `%esp` est incrémenté de 16 (*0x10*). * Ensuite le résultat de `strlen()` est comparé à 4, en cas de non égalité, le - procgramme branche sur `f()` qui met fin à l'exécution.. Nous pouvons donc en - déduite que notre saisie doit être de 4 cacactères exactement. + programme branche sur `f()` qui met fin à l'exécution.. Nous pouvons donc en + déduite que notre saisie doit être de 4 caractères exactement. * La pile est ensuite décrémentée de 8 * *0x804adf5* est ensuite positionné sur la pile, Il semble que se soit une - adresse. le contenu de cette espace mémoire est *0x66737a65*. + adresse. Le contenu de cette espace mémoire est *0x66737a65*. * `%ebx` est ensuite poussé sur la pile - * `bb()` est appelée, c'est cette fonction qui se chage du 'déchiffrement' + * `bb()` est appelée, c'est cette fonction qui se charge du 'déchiffrement' ### La fonction `bb()` -voic le code de cette fonction donné par `objdump` avec l'affichage des sauts : +Voici le code de cette fonction donné par `objdump` avec l'affichage des sauts : + ``` 8049470: 56 push %esi 8049471: 53 push %ebx @@ -451,13 +451,13 @@ voic le code de cette fonction donné par `objdump` avec l'affichage des sauts : Voici un déroullé des instructions principales de cette fonction : - * `8049472` : on mets en place le contenu de l'adresse contenant notre série de - 4 octets mystères *0x66737a65* dans `%ebx` + * `8049472` : on mets en place le contenu de l'adresse vers notre série de + 4 octets mystères (*0x66737a65*) dans `%ebx` * `8049476` : l'adresse vers notre saisie est positionnée dans `%esi` * `804947a` : l'octet de poids faible de `%ebx` est copié dans `%edx` * `804947d` : et logique de `%dl` sur lui même, si le test est vrai alors le - programme branche sur la fin "normale" de la fonction. Ceci signifirait que - notre chaine mystère est vide (donc pas de mot de passe). + programme branche sur la fin "normale" de la fonction. Ceci signifiait que + notre chaine mystère est vide (donc pas de mot de passe dans le programme). * `8049481` : l'octet de poids faible de notre saisie `%esi` est positionné dans `%eax` * `8049484` : un `xor` est ensuite réalisé entre *0x12* et `%eax` @@ -465,11 +465,11 @@ Voici un déroullé des instructions principales de cette fonction : * `8049489` : en cas d'inégalité, la fonction se termine. * `804948b` : *0x1* est écrit dans `%eax`. * `8049490` : Branchement vers l'instruction `80494a6` - * `80494a6` : l'octet de poid faible de `(%esi,%eax,1)` correspondant à la + * `80494a6` : l'octet de poids faible de `(%esi,%eax,1)` correspondant à la lettre suivante de notre chaine mystère `ecx` - * `80494aa` : si l'opération booleene de `%cl` sur lui même est différente de - zéro alors le probramme branche sur `8049498`. Ce test permet de savoir si on - est en fin de chaine (`\0`) sur notre chaine mystère. sinon le fil de code + * `80494aa` : si l'opération booléenne de `%cl` sur lui même est différente de + zéro alors le programme branche sur `8049498`. Ce test permet de savoir si on + est en fin de chaine (`\0`) sur notre chaine mystère. Sinon le fil de code continue jusqu'à la fin de la fonction. * `8049498` : le programme prend le caractère suivant de notre saisir et le place dans `%edx` @@ -480,9 +480,9 @@ Voici un déroullé des instructions principales de cette fonction : revenons à l'instruction `80494a6`. En clair, notre chaine mystère est bien le **mot de passe "chiffré"**, un simple -*xor* avec *0x12* sur cachun des caractères de ce dernier nous permettra de -trouver le mot de passe à saisir. On utilise pour celà la propriété suivante du -*"ou exclusif"* +*xor* avec *0x12* sur chacun des caractères de ce dernier nous permettra de +trouver le mot de passe à saisir. On utilise pour cela la propriété suivante du +*"ou exclusif"* : $$A \oplus B = C \implies C \oplus B = A$$ @@ -516,11 +516,11 @@ Ce qui donne: Level 4 text: what ``` -Le mot de pase de ce niveau est donc `what` +Le mot de passe de ce niveau est donc `what` ## Niveau 5 -Ici encore la technique du `ctrl+c` fonctionne bien: +Ici encore la technique du `ctrl+c` fonctionne bien : ``` [...] @@ -573,7 +573,7 @@ sauts affichés par `objdump` : ``` Sans rentrer dans les détails instruction par instruction comme fait lors du -niveau précédent, cette fonction: +niveau précédent, cette fonction : * Vérifie que la saisir utilisateur soit supérieure à 3 caractères (instructions `8049548` à `8049553`) @@ -581,10 +581,10 @@ niveau précédent, cette fonction: * Boucle sur les caractères contenus dans la chaine saisie par l'utilisateur et réalise un `xor` de celui-ci avec `%ecx`. Le résultat de cette opération est stockée dans `%ecx` (instructions `8049555` à `804956a`). - * Cette boucle s'arrete lorsque le caractère fin de chaine (`\0`) est trouvé + * Cette boucle s'arrête lorsque le caractère fin de chaine (`\0`) est trouvé (instruction `8049568`) * Compare `%ecx` à `0x43`, s'il y a égalité alors le programme continue, sinon - la fonction `f()` est appelée, ammenant la mauvaise fin. + la fonction `f()` est appelée, amenant vers la mauvaise fin. Cat algorithme de chiffrement est vraiment faible, quelques ligne en Python permettent de générer des mots de passes valides: @@ -613,3 +613,24 @@ manquant pour arriver à `0x43`: ./level5.py Toto here is your password: Totoc ``` + +Maintenant il est possible de passer le dernier niveau : + +``` +.hackme +[...] +Level 5 is onboard! Will you make it? +Totoc +Yay! + +************************************************ +* ____ _ _ * +* / ___|___ _ __ __ _ _ __ __ _| |_ ___| | * +* | | / _ \| '_ \ / _` | '__/ _` | __/ __| | * +* | |__| (_) | | | | (_| | | | (_| | |_\__ \_| * +* \____\___/|_| |_|\__, |_| \__,_|\__|___(_) * +* |___/ * +* * +* You passed all the levels!! * +************************************************ +```