freeBuf
主站

分类

漏洞 工具 极客 Web安全 系统安全 网络安全 无线安全 设备/客户端安全 数据安全 安全管理 企业安全 工控安全

特色

头条 人物志 活动 视频 观点 招聘 报告 资讯 区块链安全 标准与合规 容器安全 公开课

官方公众号企业安全新浪微博

FreeBuf.COM网络安全行业门户,每日发布专业的安全资讯、技术剖析。

FreeBuf+小程序

FreeBuf+小程序

缓冲区溢出-原理和简单利用
2019-04-25 11:43:13

缓冲区溢出

缓冲区溢出的原理

  • 什么是缓冲区溢出?缓冲区溢出是一种非常普遍、非常危险的漏洞,在各种操作系统、应用软件中广泛存在。利用缓冲区溢出攻击,可以导致程序运行失败、系统宕机、重新启动等后果。更为严重的是,可以利用它执行非授权执行,甚至可以取得系统特权,进行各种非法操作。缓冲区溢出(buffer overflow),是针对程序设计缺陷,向程序输入缓冲区写入使之溢出的内容(通常是超过缓冲区能保存的最大数据量的数据),从而破坏程序运行、趁著中断之际并获取程序乃至系统的控制权。
  • 首先,创建一个缓冲区溢出隐患的简单程序:
#include "stdio.h"
#include "string.h"
char name[] = "guangyu";
int main()
{
 char buffer[8];
 strcpy(buffer, name);        //strcpy函数,把含有'\0'结束符的字符串复制到另一个地址空间,                            返回值的类型为char*
 printf("%s",buffer);
 getchar();                  //getchar函数,读入
 return 0;
}
  • 编译并运行:

image

image

  • 程序也可以正常输出,但却弹出错误对话框。

分析原因:

1、使用OllyDbg载入Test1

image

2、使用IDA PRO定义main函数入口地址,为0x00401010,在OllyDbg中跳转至此。

image

3、在OllyDbg中,main函数里有一句JUMP form 401005,也就是CALL语句。由于缓冲区溢出和栈空间紧密相关,所以需要分析调用main函数前后,栈空间的情况。所以定位哪条语句调用了main函数。

使用Ctrl+X打开“交叉引用窗口”

image

跳转至jmp函数位置,发现并无Call语句,再次使用“交叉引用窗口”,发现Call语句,就是00401694调用main函数

5、返回OD中,并跳转至Call语句所在位置,0x00401694

image

0x00401694下面的语句地址为0x00401699,这条语句很重要,因为程序在进入每一个Call之前,都要先j将Call下面的语句入栈,然后才会执行Call语句。当Call语句执行完成后,程序再将这个地址出栈,这样就可以知道下一步该执行哪条命令,Call下面的地址也被称为“返回地址”

6、当前栈情况:

image

步入Call语句后,发现00401699已经入栈:(栈空间由下至上,由高地址往低地址走)

image

7、在程序中创建了一个8个字节大小的数组,因此进入main函数后需要为局部变量分配空间(程序采用Debug编译分配较大的空间,如果是Release编译则会分配正好的空间)

image

其中最后一行为返回地址,决定了当main函数执行完成后,程序要执行的语句的地址,而倒数第二行是父函数的EBP(扩展基址指针寄存器(extended base pointer) 其内存放一个指针,该指针指向系统栈最上面一个栈帧的底部。),在往上就是分配的局部变量空间。

8、当程序执行完0x00401026(0x0040DA36)后,分配的局部变量空间就被0xCC填满,原因是程序为了容错性和保持自身的健壮性,利用0xCC,也就是int 3断点填满变量空间,如果出现未知程序跳到这片区域,就不会出现崩溃的情况,而是被断下来。image

9、继续执行,查找反汇编代码strcpy函数的位置,即地址0x00401031执行strcpy函数前后差别:

image

image

栈中的地址0x0019FEE0位置处,保存的是strcpy第二个参数的地址,其内容是%s,也就是字符串“guangyu”。而栈中地址为0x0042001C,则是保存“guangyu”字符串的真实内存空间。

10、如果将strcpy的第一个参数改写成“guangyuguangyu”,程序会有什么不同使用OD运行至相同位置

image

可以看出,因为输入的字符串过长,使得原本位于栈中的0x0019FF40处的父函数EBP以及位于栈中的0x0019FF44处的返回地址全部被改写。原来位于0x0019FF44所保存的值为0x401699,告诉程序,执行完main函数后,执行该地址的命令。现在被改写后,变为0x00007579,即程序执行完main函数后,会跳转至0x00007579继续执行。

image

当main函数需要返回时,可以看到它要返回地址为0x007579,出现错误,继续执行,跳转至空白窗口,说明0x007579地址不存在指令,或者为无效地址。

image

缓冲区溢出的利用

1、在错误提示中,其中Code:0xc0000005,表示缓冲区溢出的错误。Address:0x0000000000007579,表示不存在的地址导致出现缓冲区溢出。其中,将地址0x007579转换成英文字符,则0x75表示”u”,0x79表示”y”,正好与输入的字符串的最后两个字符相同。

image

由于地址是由4个字节组成,那么对程序而言,如果将全局变量name赋值为guangyuguangXXXX,那么最后的四个”X”就正好覆盖了返回地址,而前面的12个字符可以是任意字符,也就解决了缓冲区漏洞利用的第一个问题——精确定位返回地址的位置。就这个程序而已,定义的局部变量buffer只有8个字节,而正常程序中如果缓冲区定义很大,简单方法可以使用:

TestCode[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"

利用26个英文大写字符和26个小写字符,一共52个字符进行测试,这样一次可以验证52个字节的缓冲区。

2、修改程序的缓冲区空间,修改为80字节。使用两次TestCode进行验证。

image

其中Address:0x6a696867,需要注意的是,Windows xp是小端显示,也就是说实际显示的字符应该是,0x6a、0x69、0x68、0x67。将其转换成对应的字符分别是g、h、i、j由于使用了两轮验证字符,第一轮是52个,加上第二轮的26个大写字母,就是78个,小写字母g前面有6个字符,就是84个字符,其中包含了4个字节的EBP,所以验证的缓冲区的大小就是80个字节。

PS:大端模式,是指数据的高字节保存在内存的低地址中,而数据的低字节保存在内存的高地址中,这样的存储模式有点儿类似于把数据当作字符串顺序处理:地址由小向大增加,而数据从高位往低位放;这和我们的阅读习惯一致。小端模式,是指数据的高字节保存在内存的高地址中,而数据的低字节保存在内存的低地址中,这种存储模式将地址的高低和数据位权有效地结合起来,高地址部分权值高,低地址部分权值低。

3、原理已经很明确了,现在需要确定的就是guangyuguangXXXX中最后四个”X”应该是什么地址。这个地址应该是基于合法地址的基础之上的。

其中最为经典的就是,jmp esp方法,也就是利用跳板进行跳转。这里的跳板是程序中原有的机器代码,它们都是能够跳转到一个寄存器内所存放的地址进行执行,如jmp、esp、call esp、jmp ecs、call eax等。如果函数在返回的时候,CPU内的寄存器刚好直接或间接指向ShellCode的开头,这样就可以把对栈内存放的放回地址的那一个元素覆盖为相应的跳板地址。

image

使用OD运行OverrunTest1,执行到main函数最后,即retn语句处,可以看到,现在esp中保存的值是0x0019FF44,而栈中的地址就是返回地址0x00401699,即下一条语句的位置。

4、此时已经跳出main函数,来到0x00401699位置处的语句进行执行,可以看到,esp的值由刚才的0x0019FF44变成了0x0019FF48,从栈空间来看,即刚才那个值的下一个位置。0x0019FF44位置是需要修改的返回地址的位置。

image

也就是说,当main函数执行完毕的时候,esp的值会自动变成返回地址的下一个位置,而esp的这种变化,一般是不受任何情况影响的。如果返回地址被破坏,esp会出现什么变化。

image

可以看到,esp中保存的地址是一样的,只是该地址中保存的值不同而已。

5、image

可见,除了反汇编代码窗口为空外,其他位置没有任何变法,esp的值依旧自增了4,在栈窗口看来,也就是到了返回地址下面的位置。

如何跳转到esp的位置:可以使用jmp esp这条指令,jmp esp的机器码是0xFFE4,那么可以编写一个程序,来在user32.dll中查找这条命令的地址。

6、运行程序,查找jmp esp

image

可以看到,这里列出很多结果,随便去一个用于实验,选择0x768635e9,也就是需要使用这个地址来覆盖程序的返回地址,这样,在程序返回时,就会执行jmp esp,从而跳到返回地址下一位置去执行该地址处的语句。也就是说,即将编写的”name”数组中的内容,其形式为guangyuguangXXXXSSSS…SSSS。其中前12个字符为任意字符,XXXX为返回地址,这里使用0x768635e9,而SSSS…SSSS则是具体想要计算机执行的代码。

总结一下,简单的说了一下什么是缓冲区,缓冲区是由于什么原因造成的,如何查找返回地址,如何替换返回地址,当我们成功找到以后,就可以使用jmp等类似的跳板,使程序跳转至想要的返回地址以及执行代码,综合来说,缓冲区溢出,就是通过这种方式,使其执行自己的代码,出现系统宕机等情况的。

小白一个,大佬勿喷。

关注我们

Tide安全团队正式成立于2019年1月,是以互联网攻防技术研究为目标的安全团队,目前聚集了十多位专业的安全攻防技术研究人员,专注于网络攻防、Web安全、移动终端、安全开发、IoT/物联网/工控安全等方向。

想了解更多Tide安全团队,请关注团队官网: http://www.TideSec.net 或关注公众号:

ewm.png

# 缓冲区溢出
本文为 独立观点,未经允许不得转载,授权请联系FreeBuf客服小蜜蜂,微信:freebee2022
被以下专辑收录,发现更多精彩内容
+ 收入我的专辑
+ 加入我的收藏
相关推荐
  • 0 文章数
  • 0 关注者