缓冲区溢出技术分析:栈溢出攻击 – 作者:华云安huaun

缓冲区溢出攻击是利用缓冲区溢出漏洞所进行的攻击行动。缓冲区溢出是一种普遍且危险的漏洞,存在于软件中,以及更底层的操作系统中。利用缓冲区溢出攻击,可以导致程序运行失败、系统故障,甚至被他人控制主机等后果。本文简单讲解缓冲区溢出的原理,并举出实例进行分析。

01 溢出原理

v2-cd45389e17cb0e4dcffbcddc7b95120b_720w.png

图 1 内存示意图

缓冲区可以理解为一段可读写的内存区域。代码段存放的是程序的机器码和只读数据。数据段存储的是静态数据和用户的全局变量。堆存储程序运行时分配的变量,大小不固定,由内存地址低向高增长。栈存放函数调用时的临时信息结构,由内存地址高向低增长。入栈(PUSH)时,栈顶变小。出栈(POP)时,栈顶变大。

除了代码段和数据区域,其他的内存区域都能作为缓冲区,因此缓冲区溢出的位置可能在数据段、也可能在堆栈段。

v2-d056fca963d852c0c0fb7a3793c96fb8_720w.png

图 2 栈示意图

寄存器

ESP(栈指针寄存器)是指针寄存器的一种,用于存放函数栈顶指针,指向栈的栈顶。

EBP(基址指针寄存器)是指针寄存器的一种,用于存放函数栈底指针,指向当前活动记录的底部。

栈溢出漏洞产生的主要原因是在函数调用时,将函数的返回地址保存入栈,即调用函数运行完毕后将要返回的主函数的地址会先被入栈,如果修改了这个返回地址,并且使这个返回地址指向一个新的内存地址,那么程序就能从其他地址继续执行,这样就产生了栈溢出漏洞攻击。

比如下面这个例子:

void fun(unsigned char *data) { unsigned char buffer[BUF_LEN]; strcpy((char*)buffer,(char*)data);//溢出点 }

这个函数是一个典型的栈溢出代码,在使用不安全的strcpy库函数的时候,系统会将data的全部数据拷贝到缓冲区详细设计的区域。因为缓冲区的长度是有限的,当data的数据长度超过了BUF_LEN的时候,便会产生缓冲区溢出。

02 准备环境

  • Windows XP

  • IDA

  • OD

  • 以及两个C程序

03 实例分析

第一个符合缓冲区C程序:

#include "stdio.h"
#include "string.h"


char test[]="abcdefg";


int main()
{
char buffer[8];
strcpy(buffer,test);
printf("%s",buffer);
getchar ();
return 0;
}

第二个缓冲区溢出C程序:

#include "stdio.h"
#include "string.h"


char test[]="abcdefghijklmn";


int main()
{
char buffer[8];
strcpy(buffer,test);
printf("%s",buffer);
getchar ();
return 0;
}

在编译,建立完成程序后,运行第一个程序,按回车能正确关闭:

v2-4cfad875d7c8b3ef19db5b9aa762a23a_720w.png

v2-301382cbf96feb19ad37d8ee11b9fe5f_720w.png

运行第二个程序,按回车则会出现内存报错:

v2-c5201985c1584c2bad9d8600ad1dedee_720w.png

v2-1faf2b543da280790f1293a9edd40e52_720w.png

接下来用OD和IDA打开第一个程序:

v2-c427fcd51489565c4bb301ee70b39e81_720w.png

在IDA中看到入口地址为401010,再用OD打开,将地址跳转到401010,并下断点。

v2-8d0817a8a1a3124f998c1a108ddc0f00_720w.png

然后再IDA中交叉应用查找(crtl+x),找到call main函数的地址为401694。

v2-27a18c7078178dd64f7bb391b745b4bc_720w.png

在OD中找到这个内存地址,并下断点,然后按F9执行至断点位置。

v2-8e9d1dae9f62754b24b53bd564b2b23b_720w.png

在401694call函数的下个地址401699为call完main函数后的返回地址。

call指令分为2步,第一步,先将call指令下的地址入栈,作为返回地址记录,第二步,跳转到call的地址。在OD的栈结构中可以看到,当call之前,0012F88的栈数据为00000001。

v2-4e38c2dcb7595a95199bc753f2d3aa56_720w.png

当步入call中后,地址401699已经入栈。

v2-5181ad1a14dd56e261415b5765e85cf5_720w.png

当运行到sub esp,4c的时候查看栈空间:

v2-96e7d04d3ec23163fb0630f6c7630822_720w.png

其中,12FF84存储的是main函数的返回地址,12FF80存储的是父函数的EBP。

v2-3022815debbcd582f3a0c22b9c8a5a28_720w.png

继续按F8单步执行到strcpy函数调用处:

v2-661ca0d8be22d0b9030b45c9365122b5_720w.png

调用strcpy的时候先将test参数入栈,然后入栈buffer参数,调用strcpy函数之后将12FF78处的0xCC(烫烫烫烫烫烫烫)修改为abcdefg。按F8执行之后查看栈空间。

此处为调用的abcdefg:

v2-8dc90b1be2b46298ff44b8b77be7269c_720w.png

此处为将内存12FF78处开始载入abcdefg,载入完成后如图:

v2-9be8c16fd20579204d86db8c28f35215_720w.png

接下来查看第二个程序:

用OD打开第二个程序,断点位置如上,前边重复如上操作,直到执行到查看栈,可看到Main函数返回地址依旧在12FF84处。

v2-719c38a940456df598040221bdaf42d1_720w.png

接下来查看第二个程序:

用OD打开第二个程序,断点位置如上,前边重复如上操作,直到执行到查看栈,可看到Main函数返回地址依旧在12FF84处。

v2-719c38a940456df598040221bdaf42d1_720w.png

接着运行,可看到在strcpy函数调用test时,12FF84处的栈任还指向返回地址

v2-0be2d02eebae66375e926aff95c12540_720w.png

但在载入buffer缓冲区时,因缓冲区数据过大,已经将返回地址占据,使main主程序无法正常返回。

v2-45865698ba5429677547758689937858_720w.png

所以在执行完后返回地址错误,所以内存报错

此上栈溢出实例分析完毕。

利用:

当输入“abcdefghijklmn”时,“mn”会将返回main函数的返回地址覆盖,那么这里就可以利用,将“abcdefghijklmn”改为“abcdefghijklXXXX”,这样“XXXX”则为新的返回地址。当弹出返回地址的时候,ESP指针会自增4,指向main函数的三个参数,那么可以利用这一特性,将返回地址覆盖为“jmp esp”指令的地址,然后将main函数的参数覆盖为shellcode,这样当执行完main函数return的时候就会跳转到jmp esp指令处然后执行esp中的代码。当test数组为“abcdefghijklXXXX..shellcode”的时候,XXXX为返回地址,接着的是shellcode,然后就可以通过shellcode达成某些目的。

来源:freebuf.com 2021-02-26 15:01:24 by: 华云安huaun

© 版权声明
THE END
喜欢就支持一下吧
点赞0
分享
评论 抢沙发

请登录后发表评论