• 栈溢出攻击 [转]


    本文的实验来源于《Computer Systems A Programmer's Perspective》(深入理解计算机系统》一书中第三章的一个实验。 
        作者给出了一个含有缓冲区溢出的程序bufbomb.c,你需要做的,就是注入给缓冲区些特殊的数据,到底利用缓冲区的目的。

     1 //bufbomb.c 
     2 /* Bomb program that is solved using a buffer overflow attack */ 
     3 #include <stdio.h> 
     4 #include <stdlib.h> 
     5 #include <ctype.h> 
     6 /* Like gets, except that characters are typed as pairs of hex digits. 
     7   Nondigit characters are ignored.  Stops when encounters newline */ 
     8 char *getxs(char *dest) 
     9 { 
    10   int c; 
    11   int even = 1; /* Have read even number of digits */ 
    12   int otherd = 0; /* Other hex digit of pair */ 
    13   char *sp = dest; 
    14   while ((c = getchar()) != EOF && c != '/n') { 
    15     if (isxdigit(c)) { 
    16       int val; 
    17       if ('0' <= c && c <= '9') 
    18     val = c - '0'; 
    19       else if ('A' <= c && c <= 'F') 
    20     val = c - 'A' + 10; 
    21       else 
    22     val = c - 'a' + 10; 
    23       if (even) { 
    24     otherd = val; 
    25     even = 0; 
    26       } else { 
    27     *sp++ = otherd * 16 + val; 
    28     even = 1; 
    29       } 
    30     } 
    31   } 
    32   *sp++ = '/0'; 
    33   return dest; 
    34 } 
    35 /* $begin getbuf-c */ 
    36 int getbuf() 
    37 { 
    38     char buf[12]; 
    39     getxs(buf); 
    40     return 1; 
    41 } 
    42 void test() 
    43 { 
    44   int val; 
    45   printf("Type Hex string:"); 
    46   val = getbuf(); 
    47   printf("getbuf returned 0x%x/n", val); 
    48 } 
    49 /* $end getbuf-c */ 
    50 int main() 
    51 { 
    52   int buf[16]; 
    53   /* This little hack is an attempt to get the stack to be in a 
    54     stable position 
    55   */ 
    56   test(); 
    57   return 0; 
    58 } 

            函数getxs的功能类似于库函数gets的功能,除了它是以十六进制数字对的编码方式读入的字符。例如,要读入字符串“0123”,你得给出输入字符串“30 31 32 33”,这个函数会忽略空格。 
            分析这个程序,可以得知,正常情况下,这个函数会在getbuf中,调入getxs函数读入数字对,然后不管任何情况下,都会对test函数返回0x1,然后由test中的printf函数打印处getbuf的返回值。 
            现在你的任务,就是,利用缓冲区溢出的漏洞,输入些特殊的数字,使得屏幕中打印的是0xdeadbeef。

     

            我是在WindowsXP,visual c++6.0环境解决这个问题的。

     

            在做这个题目之前,你当然要知道什么是帧栈结构(请参阅《深入理解计算机系统》第三章),了解%ebp和%esp的含义。

     

            题目中已经说了,“分析这个程序,可以得知,正常情况下,这个函数会在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个数。

    [转] http://blog.csdn.net/idoit0204/article/details/3935627

  • 相关阅读:
    Validation failed for one or more entities. See 'EntityValidationErrors' property for more details
    Visual Studio断点调试, 无法监视变量, 提示无法计算表达式
    ASP.NET MVC中MaxLength特性设置无效
    项目从.NET 4.5迁移到.NET 4.0遇到的问题
    发布网站时应该把debug设置false
    什么时候用var关键字
    扩展方法略好于帮助方法
    在基类构造器中调用虚方法需谨慎
    ASP.NET MVC中商品模块小样
    ASP.NET MVC中实现属性和属性值的组合,即笛卡尔乘积02, 在界面实现
  • 原文地址:https://www.cnblogs.com/longdouhzt/p/2783934.html
Copyright © 2020-2023  润新知