ssm插入数据时候栈溢出_实验三 栈溢出的漏洞的认识及利用

一、实验目的

   1、了解栈溢出漏洞定义及原理;

   2、使学生掌握如何使用栈溢出漏洞利用。

二、实验环境

  VC++6.0、ollydbg逆向工具等。

三、实验内容及步骤:

   1、了解栈的基本原理

   2、对栈溢出漏洞进行模拟操作

  3、栈溢出漏洞实战练习

四、实验过程

1. 什么是栈

栈是一种机制,计算机用它来将参数传递给函数,也可以用于放入局部函数变量,函数返回地址,它的目的是赋予程序一个方便的途径来访问特定函数的局部数据,并从函数调用者那边传递信息。栈的作用如同一个缓冲区,保存着函数所需的所有信息。在函数的开始时候产生栈,并在函数的结束时候释放它。栈一般是静态的,也意味着一旦在函数的开始创建一个栈,那么栈就是不可以改变的。栈所有保存的数据是可以改变的,但是栈的本身一般是不可以改变的

(1)缓冲溢出分为两种,一种是栈溢出,一种是堆溢出。

(2)如何找到栈?

2. 几个必须了解的指针

EIP:扩展指令指针。在调用函数时,这个指针被存储在栈中,用于后面的使用。在函数返回时,这个被存储的地址被用于决定下一个将被执行的指令的地址。

ESP:扩展栈指针。这个寄存器指向栈的当前位置,并允许通过使用push和pop操纵或者直接的指针操作来对栈中的内容进行添加和移除。

EBP:扩展基指针。这个寄存器在函数的执行过程中通常是保持不变的。它作为一个静态指针使用,用于只想基本栈的信息,例如,使用了偏移量的函数的数据和变量。这个指针通常指向函数使用栈底部

3、 VC++6.0的部分调试按钮

逐过程调试—F10      

逐语句调试—F11

跳到光标处—Ctrl+F10 

跳出本循环—Shift+F11 

设定断点—F9  

删除所有断点—Ctrl+Shift+F9          

开始编译 F7  

反汇编调试 Alt +8

重新编译 –Ctrl+F7                  

开始调试--F5   

停止调试—Shift+F5  

重新启动—Ctrl+Shift+F5:

4、通过实践来进行处理

(1)首先演示一下栈的形成:下面是以下代码

#include

int main()

{

    _asm

    {

        push 0x12345678

        pop eax

    }

}

(2)分析及利用

我们可以在VC++6.0 进行调试来观察一下esp和eip以及ebp的状态变化;

我们编译后,开始逐过程调试,来观察ESP,EBP的位置

0daaf5723cd171f0d28b04be9d9b19a3.png

我们逐语句调试下,就会发现ESP栈顶指针会跟随变化,因为我们向栈中压人了12345678这样四个字节的数据,指针会减小4个字节的。

68e75777fcedd1431857716ed9e2b1ba.png

而我们pop的时候就会发现栈顶指针就变大成为了原来的样子。这就告诉我们一个道理栈中压人数据的时候栈顶指针是变小的,而弹出栈的时候栈顶指针是变大的。也就是栈底地址高于栈顶地址。

(3)接下来操作函数内栈的调用过程:

5bc6dd5b0e159f6abcd700d3cb2c3dee.png

首先没有进入到stack_overflow函数里面的的时候EBP和ESP都是有值得,说明外面的main函数也有栈的实现。我们反汇编看一下具体栈的实现。单步走一下就会发现一个跳转jmp跳转到函数stack_overflow

4ae7a20aedc1f4658f9688b96db9a6d5.png

这时候我们单步步入

93958c7f6044a7683141228a95f92515.png

就会看到如上代码,这时候我们来进一步分析一下。首先它将ebp指针压人栈内,将当前的esp指向的地址给了ebp,这时候esp减小了44h,这时候在堆栈中又开辟了一个长度为44h的一个新的栈空间。从我们分析可以得出dword ptr[ebp-4],0这个局部变量是存放在新的栈空间里面的。ebp-4远远小于44h空间大小。局部变量是存放在栈中的。

    通过这个例子我们可以得出一个结论就是如果程序要调用某个函数,那么计算机就会自动将函数返回后执行的指令地址先压入栈里,等函数调用完之后再从中取出,跳转到该处执行。溢出的原因?

正式因为先放入栈的地址在前,而后放入栈的数据一旦过长,就会覆盖到前面的地址这就会导致程序发生错误。

(5)下面来操作下栈溢出现象;

1.#include  

2.#include  

3.#include  

4.void overflow(char *buf)  

5.{  

6.    char des[5]="";  

7.    strcpy(des,buf);  

8.    return;  

9.}  

10.void main(int argc,char *argv[])  

11.{  

12.    LoadLibrary("user32.dll");  

13.    char longbuf[100]="aaaaaaaaaaaabbbbcccccccccccc";  

14.    overflow(longbuf);  

15.    return;  

16.}  

程序一运行就会停止工作:

c31090f6db5f08af58d7ba305d3acc32.png

(6)下面我们不妨来跟踪下程序:

f2af18a940629341b6d25b9cdb488bdf.png

首先先把函数下一个地址以及参数压入栈中:

3dd420b863a5bc36009634c699e579d4.png

这时候单步运行到了strcpy这里:这是我们会发现将参数的值出来放在寄存器edx里面了,请看下面图:00 12 FF 1C

8b73d7bf750bf494ffdd6e5c4fa57120.png

然而,当我们继续单步的时候,发现代码已经一片空白

ccfc2ba4ea8c663faddd42b11f69a14e.png

这是因为前面buf的值太长,吧返回地址覆盖到,使得程序无法获取到正确的返回地址,从而程序无法正常进行。

思考:

   如果通过修改longbuf中的内容,使得返回地址到达自己预先设计的函数的函数头中,可以实现什么作用。

五、实验总结

     通过这个实验让学生了解栈溢出漏洞简单了解,以及研究其产生的原因。

六、实验思考题

 给出一段代码:

1.#include   

2.#include  

3.#define PASSWORD "qqqqqqq"  

4.int verify_password(char *password)  

5.{  

6.    int authenticated;  

7.    char buffer[8];  

8.    authenticated=strcmp(password,PASSWORD);  

9.    strcpy(buffer,password); //构造栈溢出  

10.    return authenticated;  

11.}  

12.  

13.int main()  

14.{  

15.    int valid_flag=0;  

16.    char password[1024];  

17.    while(1)  

18.    {  

19.        printf("please input password:     ");  

20.        scanf("%s",password);  

21.        valid_flag=verify_password(password);  

22.        if(valid_flag)  

23.        {  

24.            printf("incorrect password!\n\n");  

25.        }  

26.        else  

27.        {  

28.            printf("Congratulation! you have passed the Verification !\n");  

29.            break;  

30.        }  

31.    }  

32.    getchar();  

33.    char i;  

34.    scanf("%s",&i);  

35.}  

如何在不知道密码的情况下通过栈溢出绕过密码验证环节得到答案?

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值