> For the complete documentation index, see [llms.txt](https://sansong.gitbook.io/cyber/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://sansong.gitbook.io/cyber/pwn/protections/stack-canary.md).

# Stack canary

Canary in a coal mine

## Overview

Un **stack canary (ou canari de pile)** est un mécanisme simple de protection contre les buffer overflow.&#x20;

A l'appel d'une fonction, une valeur (canari) est placée sur la stack après l'adresse de retour. Quand la fonction termine son exécution **la valeur du canari est vérifiée**. Si elle a été modifiée c'est qu'une tentative de **buffer overflow** a eu lieu et l'exécution est interrompue avec le message `***stack smashing detected***`.

<figure><img src="https://1813806532-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FZRRTPIEA4wb6exZozwS0%2Fuploads%2FIKUcwM5icRAbDHpNxYSr%2Fstack-canary.svg?alt=media&amp;token=44a4f912-beed-4cb7-bb2d-986165cbac99" alt="" width="563"><figcaption><p>Fonctionnement d'un stack canary</p></figcaption></figure>

**Activer:**

```
gcc program.c -o program -fstack-protector
```

**Désactiver:**

```
gcc program.c -o program -fno-stack-protector
```

{% hint style="info" %}
Elle tient son nom des canaris utilisés dans les mines pour vérifier la présence de gaz toxiques.&#x20;
{% endhint %}

## Plus en détails

### Exemple

```c
#include <stdio.h>

void vuln() {
    char buffer[25];
    gets(buffer);
}

int main(int argc, char** argv) {
    vuln();
    return 0;
}
```

On le compile avec le canari:

```bash
┌──(kali㉿kali)-[~/Documents/exploits]
└─$ gcc canary.c -o canary -fstack-protector -m32                                                                                                       
```

Maintenant si on tente un buffer overflow on a un message d'erreur:

```bash
┌──(kali㉿kali)-[~/Documents/exploits]
└─$ python -c "print('A'*50)" | ./canary 
*** stack smashing detected ***: terminated
```

Jetons un oeil à ce qui se passe avec gdb. Dans le code assembleur de `vuln` on voit un appel à une fonction `__stack_chk_fail_local` à la fin. C'est elle qui est appelée pour arrêter l'exécution dans le cas où un **buffer overflow** est détecté.

```c
(gdb) set disassembly-flavor intel 
(gdb) disas vuln
Dump of assembler code for function vuln:
   0x0000119d <+0>:     push   ebp
   0x0000119e <+1>:     mov    ebp,esp
   0x000011a0 <+3>:     push   ebx
   0x000011a1 <+4>:     sub    esp,0x24
   0x000011a4 <+7>:     call   0x11fe <__x86.get_pc_thunk.ax>
   0x000011a9 <+12>:    add    eax,0x2e4b
   0x000011ae <+17>:    mov    edx,DWORD PTR gs:0x14
   0x000011b5 <+24>:    mov    DWORD PTR [ebp-0xc],edx
   0x000011b8 <+27>:    xor    edx,edx
   0x000011ba <+29>:    sub    esp,0xc
   0x000011bd <+32>:    lea    edx,[ebp-0x25]
   0x000011c0 <+35>:    push   edx
   0x000011c1 <+36>:    mov    ebx,eax
   0x000011c3 <+38>:    call   0x1040 <gets@plt>
   0x000011c8 <+43>:    add    esp,0x10
   0x000011cb <+46>:    nop
   0x000011cc <+47>:    mov    eax,DWORD PTR [ebp-0xc]
   0x000011cf <+50>:    sub    eax,DWORD PTR gs:0x14
   0x000011d6 <+57>:    je     0x11dd <vuln+64>
   0x000011d8 <+59>:    call   0x1210 <__stack_chk_fail_local>  <== ???
   0x000011dd <+64>:    mov    ebx,DWORD PTR [ebp-0x4]
   0x000011e0 <+67>:    leave
   0x000011e1 <+68>:    ret
End of assembler dump.
```

On va décomposer ce code pour bien comprendre ce qui se passe.

#### Prologue de la fonction

La stack frame de `vuln` est préparée.

```c
   0x0000119d <+0>:     push   ebp
   0x0000119e <+1>:     mov    ebp,esp
   0x000011a0 <+3>:     push   ebx
   0x000011a1 <+4>:     sub    esp,0x24  <== place pour les variables locales
```

#### Mise en place du canari

La valeur située à l'adresse pointée par le registre `gs+0x14`  est placée dans `EDX` puis à l'adresse `ebp-0xc` sur la pile. C'est notre fameux canari !

```c
   0x000011ae <+17>:    mov    edx,DWORD PTR gs:0x14
   0x000011b5 <+24>:    mov    DWORD PTR [ebp-0xc],edx
   0x000011b8 <+27>:    xor    edx,edx
```

Mettons un breakpoint à l'adresse `0x000011b5` pour voir la valeur du canari dans `EDX`.

```c
(gdb) b *vuln+24
(gdb) r
Breakpoint 1 at 0x000011b5

(gdb) x $edx
0x1c826400:     Cannot access memory at address 0x1c826400
```

La valeur du canari est donc **0x1c826400**.

#### Exécution de la fonction

Le code de `vuln` est exécuté.

```c
   0x000011ba <+29>:    sub    esp,0xc
   0x000011bd <+32>:    lea    edx,[ebp-0x25]
   0x000011c0 <+35>:    push   edx
   0x000011c1 <+36>:    mov    ebx,eax
   0x000011c3 <+38>:    call   0x1040 <gets@plt>
   0x000011c8 <+43>:    add    esp,0x10
   0x000011cb <+46>:    nop
```

#### Vérification du canari

La valeur du canari placée plus tôt sur la pile à `ebp-0xc` est placée dans `EAX` et soustraite à la valeur originale à `gs+0x14` avec l'instruction `sub`.&#x20;

```c
   0x000011cc <+47>:    mov    eax,DWORD PTR [ebp-0xc]
   0x000011cf <+50>:    sub    eax,DWORD PTR gs:0x14
   0x000011d6 <+57>:    je     0x11dd <vuln+64>
   0x000011d8 <+59>:    call   0x1210 <__stack_chk_fail_local>
```

Si elles sont égales le résultat est 0 et l'instruction `je (jump if equal)` envoie l'exécution à l'adresse `0x11dd` qui correspond à la fin normal de la fonction (cas où tout va bien).

```c
   0x000011dd <+64>:    mov    ebx,DWORD PTR [ebp-0x4]
   0x000011e0 <+67>:    leave
   0x000011e1 <+68>:    ret
```

Si elles sont différentes le `jump` n'est pas pris et la fonction `__stack_chk_fail_local` est appelée et arrête l'exécution avec le message `***stack smashing detected**`.
