zoukankan      html  css  js  c++  java
  • 缓冲区溢出攻击试验(bufbomb.c)

    本文的实验来源于CSAPP 《Computer Systems A Programmer's Perspective》 (深入理解计算机系统)一书中第三章的一个实验,即习题3.38。
    作者给出了一个含有缓冲区溢出的程序bufbomb.c,你需要做的,就是注入给缓冲区些特殊的数据,到底利用缓冲区的目的。
    在做这个题目之前,你当然要知道什么是帧栈结构(请参阅《深入理解计算机系统》第三章)或者之前的博文栈帧&溢出,了解%ebp和%esp的含义
     
    //bufbomb.c
    /*
    Bomb program that is solved using a buffer overflow attack */

    #include
    <stdio.h>
    #include
    <stdlib.h>
    #include
    <ctype.h>

    /* Like gets, except that characters are typed as pairs of hex digits.
    Nondigit characters are ignored. Stops when encounters newline
    */
    char*getxs(char*dest)
    {
      int c;
      int even =1; /* Have read even number of digits */
      int otherd =0; /* Other hex digit of pair */
      char*sp = dest;
      while ((c = getchar()) != EOF && c !='\n') {
        if (isxdigit(c)) {
          int val;
          if ('0'<= c && c <='9')
            val
    = c -'0';
          else if ('A'<= c && c <='F')
            val
    = c -'A'+10;
          else
            val
    = c -'a'+10;
          if (even) {
            otherd
    = val;
            even
    =0;
          }
          else {
            *sp++= otherd *16+ val;
            even
    =1;
          }
        }
      }
      *sp++='\0';
      return dest;
    }

    /* $begin getbuf-c */
    int getbuf()
    {
      char buf[12];
      getxs(buf);
      return1;
    }

    void test()
    {
      int val;
      printf(
    "Type Hex string:");
      val
    = getbuf();
      printf(
    "getbuf returned 0x%x\n", val);
    }
    /* $end getbuf-c */

    int main()
    {

      int buf[16];
    /* This little hack is an attempt to get the stack to be in a
    stable position
    */
      int offset = (((int) buf) &0xFFF);
      int*space = (int*) alloca(offset);
      *space =0; /* So that don't get complaint of unused variable */
      test();
      return0;
    }
     
           函数getxs的功能类似于库函数gets的功能,除了它是以十六进制数字对的编码方式读入的字符。例如,要读入字符串“0123”,你得给出输入字符串“30 31 32 33”,这个函数会忽略空格。
           分析这个程序,可以得知,正常情况下,这个函数会在getbuf中,调入getxs函数读入数字对,然后不管任何情况下,都会对test函数返回0x1,然后由test中的printf函数打印处getbuf的返回值。
           现在你的任务,就是,利用缓冲区溢出的漏洞,输入些特殊的数字,使得屏幕中打印的是0xdeadbeef。
     
           由于这个程序中含有alloca函数,因而要添加#include <new>#include <excpt.h>#include <malloc.h>(这三个是我在网上随便搜的,反正引进之后编译之后不报错)。
           我是在WindowsXP,visual c++6.0环境解决这个问题的。
           题目中已经说了,“分析这个程序,可以得知,正常情况下,这个函数会在getbuf中,调入getxs函数读入数字对,然后不管任何情况下,都会对test函数返回0x1,”那我们该怎么办了?我们马上可以想到在getbuf这个函数里定义的char buf[12]上做手脚,可以看到在getxs函数里的while循环,结束条件只是以回车或者是eof结束符为判断标准,所以,根本没对char输入的数量做判断!这样的话,我们可以输入多于12个的数,从而缓冲区溢出!
           在这里还是提一下帧栈结构,如下:
    +-------------------------------+高地址
    |函数参数 n 个                   |
    +-------------------------------+
    |函数参数第 n-1 个            |
    +-------------------------------+
    |                    . . .                   |
    |                    . . .                   |
    |                    . . .                   |
    +-------------------------------+
    |函数参数第1个                  |
    +-------------------------------+
    |return 返回地址                 |
    +-------------------------------+
    |ebp指针入栈                      |
    +-------------------------------+
    |local var(局部变量)      |
    +-------------------------------+
    |                            others     |
    +-------------------------------+低地址
     
        按照上面说的函数栈的存放情况,在getbuf这个函数里,函数参数没有,我们不管,然后就是return返回地址,然后就是ebp指针,然后就是char buf[12]。
    +-------------------------------+低地址
    |return 返回地址                 |
    +-------------------------------+
    |ebp指针入栈                      |
    +-------------------------------+
    |                buf[11]                |
    +-------------------------------+
    |                buf[10]                |
    +-------------------------------+
                        :
                        :
                        :
    +-------------------------------+
    |                 buf[0]                 |
    +-------------------------------+
    |                others                  |
    +-------------------------------+高地址
           如果我们对buf溢出,能改写ebp和return地址!下面看看,ebp是多少,return地址是多少。
           要知道这里的%ebp存的是test函数的%ebp,因而我们在调试的时候就可以在test函数得到%ebp的值,它应该是我们写入的buf[12]-buf[15]的值,而且它要保持原来的值,不然返回之后就乱套了,在我机器上是0x0012efa0。这个很容易,解决了第一步。
           下面我们再来看返回地址,先看一段汇编码(不同的机器有所不同):
    58:       val = getbuf();
    004011C5   call        @ILT+10(getbuf) (0040100f)
    004011CA   mov         dword ptr [ebp-4],eax
    59:       printf("getbuf returned 0x%x\n", val);
    004011CD   mov         eax,dword ptr [ebp-4]
    004011D0   push        eax
    004011D1   push        offset string "getbuf returned 0x%x\n" (0042001c)
    004011D6   call        _printf (00401510)
    004011DB   add         esp,8
    
     
           在getbuf()返回后,肯定会接着执行004011CA ,我们能让它从这执行吗?当然不行!不然就要push eax,那是我们不想看到的,因为eax的值就是1。因而我们会想到能不能跳过这?当然能,改返回地址啊!顺水推舟,我们通过buf数组来覆盖返回地址。此时,我们想要它直接跳到004011D1处,因而可以通过设置buf[16]-buf[19]的值来覆盖返回地址。
           到了考虑如何加进deadbeef了,在返回后,将直接执行push        offset string "getbuf returned 0x%x\n" (0042001c),没eax怎么行了?不然printf函数就少了参数。再回到帧栈结构一下,printf在调用之前,要压入参数,先压入val,再压入offset string "getbuf returned 0x%x\n",也就是说参数val(等同那个eax)在offset string "getbuf returned 0x%x\n“之上,而且紧挨着。此时我们可以想到,既然返回之后(返回地址及其以下的元素都已弹出,返回地址的上一个字节成了栈顶)就执行push        offset string "getbuf returned 0x%x\n" (0042001c)进行压栈,那此时栈顶一定是参数val,而它原来就在返回地址上面,因而我们可以通过设置buf[20]-buf[23]的值来覆盖这个地方。
           综上所述,%ebp的值为0x0012efa0,修改后的返回地址为0x004011D1,因而我们可以输入
           00000000  00000000  00000000  a0ef1200  d1114000  efbeadde
           这24个0可以输入别的,不影响,关键是后面24个数。
    ---
    可以转载, 但必须以超链接形式标明文章原始出处和作者信息及版权声明
  • 相关阅读:
    class-决策树Decision Tree
    class-朴素贝叶斯NaiveBayes
    class-k近邻算法kNN
    [linux环境配置]个人用持续更新ing~
    [python基础] python生成wordcloud并保存
    [算法基础]快排、归并、堆排序比较
    [算法基础]斐波那契(recursion+loop)两种方式执行时间对比
    [python基础]xml_rpc远程调控supervisor节点进程
    [Supervisor]supervisor监管gunicorn启动DjangoWeb时异常退出
    [python基础] csv.wirterow()报错UnicodeEncodeError
  • 原文地址:https://www.cnblogs.com/null00/p/2065108.html
Copyright © 2011-2022 走看看