您好,欢迎访问三七文档
第五章缓冲区溢出攻击5第五章缓冲区溢出攻击5.1缓冲区溢出程序的原理及要素5.2攻击UNIX5.3缓冲区溢出攻击概述55.4攻击Windows•缓冲区溢出是一种非常普遍、非常危险的漏洞,在各种操作系统、应用软件中广泛存在。利用缓冲区溢出攻击,可以导致程序运行失败、系统宕机、重新启动等后果。更为严重的是,可以利用它执行非授权指令,甚至可以取得系统特权,进而进行各种非法操作。5.1缓冲区溢出攻击概述•缓冲区溢出攻击有多种英文名称:bufferoverflow,bufferoverrun,smashthestack,trashthestack,scribblethestack,manglethestack,memoryleak,overrunscrew;它们指的都是同一种攻击手段。•第一个缓冲区溢出攻击—Morris蠕虫,发生在1988年,它曾造成了全世界6000多台网络服务器瘫痪。5.1缓冲区溢出攻击概述缓冲区溢出攻击概述•历史上最著名的例子–1988年,美国康奈尔大学的计算机科学系研究生、23岁的莫里斯利用Unixfingerd程序不限制输入长度的漏洞,输入512个字符后使缓冲器溢出,同时编写一段特别大的恶意程序能以root(管理员)身份执行,并感染到其他机器上。–它造成全世界6000多台网络服务器瘫痪。参考:://en.wikipedia.org/wiki/Blaster_%28computer_worm%295.1–1996•AlephOne,SmashingtheStackforFunandProfit,Phrack49–1998•Dildog:提出利用栈指针的方法完成跳转•TheTaoofWindowsBufferOverflows–1999•DarkSpyrit:提出使用系统核心DLL中的JmpESP指令完成跳转,Phrack55•M.Conover:基于堆的缓冲区溢出教程5.1缓冲区溢出攻击概述–2001年始,微软的IIS5.0一系列的漏洞被发现,其中不少漏洞是由于Unicode的处理问题造成的,在攻击利用的时候与Windows所支持的语言字符集密切相关。(《Widechar的字符串缓冲区溢出攻击技术》)–2003年8月引起全球轰动的“冲击波”病毒及变种,也是利用WindowsRPC服务的缓冲区溢出漏洞来进行传播的。–2004年5月的“震荡波”病毒及变种也是利用了Windows系统的缓冲区漏洞。–目前5.1缓冲区溢出攻击概述缓冲区溢出攻击概述•定义–缓冲区溢出攻击是一种通过往程序的缓冲区写超出其长度的内容,造成缓冲区溢出,从而破坏程序的堆栈,使程序转而执行其他预设指令,以达到攻击目的的攻击方法。•分类–基于堆栈的缓冲区溢出(栈溢出)–基于堆/BSS的缓冲区溢出–整数溢出5.1缓冲区溢出程序原理及要素•缓冲区溢出程序的原理–众所周知,C语言不进行数组的边界检查。–在许多C语言实现的应用程序中,都假定缓冲区的长度是足够的,即它的长度肯定大于要拷贝的字符串的长度。事实并非如此5.2缓冲区溢出程序原理及要素5.2例1:#includestdio.hvoidfunction(char*str){charbuffer[9];strcpy(buffer,str);}voidmain(){char*input=1234567890;function(input);}缓冲区溢出程序原理及要素5.2例2:#includestdio.hintmain(){charname[8];printf(pleasetypeyourname:);gets(name);printf(hello,%s!,name);return0;}•在C语言中,指针和数组越界不保护是Bufferoverflow的根源。•在C语言标准库中存在像strcpy,gets这样问题的标准函数还有strcat(),sprintf()和scanf()等。•要透彻地理解这种攻击方式,需要计算机体系架构方面的基础知识,理解CPU、寄存器、内存是怎样协同工作而让程序流畅执行的。5.2缓冲区溢出程序原理及要素缓冲区溢出程序原理及要素•缓冲区溢出攻击背景知识与技巧–进程内存空间结构–汇编语言基本知识–栈的基本结构–函数调用过程–编译器5.2进程内存空间结构•根据不同的操作系统,一个进程可能被分配到不同的内存区域去执行。但是不管什么样的操作系统、什么样的计算机架构,进程使用的内存都可以按照功能大致分成以下4个部分:–代码区:这个区域存储着被装入执行的二进制机器代码,处理器会到这个区域取指并执行。–数据区:用于存储全局变量等。进程内存空间结构•堆区:进程可以在堆区动态地请求一定大小的内存,并在用完之后归还给堆区。•栈区:用于动态地存储函数之间的调用关系,以保证被调用函数在返回时恢复到调用函数中继续执行。Linux进程内存空间结构17Linux进程内存空间•Highestzone(0xc0000000-3G)–进程环境参数:envstrings&pointers–进程参数:argvstrings&pointers,argc•栈–存储函数参数、本地参数和栈状态变量(返回地址,…)–LIFO,向低地址增长•堆–动态分配变量(malloc)–向高地址增长•.bss:uninitializeddata•.data:staticinitializeddata•.text(0x80000000):指令,只读数据Win32进程内存空间19Win32进程内存空间•系统核心内存区间–0xFFFFFFFF~0x80000000(4G~2G)–为Win32操作系统保留•用户内存区间–0x00000000~0x80000000(0G~2G)–堆:动态分配变量(malloc),向高地址增长–静态内存区间:全局变量、静态变量–代码区间:从0x00400000开始–栈:向低地址增长•单线程进程:(栈底地址:0x0012FFXXXX)–多线程进程拥有多个堆/栈汇编语言基础知识-寄存器汇编语言基础知识-汇编指令22栈的基本结构•栈-LIFO抽象数据结构–用于实现函数或过程调用•相关寄存器–BP(BasePointer)=FP(FramePointer):当前栈底指针–SP(StackPointer):当前栈顶指针•相关操作–PUSH:压栈–POP:弹栈23函数调用过程•函数调用过程的三个步骤–prologue:保存当前的栈基址(ebp).–call:调用参数和返回地址(eip)压栈,跳转到函数入口–return(orepilogue):恢复调用者原有栈函数调用示例intfunc_B(intarg_B1,intarg_B2){intvar_B1,var_B2;var_B1=arg_B1+arg_B2;var_B2=arg_B1-arg_B2;returnvar_B1*var_B2;}intfunc_A(intarg_A1,intarg_A2){intvar_A;var_A=func_B(arg_A1,arg_A2)+arg_A1;returnvar_A;}intmain(intargc,char**argv){intvar_main;var_main=func_A(4,3);returnvar_main}这段代码编译后,各个函数对应的机器指令在代码区中可能是这样分布的(我们可以简单地把它们在内存代码区中的分布位置理解成是散乱无关的)。25GCC编译器基础•最著名的GNU的Ansic/c++编译器–gcc[options][filenames]–编译:gcc-ctest.c生成test.o–连接:gcc-otesttest.o–同时搞定:gcctest.c-otest•make:用于控制编译过程–MakefileHowTo26GDB调试器的使用•断点相关指令–break/clear,disable/enable/delete–watch–表达式值改变时,程序中断•执行相关指令–run/continue/next/step–attach–调试已运行的进程–finish/return•信息查看相关指令–inforeg/break/files/args/frame/functions/…–backtrace–函数调用栈–print/fexp–显示表达式的值–x/nfuaddr–显示指定内存地址的内容–list–列出源码–disassfunc–反汇编指定函数27VC6.0命令行•环境变量–我的电脑-属性-高级-环境变量–PATH:•C:\ProgramFiles\MicrosoftVisualStudio\VC98\Bin;•C:\ProgramFiles\MicrosoftVisualStudio\Common\MSDev98\Bin;–INCLUDE:•C:\ProgramFiles\MicrosoftVisualStudio\VC98\Include–LIB:•C:\ProgramFiles\MicrosoftVisualStudio\VC98\Lib•命令行指令–clsourcefilename–编译并链接28Win32平台调试器•OllyDbg1.10汉化版–32-bitassemblerlevelanalysingdebuggerbyOlehYuschuk–Free–支持插件机制•OllyUni:查找跳转指令功能•Softice•IDAPro•我们用gcc-S来获得汇编语言输出,可以看到main函数的开头部分对应如下语句:•pushl%ebp•movl%esp,%ebp•subl$8,%esp•首先把EBP保存下来,然后EBP等于现在的ESP,这样EBP就可以用来访问本函数的局部变量。•之后ESP减8,就是堆栈向上增长8个字节,用来存放name[]数组。现在堆栈的布局如下:•由于我们输入的name字符串太长,name数组容纳不下,只好向内存顶部继续写‘A’。•由于堆栈的生长方向与内存的生长方向相反,这些‘A’覆盖了堆栈的老的元素。•EBP,ret都已经被‘A’覆盖了。•在main返回的时候,就会把‘AAAA’的ASCII码:0x41414141作为返回地址,CPU会试图执行0x41414141处的指令,结果出现错误,这就是一次堆栈溢出。缓冲区溢出程序原理及要素•前面的例子中,只是随便往缓冲区填入过长的数据造成它溢出,越界的数据破坏了栈中相邻变量的值,甚至破坏栈帧中所保存的EBP值、返回地址等重要数据,一般只会导致程序出错并终止。但是不能达到攻击的目的。•如果想要利用缓冲区溢出的漏洞进行攻击又该怎么办呢?缓冲区溢出程序原理及要素•第一种方法:–通过溢出改写邻接变量,导致程序流程发生改变。–这种漏洞利用方法对代码环境的要求相对比较苛刻。–例子:突破密码验证程序。#includestdio.h#definePASSWORD1234567intverify_password(char*password){intauthenticated;charbuffer[8];//addlocalbufftobeoverflowedauthenticated=strcmp(password,PASSWORD);strcpy(buffer,password);//overflowedhere!returnauthenticated;}voidmain(){intvalid_flag=0;charpassword[1024];while(1){printf(pleaseinputpassword:);scanf(%s,password);valid_flag=verify_password(password);if(valid_flag){printf(incorrectpassword!\n\n);}else{printf(Congratulation!Youhavepassedtheverification!\n);
本文标题:网络安全第五讲
链接地址:https://www.777doc.com/doc-1794666 .html