TD9 corrections and rewords

This commit is contained in:
Yorick Barbanneau 2023-04-23 00:31:51 +02:00
parent 60aecd0591
commit d4fb4c586a

View file

@ -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:
@ -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,7 +84,7 @@ exit(1 <no return ...>
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 <u>Day of
the Tentacle</u>: *This is all too easy!* :
the Tentacle</u>: *"This is all too easy!"* :
```
./hackme
@ -136,7 +136,7 @@ $2 = 0x804d030 <p> "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,15 +202,15 @@ 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
0x080493a0 <+0> push %ebx
0x080493a1 <+1>: sub $0x14,%esp
0x080493a4 <+4>: push $0x804a280
0x080493a9 <+9>: call 0x8049060 <wprintf@plt>
@ -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,7 +516,7 @@ 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
@ -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!! *
************************************************
```