---
title: "Sécurité logicielle : TD 9 Hackme"
date: 2023-04-14
tags: ["Assembleur", "x86"]
categories: ["Sécurité logicielle", "TD"]
author:
  - Yorick Barbanneau
---

## Level 0

### Première exécution du programme

Le programme demande à  l'utilisateur une saisie, lorsque je rentre un texte, il
répond `Nope`:

```
./hackme 
This is level 0, welcome! What do you have to say?
bonjour
Nope!
```

Il doit donc s'attendre à un mot de passe bien précis.


### Avec strace

Lors de l'exécution du programme à l'aide de `strace`, nous pouvons d'abord voir
-- après les projections mémoire avec `mmap` et d'autres éléments -- des appels
systèmes `write` pour afficher le message invitant à la saisie. Cet affichage
est découpé en 4 parties (3 de 16 octets et une de 3)

Vient ensuite un appel système `read` pour lire la saisie sur l'entrée standard
puis un `write()`  de 6 octets pour écrire `Nope!` sur la sortie standard.

Enfin un appel système `exit_group` est lancé avec 1 en paramètre (terminer tous
les threads du processus). La commande `echo $?` lancé dans le terminal ayant
exécuté `hack` confirme que le processus a quitté avec 1 comme code de
retour.

### avec strings

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:

```
[...]
GLIBC_2.2
GLIBC_2.0
__gmon_start__
ZYh<
ZYh0
8Eureu%
UWVS
[^_]
R`jw}]nj
ezsf
;*2$"(
QnuuxMjm
IAmSuperSecure
GCC: (Debian 8.3.0-6) 8.3.0
[...]
```

`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 
__libc_start_main(0x80490a0, 1, 0xffb45f24, 0x8049590 <unfinished ...>
wprintf(0x804a064, 0xf7f988cb, 0xf7c1ca2f, 0xf7f804a0This is level 0, welcome! What do you have to say?
)                              = 51
getline(0xffb45e18, 0xffb45e1c, 0xf7e1d620, 0xf7c76ca5MyBadPassword        
)                             = 14
strcmp("MyBadPassword", "IAmSuperSecure")                                           = 1
wprintf(0x804a048, 0xf7fbca40, 0, 0x80492c2Nope!
)                                        = 6
exit(1 <no return ...>
+++ exited (status 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 <u>Day of
the Tentacle</u>: *"This is all too easy!"* :

```
./hackme
This is level 0, welcome! What do you have to say?
IAmSuperSecure
Ok, that was easy!
```

## Level 1

Une fois pframe installé et le point d'arrêt positionné sur `strcmp@plt`, la
*pile d'appel* montre que la fonction appelante est `r1()`. Une fois passé dans
son contexte, analysons le code assembleur:

```{.numberLines}
[...]
(gdb) bt
#0  0x08049030 in strcmp@plt ()
#1  0x08049372 in r1 ()
#2  0x080490c8 in main ()
(gdb) frame 1
#1  0x08049372 in r1 ()
(gdb) disass
Dump of assembler code for function r1:
   0x08049350 <+0>:	    push   %ebx
   0x08049351 <+1>:	    sub    $0x14,%esp
   0x08049354 <+4>:	    push   $0x804a184
   0x08049359 <+9>:	    call   0x8049060 <wprintf@plt>
   0x0804935e <+14>:	call   0x8049220 <r>
   0x08049363 <+19>:	pop    %edx
   0x08049364 <+20>:	pop    %ecx
   0x08049365 <+21>:	push   $0x804d030 <- voici l'adresse de la chaine source
   0x0804936a <+26>:	push   %eax       <- voici l'adresse de ma saisie
   0x0804936b <+27>:	mov    %eax,%ebx
   0x0804936d <+29>:	call   0x8049030 <strcmp@plt>
=> 0x08049372 <+34>:	add    $0x10,%esp
   0x08049375 <+37>:	test   %eax,%eax
```

\pagebreak

Nous pouvons voir que les adresses vers les chaines comparées par `strcmp()`
sont positionnées sur la pile comme le montre les commentaires aux lignes 17 et
19 de la capture `gdb` ci-dessus. Mais que contiennes ces adresses :

```
(gdb) p (char*)($eax)
$1 = 0x804f580 "ThisIsMyTest
(gdb) p (char*)0x804d030
$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 obscurcie.
Essayons donc de comprendre comment. Recommençons l'exécution avec un `watch`
la chaine contenue sur le programme :

```
(gdb) wa * (char*)0x804d030 
Hardware watchpoint 1: * (char*)0x804d030
[...]

Hardware watchpoint 1: *(char*)0x804d030

Old value = 81 'Q'
New value = 72 'H'
0x08049339 in z ()
(gdb) bt
#0  0x08049339 in z ()
#1  0x080490c3 in main ()
```

La fonction permettant le déchiffrage est `z()`, passons à son désassemblage:

```
...
(gdb) disass
Dump of assembler code for function z:
   0x08049320 <+0>:	    mov    0x4(%esp),%edx
   0x08049324 <+4>:	    movzbl (%edx),%eax
   0x08049327 <+7>:	    test   %al,%al
   0x08049329 <+9>:	    je     0x8049340 <z+32>
   0x0804932b <+11>:	lea    0x0(%esi,%eiz,1),%esi
   0x0804932f <+15>:	nop

   0x08049330 <+16>:	sub    $0x9,%eax        ; retire 0x9 à %eax
   
   0x08049333 <+19>:	add    $0x1,%edx        ; incrémente %edx

   0x08049336 <+22>:	mov    %al,-0x1(%edx)   ; remets le caractère déchiffré 
                                                ; dans sa chaine

=> 0x08049339 <+25>:	movzbl (%edx),%eax      ; copie le caractère courant
                                                ; dans %eax (bits 1 à 8)

   0x0804933c <+28>:	test   %al,%al          ; boucle tant que le caractère
   0x0804933e <+30>:	jne    0x8049330 <z+16> ; \0 n'est pas trouvé
```

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.

\pagebreak

## Level 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?
ThisIsTest

Breakpoint 1, 0x08049030 in strcmp@plt ()
(gdb) bt
#0  0x08049030 in strcmp@plt ()
#1  0x080493ca in r2 ()
#2  0x080490cd in main ()
```

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 <wprintf@plt>
   0x080493ae <+14>:	call   0x8049220 <r>
   0x080493b3 <+19>:	mov    %eax,%ebx
   0x080493b5 <+21>:	mov    %eax,(%esp)
   0x080493b8 <+24>:	call   0x80492f0 <x1>
   0x080493bd <+29>:	pop    %eax
   0x080493be <+30>:	pop    %edx
   0x080493bf <+31>:	push   $0x804adec    <- adresse de la chaine
   0x080493c4 <+36>:	push   %ebx          <- adresse de notre saisie
   0x080493c5 <+37>:	call   0x8049030 <strcmp@plt>
=> 0x080493ca <+42>:	add    $0x10,%esp
   0x080493cd <+45>:	test   %eax,%eax
   0x080493cf <+47>:	jne    0x80493eb <r2+75>
   0x080493d1 <+49>:	sub    $0xc,%esp
   0x080493d4 <+52>:	push   $0x804a318
   0x080493d9 <+57>:	call   0x8049060 <wprintf@plt>
   0x080493de <+62>:	mov    %ebx,(%esp)
   0x080493e1 <+65>:	call   0x8049050 <free@plt>
   0x080493e6 <+70>:	add    $0x18,%esp
   0x080493e9 <+73>:	pop    %ebx
   0x080493ea <+74>:	ret
   0x080493eb <+75>:	call   0x8049280 <f>
End of assembler dump.
```

Profitons-en pour afficher le contenu de nos deux chaines:

```
(gdb) p (char*)0x804adec
$10 = 0x804adec "R`jw}]nj"
(gdb) p (char*)$ebx
$11 = 0x804f5c0 "]qr|R|]n|}"
```

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.

\pagebreak

Pour déchiffrer le mot de passe écrit dans le programme, j'ai écris un script 
Python :

```python
cyphertext = "R`jw}]nj"
cleartext = ""
for l in range(len(cyphertext)):
    c += (chr(ord(cyphertext[l])-0x9))
print(cleartext)
```

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
résultat de la commande `bt`:

```
[...]
#5  0x08049248 in r ()
#6  0x08049403 in wut ()
#7  0x080490d2 in main ()
```

`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 ()
(gdb) disass
Dump of assembler code for function wut:
   0x080493f0 <+0>:	    push   %ebx
   0x080493f1 <+1>:	    sub    $0x14,%esp
   0x080493f4 <+4>:	    push   $0x804a37c
   0x080493f9 <+9>:	    call   0x8049060 <wprintf@plt>
   0x080493fe <+14>:	call   0x8049220 <r>
=> 0x08049403 <+19>:	add    $0x10,%esp
   0x08049406 <+22>:	cmpl   $0x65727545,(%eax)  <- intéressant
   0x0804940c <+28>:	jne    0x8049433 <wut+67>
   0x0804940e <+30>:	cmpl   $0x21614b,0x4(%eax) <- et encore interessant
   0x08049415 <+37>:	mov    %eax,%ebx
   0x08049417 <+39>:	jne    0x8049433 <wut+67>
   0x08049419 <+41>:	sub    $0xc,%esp
   0x0804941c <+44>:	push   $0x804a424
   0x08049421 <+49>:	call   0x8049060 <wprintf@plt>
   0x08049426 <+54>:	mov    %ebx,(%esp)
   0x08049429 <+57>:	call   0x8049050 <free@plt>
   0x0804942e <+62>:	add    $0x18,%esp
   0x08049431 <+65>:	pop    %ebx
   0x08049432 <+66>:	ret
   0x08049433 <+67>:	call   0x8049280 <f>
End of assembler dump.
```

Voici deux comparaisons intéressantes. La première s'effectue sur les 4 octets à
l'adresse contenue dans `%eax`. La suivante sur le contenu à l'adresse de 
`%eax + 0x4`.

\pagebreak

Un script Python permet encore une fois de transformer ces deux valeurs en
texte, le voici:

```python
#!/bin/env python3

hextext = "6572754521614b"
finaltext = ""
cleartext = ""
for i in range(0, len(hextext) - 1, 2):
    c = '{}{}'.format(hextext[i], hextext[i+1])
    cleartext += (chr(int(c, 16)))
cur_size=0
bits_processed=0
for i in range(0, len(cleartext) - 1, 4):
    if (len(cleartext) - 4 * bits_processed) > 4:
        cur_size = 4
    else:
        cur_size = len(cleartext) - 4 * bits_processed
    for j in range(i+cur_size,i,-1):
        finaltext += cleartext[j-1]
    bits_processed+=1
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 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 exécuter notre programme dans gdb, utiliser la
technique du `ctrl+c` puis `bt`:

```
...
#5  0x08049248 in r ()
#6  0x080494e3 in aa ()
#7  0x080490d7 in main ()
```

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
   0x080494d1 <+1>:	    sub    $0x14,%esp
   0x080494d4 <+4>:	    push   $0x804a474
   0x080494d9 <+9>:	    call   0x8049060 <wprintf@plt>
   0x080494de <+14>:	call   0x8049220 <r>
=> 0x080494e3 <+19>:	mov    %eax,(%esp)
   0x080494e6 <+22>:	mov    %eax,%ebx
   0x080494e8 <+24>:	call   0x8049080 <strlen@plt>
   0x080494ed <+29>:	add    $0x10,%esp
   0x080494f0 <+32>:	cmp    $0x4,%eax
   0x080494f3 <+35>:	jne    0x8049524 <aa+84>
   0x080494f5 <+37>:	sub    $0x8,%esp
   0x080494f8 <+40>:	push   $0x804adf5
   0x080494fd <+45>:	push   %ebx
   0x080494fe <+46>:	call   0x8049470 <bb> <-  cet appel est intéressant non?
   0x08049503 <+51>:	add    $0x10,%esp
   0x08049506 <+54>:	test   %eax,%eax
   0x08049508 <+56>:	je     0x8049524 <aa+84>
   0x0804950a <+58>:	sub    $0xc,%esp
   0x0804950d <+61>:	push   $0x804a4ec
   0x08049512 <+66>:	call   0x8049060 <wprintf@plt>
   0x08049517 <+71>:	mov    %ebx,(%esp)
   0x0804951a <+74>:	call   0x8049050 <free@plt>
   0x0804951f <+79>:	add    $0x18,%esp
   0x08049522 <+82>:	pop    %ebx
   0x08049523 <+83>:	ret
   0x08049524 <+84>:	call   0x8049280 <f>
End of assembler dump.
```

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`
 * puis copie cette adresse dans %ebx, afin de préparer l'appel à `strlen()`
 * cet appel positionnera le résultat dans `%eax` à partir de la chaine dans
   `%ebx`
 * `%esp` est incrémenté de 16 (*0x10*).
 * Ensuite le résultat de `strlen()` est comparé à 4, en cas de non égalité, le
   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*.
 * `%ebx` est ensuite poussé sur la pile
 * `bb()` est appelée, c'est cette fonction qui se charge du 'déchiffrement'

### La fonction `bb()`

Voici le code de cette fonction donné par `objdump` avec l'affichage des sauts :

```
8049470:              56                     push   %esi
8049471:              53                     push   %ebx
8049472:              8b 5c 24 10            mov    0x10(%esp),%ebx
8049476:              8b 74 24 0c            mov    0xc(%esp),%esi
804947a:              0f b6 13               movzbl (%ebx),%edx
804947d:              84 d2                  test   %dl,%dl
804947f:    /-------- 74 2d                  je     80494ae <bb+0x3e>
8049481:    |         0f b6 06               movzbl (%esi),%eax
8049484:    |         83 f0 12               xor    $0x12,%eax
8049487:    |         38 c2                  cmp    %al,%dl
8049489: /--|-------- 75 35                  jne    80494c0 <bb+0x50>
804948b: |  |         b8 01 00 00 00         mov    $0x1,%eax
8049490: |  |  /----- eb 14                  jmp    80494a6 <bb+0x36>
8049492: |  |  |      8d b6 00 00 00 00      lea    0x0(%esi),%esi
8049498: |  |  |  /-> 0f b6 14 06            movzbl (%esi,%eax,1),%edx
804949c: |  |  |  |   83 c0 01               add    $0x1,%eax
804949f: |  |  |  |   83 f2 12               xor    $0x12,%edx
80494a2: |  |  |  |   38 ca                  cmp    %cl,%dl
80494a4: +--|--|--|-- 75 1a                  jne    80494c0 <bb+0x50>
80494a6: |  |  \--|-> 0f b6 0c 03            movzbl (%ebx,%eax,1),%ecx
80494aa: |  |     |   84 c9                  test   %cl,%cl
80494ac: |  |     \-- 75 ea                  jne    8049498 <bb+0x28>
80494ae: |  \-------> b8 01 00 00 00         mov    $0x1,%eax
80494b3: |            5b                     pop    %ebx
80494b4: |            5e                     pop    %esi
80494b5: |            c3                     ret
80494b6: |            8d b4 26 00 00 00 00   lea    0x0(%esi,%eiz,1),%esi
80494bd: |            8d 76 00               lea    0x0(%esi),%esi
80494c0: \----------> 31 c0                  xor    %eax,%eax
80494c2:              5b                     pop    %ebx
```

Voici un déroullé des instructions principales de cette fonction :

 * `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 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`
 * `8049487` : les bits de poids faible de `%eax` et `%edx` sont comparés
 * `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 poids faible de `(%esi,%eax,1)` correspondant à la
   lettre suivante de notre chaine mystère `ecx`
 * `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`
 * `804949c` : `%eax` est incrémenté de 1
 * `804949f` : un `xor` est ensuite réalisé entre *0x12* et `%edx`
 * `80494a2` : les bits de poids faible de `%eax` et `%edx` sont comparés
 * `80494a4` : s'il ne sont pas égaux alors fin du programme, sinon nous
   revenons à l'instruction `80494a6`.

En clair, notre chaine mystère est bien le **mot de passe "chiffré"**, un simple
*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$$

Là encore un script Python permet de faire le travail pour nous:

```python
#!/bin/env python3
hextext = "66737a65"
finaltext = ""
cleartext = ""
for i in range(0, len(hextext) - 1, 2):
    c = '{}{}'.format(hextext[i], hextext[i+1])
    cleartext += chr(int(c, 16) ^ 0x12)
cur_size=0
bits_processed=0
for i in range(0, len(cleartext) - 1, 4):
    if (len(cleartext) - 4 * bits_processed) > 4:
        cur_size = 4
    else:
        cur_size = len(cleartext) - 4 * bits_processed
    for j in range(i+cur_size,i,-1):
        finaltext += cleartext[j-1]
    bits_processed+=1
print('Level 4 text: {}'.format(finaltext))
```

Ce qui donne:

```bash
./level4.py
Level 4 text: what
```

Le mot de passe de ce niveau est donc `what`

## Level 5

Ici encore la technique du `ctrl+c` fonctionne bien :

```
[...]
Program received signal SIGINT, Interrupt.
0xf7fc7559 in __kernel_vsyscall ()
(gdb) bt
[...]
#5  0x08049248 in r ()
#6  0x08049543 in yay ()
#7  0x080490dc in main ()
```

Donc la fonction intéressante est `yay()`, voici le code assembleur avec les
sauts affichés par `objdump` :

```
08049530 <yay>:
 8049530:	       53                   	push   %ebx
 8049531:	       83 ec 14             	sub    $0x14,%esp
 8049534:	       68 84 a5 04 08       	push   $0x804a584
 8049539:	       e8 22 fb ff ff       	call   8049060 <wprintf@plt>
 804953e:	       e8 dd fc ff ff       	call   8049220 <r>
 8049543:	       89 04 24             	mov    %eax,(%esp)
 8049546:	       89 c3                	mov    %eax,%ebx
 8049548:	       e8 33 fb ff ff       	call   8049080 <strlen@plt>
 804954d:	       83 c4 10             	add    $0x10,%esp
 8049550:	       83 f8 03             	cmp    $0x3,%eax
 8049553:	/----- 76 36                	jbe    804958b <yay+0x5b>
 8049555:	|      0f b6 03             	movzbl (%ebx),%eax
 8049558:	|      89 da                	mov    %ebx,%edx
 804955a:	|      31 c9                	xor    %ecx,%ecx
 804955c:	|      84 c0                	test   %al,%al
 804955e:	+----- 74 2b                	je     804958b <yay+0x5b>
 8049560:	|  /-> 83 c2 01             	add    $0x1,%edx
 8049563:	|  |   31 c1                	xor    %eax,%ecx
 8049565:	|  |   0f b6 02             	movzbl (%edx),%eax
 8049568:	|  |   84 c0                	test   %al,%al
 804956a:	|  \-- 75 f4                	jne    8049560 <yay+0x30>
 804956c:	|      80 f9 43             	cmp    $0x43,%cl
 804956f:	+----- 75 1a                	jne    804958b <yay+0x5b>
 8049571:	|      83 ec 0c             	sub    $0xc,%esp
 8049574:	|      68 24 a6 04 08       	push   $0x804a624
 8049579:	|      e8 e2 fa ff ff       	call   8049060 <wprintf@plt>
 804957e:	|      89 1c 24             	mov    %ebx,(%esp)
 8049581:	|      e8 ca fa ff ff       	call   8049050 <free@plt>
 8049586:	|      83 c4 18             	add    $0x18,%esp
 8049589:	|      5b                   	pop    %ebx
 804958a:	|      c3                   	ret
 804958b:	\----> e8 f0 fc ff ff       	call   8049280 <f>
```

Sans rentrer dans les détails instruction par instruction comme fait lors du
niveau précédent, cette fonction :

 * Vérifie que la saisir utilisateur soit supérieure à 3 caractères
   (instructions `8049548` à `8049553`)
 * Initialise `%ecx` à 0 via un `xor` sur lui même (instruction `804955a`).
 * 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'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, amenant vers la mauvaise fin.

Cet algorithme de chiffrement est vraiment faible. `0x43` correspond à `C` dans
la table ascii, utilisons les mathématiques:

\begin{gather}
\nonumber0 \oplus A = A\\
 \nonumber\text{et } A \oplus A = 0\\
 \nonumber\text{ainsi } 0 \oplus A \oplus A = 0\\
 \nonumber\text{donc } 0 \oplus A \oplus A \oplus A \oplus A \oplus B = B
\end{gather}

Ansi saisir un même caractère un nombre pair de  fois suivi de `C`, alors c'est 
gagné :

```
.hackme
[...]
Level 5 is onboard! Will you make it?
xxxxC
Yay!

************************************************
*   ____                            _       _  *
*  / ___|___  _ __   __ _ _ __ __ _| |_ ___| | *
* | |   / _ \| '_ \ / _` | '__/ _` | __/ __| | *
* | |__| (_) | | | | (_| | | | (_| | |_\__ \_| *
*  \____\___/|_| |_|\__, |_|  \__,_|\__|___(_) *
*                   |___/                      *
*                                              *
* You passed all the levels!!                  *
************************************************
```

Pour ameliorer le chiffrement, il faudrait pouvoir vérifier le `xor` sur 4
octets set non sur un seul.

### script pour trouver les mots de passe

Il est aussi très simple d'écrire un script permettent de générer des mots de
passes permettant de passer le niveau 5. Par exemple, celui-ci ajoute le
caractère de fin au mot fourni par l'utilisateur :

```python
#!/bin/env python3
import sys

password = sys.argv[1]

if len(password) < 3:
    print('Minimal password size: 3 char, get {}'.format(len(password)))
    sys.exit(1)
xor=0
target=0x43
for letter in password:
    xor=xor^ord(letter)
last_letter=xor^target
print("here is your password: {}{}".format(password,chr(last_letter)))
```

L'utilisation est simple:

```
./level5.py Toto
here is your password: Totoc
```
