章节大纲

  • /* 有缓冲区溢出漏洞的程序 retlib.c */
    #include <stdlib.h>
    #include <stdio.h>
    #include <string.h>
    
    #ifndef BUF_SIZE
    #define BUF_SIZE 12
    #endif
    
    int bof(char *str)
    {
        char buffer[BUF_SIZE];
        unsigned int *framep;
    
        // 将ebp复制到framep
        asm("movl %%ebp, %0" : "=r" (framep));      
    
        /* 为了实验目的打印信息 */
        printf("Address of buffer[] inside bof():  0x%.8x\n", (unsigned)buffer);
        printf("Frame Pointer value inside bof():  0x%.8x\n", (unsigned)framep);
    
        strcpy(buffer, str);   (*@\reflectbox{\ding{222}} \textbf{buffer overflow!} @*)
    
        return 1;
    }
    
    int main(int argc, char **argv)
    {
       char input[1000];
       FILE *badfile;
    
       badfile = fopen("badfile", "r");
       int length = fread(input, sizeof(char), 1000, badfile);
       printf("Address of input[] inside main():  0x%x\n", (unsigned int) input);
       printf("Input size: %d\n", length);
    
       bof(input);
    
       printf("(^_^)(^_^) Returned Properly (^_^)(^_^)\n");
       return 1;
    }
    
    // 此函数将在可选任务中使用
    void foo(){
        static int i = 1;
        printf("Function foo() is invoked %d times\n", i++);
        return;
    }
     
    上述程序具有缓冲区溢出漏洞。它首先从名为 badfile 的文件中读取多达 1000 字节的输入。然后,它将输入数据传递给 bof() 函数,该函数使用 strcpy() 将输入复制到其内部缓冲区。然而,内部缓冲区的大小小于 1000,因此存在潜在的缓冲区溢出漏洞。
     
    这个程序是一个 root 拥有的 Set-uid 程序,因此如果普通用户可以利用这个缓冲区溢出漏洞,用户能够获得 root shell。该程序从用户提供的名为 badfile 的文件中获取输入,因此,我们可以构造该文件,以便当有漏洞的程序将文件内容复制到其缓冲区时,可以生成 root shell。
     
    我们首先编译代码并将其变成 root 拥有的 Set-uid 程序。不要忘记用 -fno-stack-protector 选项(关闭 StackGuard 保护)和 "-z noexecstack" 选项(打开不可执行堆栈保护)。还应注意,在打开 Set-uid 位之前必须先更改所有权,因为所有权更改会导致 Set-uid 位被关闭。所有这些命令都包含在提供的 Makefile 中。

    $ gcc -m32 -DBUF_SIZE=N -fno-stack-protector -z noexecstack -o retlib retlib.c
    $ sudo chown root retlib          
    $ sudo chmod 4755 retlib