第网络攻击技术.ppt

上传人:本田雅阁 文档编号:2633105 上传时间:2019-04-25 格式:PPT 页数:266 大小:2.58MB
返回 下载 相关 举报
第网络攻击技术.ppt_第1页
第1页 / 共266页
第网络攻击技术.ppt_第2页
第2页 / 共266页
第网络攻击技术.ppt_第3页
第3页 / 共266页
亲,该文档总共266页,到这儿已超出免费预览范围,如果喜欢就下载吧!
资源描述

《第网络攻击技术.ppt》由会员分享,可在线阅读,更多相关《第网络攻击技术.ppt(266页珍藏版)》请在三一文库上搜索。

1、,第2章 网络攻击技术,指导教师:杨建国,2013年8月10日,2.1 信息收集技术 2.2 口令攻击 2.3 缓冲区溢出攻击 2.4 拒绝服务攻击 2.5 web应用安全攻击 2.6 恶意代码攻击 2.7 病毒蠕虫与木马攻击,第2章 网络攻击技术,2.8 网络欺骗攻击 2.9 网络钓鱼攻击 2.10 假消息攻击 2.11 网络协议攻击 2.12 操作系统攻击 2.13 远程控制攻击,2.3 缓冲区溢出攻击,信息收集必要性 信息收集的内容 信息收集的方式 信息收集的技术,缓冲区溢出攻击,第7章 缓冲区溢出攻击及防御技术,张玉清,国家计算机网络入侵防范中心,7,2019/4/25,网络入侵与防范

2、技术,6,本章内容安排,7.1 缓冲区溢出概述 7.2 缓冲区溢出原理 7.3 缓冲区溢出的过程 7.4 代码植入技术 7.5 实例:ida溢出漏洞攻击 7.6 缓冲区溢出的防御 7.7 小结,2019/4/25,网络入侵与防范技术,7,7.1 缓冲区溢出概述,什么是缓冲区?它是包含相同数据类型实例的一个连续的计算机内存块。是程序运行期间在内存中分配的一个连续的区域,用于保存包括字符数组在内的各种数据类型。 所谓溢出,其实就是所填充的数据超出了原有的缓冲区边界。 两者结合进来,所谓缓冲区溢出,就是向固定长度的缓冲区中写入超出其预告分配长度的内容,造成缓冲区中数据的溢出,从而覆盖了缓冲区周围的内

3、存空间。黑客借此精心构造填充数据,导致原有流程的改变,让程序转而执行特殊的代码,最终获取控制权。,2019/4/25,网络入侵与防范技术,8,7.1 缓冲区溢出概述,利用缓冲区溢出漏洞进行攻击最早可追溯到1988年Morris蠕虫,它所利用的就是fingerd程序的缓冲区溢出漏洞。 1989年,Spafford提交了一份分析报告,描述了VAX机上BSD版Unix的Fingerd的缓冲区溢出程序的技术细节,引起了一部分安全人士对这个研究领域的重视。 1996年,Aleph One发表了题为“Smashing the stack for fun and profit”的文章后,首次详细地介绍了Un

4、ix/Linux下栈溢出攻击的原理、方法和步骤,揭示了缓冲区溢出攻击中的技术细节。 1999年w00w00安全小组的Matt Conover写了基于堆缓冲区溢出专著,对堆溢出的机理进行了探索。,7.1 缓冲区溢出概述,Windows系统中缓冲区溢出的事例更是层出不穷。 2001年“红色代码”蠕虫利用微软IIS Web Server中的缓冲区溢出漏洞使300 000多台计算机受到攻击; 2003年1月,Slammer蠕虫爆发,利用的是微软SQL Server 2000中的缺陷; 2004年5月爆发的“振荡波”利用了Windows系统的活动目录服务缓冲区溢出漏洞; 2005年8月利用Windows

5、即插即用缓冲区溢出漏洞的“狙击波”被称为历史上最快利用微软漏洞进行攻击的恶意代码。 2008年底至2009年的Conficker蠕虫利用的是Windows处理远程RPC请求时的漏洞(MS08-067)。,2019/4/25,网络入侵与防范技术,10,7.1 缓冲区溢出概述,目前,利用缓冲区溢出漏洞进行的攻击已经占所有系统攻击总数的80%以上。 缓冲区溢出攻击之所以日益普遍,其原因在于各种操作系统和应用软件上存在的缓冲区溢出问题数不胜数,而其带来的影响不容小觑。 对缓冲区溢出漏洞攻击,可以导致程序运行失败、系统崩溃以及重新启动等后果。 更为严重的是,可以利用缓冲区溢出执行非授权指令,甚至取得系统

6、特权,进而进行各种非法操作。 如何防止和检测出利用缓冲区溢出漏洞进行的攻击,就成为防御网络入侵以及入侵检测的重点之一。,7.1 缓冲区溢出概述,与其他的攻击类型相比,缓冲区溢出攻击 不需要太多的先决条件 杀伤力很强 技术性强 缓冲区溢出比其他一些黑客攻击手段更具有破坏力和隐蔽性。这也是利用缓冲区溢出漏洞进行攻击日益普遍的原因。,2019/4/25,网络入侵与防范技术,11,2019/4/25,网络入侵与防范技术,12,7.1 缓冲区溢出概述,破坏性: 它极容易使服务程序停止运行,服务器死机甚至删除服务器上的数据。 隐蔽性: 首先,漏洞被发现之前,程序员一般是不会意识到自己的程序存在漏洞的(事实

7、上,漏洞的发现者往往并非编写者),于是疏于监测; 其次,被植入的攻击代码一般都很短,执行时间也非常短,很难在执行过程中被发现,而且其执行并不一定会使系统报告错误,并可能不影响正常程序的运行;,7.1 缓冲区溢出概述,隐蔽性: 第三,由于漏洞存在于防火墙内部的主机上,攻击者可以在防火墙内部堂而皇之地取得本来不被允许或没有权限的控制权; 第四,攻击的随机性和不可预测性使得防御变得异常艰难,没有攻击时,被攻击程序本身并不会有什么变化,也不会存在任何异常的表现; 最后,缓冲区溢出漏洞的普遍存在,针对它的攻击让人防不胜防(各种补丁程序也可能存在着这种漏洞。,7.2 缓冲区溢出原理,7.2.1 栈溢出 7

8、.2.2 堆溢出 7.2.3 BSS溢出 7.2.4 格式化串溢出,2019/4/25,网络入侵与防范技术,15,7.2 缓冲区溢出原理,当程序运行时,计算机会在内存区域中开辟一段连续的内存块,包括代码段、数据段和堆栈段三部分。,7.2 缓冲区溢出原理,程序在内存中的存放形式,7.2 缓冲区溢出原理,代码段(.text),也称文本段(Text Segment),存放着程序的机器码和只读数据,可执行指令就是从这里取得的。如果可能,系统会安排好相同程序的多个运行实体共享这些实例代码。这个段在内存中一般被标记为只读,任何对该区的写操作都会导致段错误(Segmentation Fault)。 数据段,

9、包括已初始化的数据段(.data)和未初始化的数据段(.bss),前者用来存放保存全局的和静态的已初始化变量,后者用来保存全局的和静态的未初始化变量。数据段在编译时分配。,7.2 缓冲区溢出原理,堆栈段分为堆和栈。 堆(Heap):位于BSS内存段的上边,用来存储程序运行时分配的变量。 堆的大小并不固定,可动态扩张或缩减。其分配由malloc()、new()等这类实时内存分配函数来实现。当进程调用malloc等函数分配内存时,新分配的内存就被动态添加到堆上(堆被扩张);当利用free等函数释放内存时,被释放的内存从堆中被剔除(堆被缩减)。 堆的内存释放由应用程序去控制,通常一个new()就要对

10、应一个delete(),如果程序员没有释放掉,那么在程序结束后操作系统会自动回收。,7.2 缓冲区溢出原理,栈(Stack)是一种用来存储函数调用时的临时信息的结构,如函数调用所传递的参数、函数的返回地址、函数的局部变量等。 在程序运行时由编译器在需要的时候分配,在不需要的时候自动清除。 栈的特性: 最后一个放入栈中的物体总是被最先拿出来,这个特性通常称为先进后出(FILO)队列。 栈的基本操作: PUSH操作:向栈中添加数据,称为压栈,数据将放置在栈顶; POP操作:POP操作相反,在栈顶部移去一个元素,并将栈的大小减一,称为弹栈。,堆和栈的区别,分配和管理方式不同 堆是动态分配的,其空间的

11、分配和释放都由程序员控制。 栈由编译器自动管理。栈有两种分配方式:静态分配和动态分配。静态分配由编译器完成,比如局部变量的分配。动态分配由alloca()函数进行分配,但是栈的动态分配和堆是不同的,它的动态分配是由编译器进行释放,无须手工控制。 产生碎片不同 对堆来说,频繁的new/delete或者malloc/free势必会造成内存空间的不连续,造成大量的碎片,使程序效率降低。 对栈而言,则不存在碎片问题,因为栈是先进后出的队列,永远不可能有一个内存块从栈中间弹出。 生长方向不同 堆是向着内存地址增加的方向增长的,从内存的低地址向高地址方向增长。 栈的生长方向与之相反,是向着内存地址减小的方

12、向增长,由内存的高地址向低地址方向增长。,2019/4/25,网络入侵与防范技术,21,7.2 缓冲区溢出原理,在这里,我们假设现在有一个程序, 它的函数调用顺序如下。 main() -; func_1() -; func_2() -; func_3() 即: 主函数main调用函数func_1; 函数func_1调用函 数func_2; 函数func_2调用函数func_3。 其详细结构图如下页图所示。,2019/4/25,网络入侵与防范技术,22,程序在内存中的影像,随着函数调用层数的增加,函数栈帧是一块块地向内存低地址方向延伸的。 随着进程中函数调用层数的减少,即各函数调用的返回,栈帧会

13、一块块地被遗弃而向内存的高址方向回缩。 各函数的栈帧大小随着函数的性质的不同而不等,由函数的局部变量的数目决定。 在缓冲区溢出中,我们主要关注数据区和堆栈区。,2019/4/25,网络入侵与防范技术,23,2019/4/25,网络入侵与防范技术,24,程序所使用的栈,在使用栈时,引用栈帧需要借助两个寄存器。 一个是SP(ESP),即栈顶指针,它随着数据入栈出栈而发生变化。 另一个是BP(EBP),即基地址指针,它用于标识栈中一个相对稳定的位置,通过BP,再加上偏移地址,可以方便地引用函数参数以及局部变量。,2019/4/25,网络入侵与防范技术,25,程序所使用的栈,函数被调用的时候,栈中的压

14、入情况如下:,Func函数中的局部变量,调用Func函数前的EBP,退出Func函数后的返回地址,传递给Func的实参,内存低地址,内存高地址,最先压入栈,最后压入栈,2019/4/25,网络入侵与防范技术,26,程序所使用的栈,在局部变量的下面,是前一个调用函数的EBP,接下来就是返回地址。 如果局部变量发生溢出,很有可能会覆盖掉EBP甚至RET(返回地址),这就是缓冲区溢出攻击的“奥秘”所在。,2019/4/25,网络入侵与防范技术,27,7.2 缓冲区溢出原理,如果在堆栈中压入的数据超过预先给堆栈分配的容量时,就会出现堆栈溢出,从而使得程序运行失败;如果发生溢出的是大型程序还有可能会导致

15、系统崩溃。,7.2.1 栈溢出,程序中发生函数调用时,计算机做如下操作:首先把指令寄存器EIP(它指向当前CPU将要运行的下一条指令的地址)中的内容压入栈,作为程序的返回地址(下文中用RET表示);之后放入栈的是基址寄存器EBP,它指向当前函数栈帧(stack frame)的底部;然后把当前的栈指针ESP拷贝到EBP,作为新的基地址,最后为本地变量的动态存储分配留出一定空间,并把ESP减去适当的数值。,7.2.1 栈溢出实例,我们来看一段简单程序的执行过程中对栈的操作和溢出的产生过程。 #include int main() char name16; gets(name); for(int i

16、=0;i16 ,2019/4/25,网络入侵与防范技术,30,7.2.1 栈溢出实例,编译上述代码,输入hello world! 结果会输出hello world! 在调用main()函数时,程序对栈的操作是这样的: 先在栈底压入返回地址 接着将栈指针EBP入栈,并把EBP修改为现在的ESP 之后ESP减16,即向上增长16个字节,用来存放name数组,2019/4/25,网络入侵与防范技术,31,7.2.1 栈溢出实例,现在栈的布局如图所示。,2019/4/25,网络入侵与防范技术,32,7.2.1 栈溢出实例,执行完gets(name)之后,栈中的内容如下图所示,2019/4/25,网络入

17、侵与防范技术,33,7.2.1 栈溢出实例,接着执行for循环,逐个打印name数组中的字符,直到碰到0x00字符 最后,从main返回,将ESP增加16以回收name数组占用的空间,此时ESP指向先前保存的EBP值。程序将这个值弹出并赋给EBP,使EBP重新指向main()函数调用者的栈的底部。然后再弹出现在位于栈顶的返回地址RET,赋给EIP,CPU继续执行EIP所指向的命令。 说明1:EIP寄存器的内容表示将要执行的下一条指令地址。 说明2:当调用函数时, Call指令会将返回地址(Call指令下一条指令地址)压入栈 Ret指令会把压栈的返回地址弹给EIP,2019/4/25,网络入侵与

18、防范技术,34,7.2.1 栈溢出实例,如果输入的字符串长度超过16个字节,例如输入:hello world!AAAAAAAA,则当执行完gets(name)之后,栈的情况如图所示。,2019/4/25,网络入侵与防范技术,35,7.2.1 栈溢出实例,由于输入的字符串太长,name数组容纳不下,只好向栈的底部方向继续写A。这些A覆盖了堆栈的老的元素,从上页图可以看出,EBP,Ret 都已经被A覆盖了。 从main返回时,就必然会把AAAA的ASCII码0x41414141视作返回地址,CPU会试图执行0x41414141处的指令,结果出现难以预料的后果,这样就产生了一次堆栈溢出。 在Wind

19、ows XP下用VC6.0运行程序,结果如下页图所示。,2019/4/25,网络入侵与防范技术,36,7.2.2 堆溢出,当我们需要较大的缓冲区或在写代码时不知道包含在缓冲区中对象的大小,常常要使用堆。 堆溢出的工作方式几乎与栈溢出的工作方式完全相同,唯一不同的是,堆没有压栈和入栈操作,而是分配和回收内存。 C语言中使用malloc()和free()函数实现内存的动态分配和回收,C+语言使用new()和delete()函数来实现相同的功能。,7.2.2 堆溢出实例,# include # include # include # include # define BUFFER-SIZE 16 #

20、 define OVERLAYSIZE 8 /* 我们将覆盖buf2 的前OVERLAYSIZE 个字节 */ int main() u-long diff ; char * buf1 = (char * )malloc (BUFFER-SIZE) ; char * buf2 = (char * )malloc (BUFFER-SIZE) ; diff = (u-long) buf2 - (u-long) buf1 ; printf (buf1 = %p , buf2 = %p , diff = 0x %x ( %d) bytes n, buf1 , buf2 , diff , diff) ;

21、 /* 将buf2 用a填充 */ memset (buf2 , a, BUFFER-SIZE - 1) , buf2BUFFER-SIZE - 1 = 0; printf (before overflow: buf2 = %s n, buf2) ; /* 用diff + OVERLAYSIZE 个b填充buf1 */ memset (buf1 , b, (u-int) (diff + OVERLAYSIZE) ) ; printf (after overflow: buf2 = %s n, buf2) ; return 0 ; ,7.2.2 堆溢出实例,运行结果: / users/ test

22、 41 % . / heap1 buf1 = 0x8049858 , buf2 = 0x8049870 , diff = 0x18 (24) bytes before overflow: buf2 = aaaaaaaaaaaaaaa after overflow: buf2 = bbbbbbbbaaaaaaa 我们看到,buf2的前八个字节被覆盖了,这是因为往buf1中填写的数据超出了它的边界进入了buf2的范围。由于buf2的数据仍然在有效的Heap区内,程序仍然可以正常结束。,7.2.2 堆溢出实例,虽然buf1和buf2是相继分配的,但它们并不是紧挨着的,而是有八个字节的间距。这是因为,

23、使用malloc()动态分配内存时,系统向用户返回一个内存地址,实际上在这个地址前面通常还有8字节的内部结构,用来记录分配的块长度、上一个堆的字节数以及一些标志等。这个间距可能随不同的系统环境而不同。buf1溢出后,buf2的前8字节也被改写为bbbbbbbb,buf2内部的部分内容也被修改为b。,7.2.2 堆溢出实例,示意图:,7.2.2 堆溢出,堆溢出不如栈溢出流行,原因在于 比栈溢出难度更大 需要结合其他的技术 对于内存中变量的组织方式有一定的要求,2019/4/25,网络入侵与防范技术,42,7.2.3 BSS溢出,.bss段存放全局和静态的未初始化变量,其分配比较简单,变量与变量之

24、间是连续存放的,没有保留空间。 下面这样定义的两个字符数组即是位于BSS段: static char buf116,buf216; 如果事先向buf2中写入16个字符A,之后再往buf1中写入24个B,由于变量之间是连续存放的,静态字符数组buf1溢出后,就会覆盖其相邻区域字符数组buf2的值。利用这一点,攻击者可以通过改写BSS中的指针或函数指针等方式,改变程序原先的执行流程,使指针跳转到特定的内存地址并执行指定操作。,7.2.4 格式化串溢出,与前面三种溢出不同的是,这种溢出漏洞是利用了编程语言自身存在的安全问题。格式化串溢出源自*printf()类函数的参数格式问题(如printf、fp

25、rintf、sprintf等)。 int printf (const char *format, arg1, arg2, ); 它们将根据format的内容(%s,%d,%p,%x,%n,),将数据格式化后输出。 问题在于:*printf()函数并不能确定数据参数arg1,arg2,究竟在什么地方结束,即函数本身不知道参数的个数,而只会根据format中打印格式的数目依次打印堆栈中参数format后面地址的内容。,7.2.4 格式化串溢出实例,/*程序说明: %#x:按16进制输出,并在前面加上0x %.20d:按10进制输出,输出20位,并在前面补0 %n:将显示内容的长度输出到一个变量中去

26、 */ # include main() int num= 0x61616161 ; printf (Before : num = %#x n, num) ; printf (%.20d %n n, num, ,7.2.4 格式化串溢出实例,当程序执行第二个printf语句时,参数压栈之后的内存布局如下:,7.2.4 格式化串溢出实例,根据C函数调用约定,参数从右向左依次压栈,所以参数&num比参数num先压入栈中。也就是说,程序中将&num (num的地址)压入栈作为printf()的第三个参数,而使用打印格式%n会将打印总长度保存到对应参数(&num)的地址中去,从而改变了num的值。 整

27、个程序的输出结果为: Before : num = 0x61616161 00000000001633771873 After : num = 0x14 变量num的值已经变成了0x14(20)。,7.2.4 格式化串溢出实例,如果将第二个printf语句修改为: printf (%.20d %n n, num) ; /注意,这里没有压num的地址入栈 则运行的结果为: Before : num= 0x61616161 Segmentation fault (core dumped) /执行第二个printf()时发生段错误了 原因:printf()将堆栈中main()函数的变量num当作了%

28、n所对应的参数,因此会将0x14保存到地址0x61616161中去,而0x61616161是不能访问的地址,因此系统提示发生段错误。如果可以控制num的内容,那么就意味着可以修改任意地址(当然是允许写入的地址)的内容。,2019/4/25,网络入侵与防范技术,49,7.2.4 格式化串溢出,在实际应用中,如果遇到脆弱的程序,将用户的输入错误地放在格式化串的位置,就会造成缓冲区溢出的攻击。 如果攻击者可以事先构造好可以攻击的代码shellcode,如果可以将返回地址覆盖成shellcode的起始地址,当缓冲区溢出发生后,程序就会跳到精心设计好的shellcode处执行,达到攻击的目的。,7.3

29、缓冲区溢出攻击的过程,7.3.1 在程序的地址空间安排适当代码 7.3.2 使控制流跳转到攻击代码,7.3 缓冲区溢出攻击的过程,缓冲区溢出攻击的目的在于扰乱某些工作在特殊权限状态下的程序,使攻击者取得程序的控制权,借机提高自己的权限,控制整个主机。 一般来说,攻击者要实现缓冲区溢出攻击,必须完成两个任务,一是在程序的地址空间里安排适当的代码;二是通过适当的初始化寄存器和存储器,让程序跳转到安排好的地址空间执行。,7.3.1 在程序地址空间安排适当代码,这一步骤也可以简称为植入代码的过程。 如果所需要的代码在被攻击程序中已经存在了,那么攻击者所要做的只是向代码传递一些参数,然后使程序跳转到目标

30、。 比如攻击代码要求执行“exec(/bin/sh)”,而在libc库中存在这样的代码“exec(arg)”,其中,arg是一个指向字符串的指针参数,那么,攻击者只要把传入的参数指针指向字符串“/bin/sh”,然后跳转到libc库中的相应的指令序列就OK了。,7.3.1 在程序地址空间安排适当代码,很多时候所需要的代码并不能从被攻击程序中找到,这就得用“植入法”来完成了。 构造一个字符串,它包含的数据是可以在被攻击程序的硬件平台上运行的指令序列,在被攻击程序的缓冲区如栈、堆或静态数据区等地方找到足够的空间存放这个字符串。然后再寻找适当的机会使程序跳转到其所安排的这个地址空间中。,7.3.2

31、将控制流转移到攻击代码,缓冲区溢出最关键的步骤就是寻求改变程序执行流程的方法,扰乱程序的正常执行次序,使之跳转到攻击代码。原则上来讲,攻击时所针对的缓冲区溢出的程序空间可以为任意空间,但因不同地方程序空间的突破方式和内存空间的定位差异,也就产生了多种转移方式。 Function Pointers(函数指针) Activation Records(激活记录) Longjmp buffers(长跳转缓冲区),Function Pointers(函数指针),函数指针:void (* foo) ()声明了一个返回值为void 类型的函数指针变量foo。 函数指针可以用来定位任意地址空间,攻击时只需要在

32、任意空间里的函数指针邻近处找到一个能够溢出的缓冲区,然后用溢出来的数据改变函数指针的值。当程序使用函数指针调用函数时,程序的流程就会指向攻击者定义的指令序列。,用函数指针控制程序流程图示,2019/4/25,网络入侵与防范技术,56,Activation Records(激活记录),当一个函数调用发生时,堆栈中会留驻一个Activation Record,它包含了函数结束时返回的地址。溢出这一记录,使这个返回地址指向攻击代码,当函数调用结束时,程序就会跳转到所设定的地址,而不是原来的地址。 这样的溢出方式比较常见。,用活动记录控制程序流程图示,2019/4/25,网络入侵与防范技术,58,Lo

33、ngjmp buffers(长跳转缓冲区),在C语言中包含了一个简单的检验/恢复系统,称为setjmp/longjmp,在检验点设定setjmp(buffer),用longjmp(buffer)来恢复检验点。 和函数指针一样,longjmp(buffer)能够跳转到buffer中信息所指向的任何地方。如果攻击者能够修改buffer的内容,使用longjmp(buffer)就可以跳转到攻击代码。 使用这种方法,需要先找到一个可供溢出的缓冲区,2019/4/25,网络入侵与防范技术,60,植入代码和流程控制的综合,常见的缓冲区溢出攻击是溢出字符串综合使用了代码植入和Activation Recor

34、ds改写技术。 攻击者定位在一个可供溢出的局部变量,然后向程序传递一个设计好的长字符串,在引发缓冲区溢出改变Activation Records的同时植入代码。 即用一个长字符串完成代码植入并覆盖函数的返回地址。 示意图见下面。,植入代码和流程控制的综合图示,2019/4/25,网络入侵与防范技术,61,7.4 代码植入技术,7.4.1 shellcode 7.4.2 返回地址 7.4.3 填充数据 7.4.4 植入代码的构造类型 7.4.5 shellcode使用示例,7.4 代码植入技术,所植入的代码一般由shellcode、返回地址、填充数据这三种元素按照一定的结构和构造类型组成 什么是

35、shellcode 是植入代码的核心组成部分,是一段能完成特殊任务的自包含的二进制代码。 由于它最初是用来生成一个高权限的shell,因此而得名。虽然现在人们已经远远不满足于生成一个shell,但shellcode的“美名”一直延用至今。 攻击者通过巧妙的编写和设置,利用系统的漏洞将shellcode送入系统中使其得以执行,从而获取特殊权限的执行环境,或给自己设立有特权的帐户,取得目标机器的控制权。,7.4.1 shellcode,除了经典的利用exec()系统调用执行/bin/sh获取shell之外,下表列出了Unix/Linux系统中的shellcode经常用到的一些其它系统调用。,7.4

36、.1 shellcode,在linux中,为了获得一个交互式shell,一般需要执行代码execve(“/bin/sh”, “/bin/sh”, NULL); 对此代码进行编译后得到机器码。 char shellcode = “xebx1fx5ex89x76x08x31xc0x88x46x07x89x46x0cxb0x0bx89xf3x8dx4ex08x8dx56x0cxcdx80x31xdbx89xd8x40xcdx80xe8xdcxffxffxff/bin/sh”; 注意:不同的操作系统、不同的机器硬件产生系统调用的方法和参数传递的方法也不尽相同。,7.4.2 返回地址,返回地址是指she

37、llcode的入口地址。攻击者如果希望目标程序改变其原来的执行流程,转而执行shellcode,则必须设法用shellcode的入口地址覆盖某个跳转指令。 由于所植入的代码是被复制到目标机器的缓冲区中,攻击者无法知道其进入到缓冲区后的确切地址。不过,内存的分配是有规律的,如Linux系统,当用户程序运行时,栈是从0xbfffffff开始向内存低端生长的。如果攻击者想通过改写函数返回地址的方式使程序指令发生跳转,则程序指令跳转后的指向也应该在0xbfffffff附近。 事实上,虽然不同的缓冲区溢出漏洞,其植入代码的返回地址都不同,但均处于某个较小的地址区间内。另外,为了提高覆盖函数返回地址的成功

38、率,往往在植入代码中安排一段由重复的返回地址组成的内容。,7.4.3 填充数据,由于攻击者不能准确地判断shellcode的入口地址,因此为了提高shellcode的命中率,往往在shellcode的前面安排一定数量的填充数据。 填充数据必须对植入代码的功能完成没有影响,这样只要返回地址指向填充数据中的任何一个位置,均可以确保shellcode顺利执行。 填充数据还可以起到一个作用,就是当植入代码的长度够不着覆盖目标如函数返回地址时,可以通过增加填充数据的数量,使植入代码的返回地址能够覆盖函数返回地址。,7.4.3 填充数据,对于Intel CPU来说,填充数据实质上是一种单字节指令,使用得最

39、多的是空操作指令NOP,其值为0x90,该指令什么也不做,仅跳过一个CPU周期。除此之外,还有其他的单字节指令可以作为填充数据使用,如调整计算结果的AAA和AAS、操作标志位的CLC和CLD等。 在植入代码中,往往安排比较长甚至几百上千的填充数据,而一个有效的指令长度实际最大也不过10字节左右,因此,也可以根据这一特点来判断是否发生了缓冲区溢出攻击。,7.4.4 植入代码的构造类型,所植入的代码是由黑客精心构造的,而由于缓冲区溢出自身的特性,它的结构和构造类型有一定的特性。 NSR模式 RNS模式 AR模式 其中, S代表shellcode, R代表返回地址, N代表填充数据, A表示环境变量

40、。,2019/4/25,网络入侵与防范技术,70,NSR模式,NSR模式,在shellcode的后面安排一定数量的返回地址,在前面安排一定数量的填充数据,这种结构称为NSR型,或前端同步型。 原理是:只要全部的N和S都处于缓冲区内,并且不覆盖RET,而使R正好覆盖存放RET的栈空间,这样只要将R的值设置为指向N区中任一位置,就必然可以成功地跳转到我们预先编写的shellcode处执行。,2019/4/25,网络入侵与防范技术,71,2019/4/25,网络入侵与防范技术,72,NSR模式,这是一种经典结构,适合于溢出缓冲区较大、足够放下我们的shellcode的情况。 这是一种非精确定位的方法

41、,N元素越多成功率越大,其缺点是缓冲区必须足够大,否则shellcode放不下或者N元素数量太少都会造成失败。,RNS模式,2019/4/25,网络入侵与防范技术,73,RNS模式,其原理是:只要把整个缓冲区全部用大量的返回地址填满,并且保证会覆盖存放RET的栈空间,再在后面紧接N元素和shellcode,这样就可以很容易地确定返回地址R的值,并在植入代码中进行设置。 这里填充的R的数目必须能够覆盖ret,R的值必须指向大量N中的任何一个。 这种方法对大的和小的缓冲区都有效。而且RET地址较容易计算。,2019/4/25,网络入侵与防范技术,74,AR模式,AR模式,又称环境变量型。这种构造类

42、型不同于NSR型和RNS型,它必须事先将shellcode放置在环境变量中,然后将shellcode的入口地址和填充数据构成植入代码进行溢出攻击。 这种构造类型对于大、小溢出缓冲区都适合。但由于必须事先将shellcode放置到环境变量中,故其应用受到了限制,只能用于本地而不能用于远程攻击。,缓冲区溢出攻击的三步曲,从上面的分析可知,不管哪种类型的缓冲区溢出攻击,一般都存在下面三个步骤: 构造需要执行的代码shellcode,并将其放到目标系统的内存。 获得缓冲区的大小和定位溢出点ret的位置。 控制程序跳转,改变程序流程。 具体如何完成这三个攻击步骤将在实验课中介绍。,2019/4/25,网

43、络入侵与防范技术,77,2019/4/25,网络入侵与防范技术,78,7.4.5 shellcode使用示例,下面通过一个例子说明栈溢出是如何产生的、以及如何利用它来执行精心安排的shellcode:,Vul-func (char * buf-src) char buf-dest 16 ; strcpy(buf-dest , buf-src) ; main() int i ; char str256 ; for (i = 0 ; i 256 ; i + + ) str i = a; Vul-func (str); ,2019/4/25,网络入侵与防范技术,79,7.4.5 shellcode使

44、用示例,显然,数组str的大小(256 字节) 远远超过了目的缓冲区buf- dest 的大小(16 字节) ,发生了缓冲区溢出。 调用函数Vul-func 前后,堆栈使用情况如下页图所示。,2019/4/25,网络入侵与防范技术,80,7.4.5 shellcode使用示例,2019/4/25,网络入侵与防范技术,81,7.4.5 shellcode使用示例,从上页图可以看出,Vul-func 函数调用完成后,str数组的内容(256个字母a即0x616161 )已经覆盖了从地址buf-dest到地址buf-dest + 256 内存空间原来所有的内容,包括调用函数Vul-func时保存的E

45、BP和返回地址RET。 这样,函数返回时就返回到地址0x61616161,发生错误。缓冲区溢出使得程序执行的流程发生了变化。,2019/4/25,网络入侵与防范技术,82,7.4.5 shellcode使用示例,如果能在返回地址RET处写入一段精心设计好的攻击代码的首地址,系统就会转去执行攻击代码,从而被攻破。 如要获得一个shell,可以安排执行如下代码:execve(“/bin/sh”, “/bin/sh”, NULL),2019/4/25,网络入侵与防范技术,83,7.4.5 shellcode使用示例,将这段代码进行反汇编,就获得了一个交互式shell的shellcode。只需将函数的

46、返回地址RET 覆盖为此shellcode 的首地址即可获得一个shell: char shellcode= “xebx1fx5ex89x76x08x31xc0x88x46x07x89x46x0cxb0x0b” “x89xf3x8dx4ex08x8dx56x0cxcdx80x31xdbx89xd8x40xcd” “x80xe8xdcxffxffxff/bin/sh”;,7.4.5 shellcode使用示例,为了说明如何使用shellcode以及如何精心安排溢出字符串,下面举个例子来说明。 通过运行下面的代码,就能获得一个shell,当然,这个程序只具有实验目的,不具有攻击性。 详细的攻击实例

47、将在实验课中介绍。,2019/4/25,网络入侵与防范技术,84,2019/4/25,网络入侵与防范技术,85,7.4.5 shellcode使用示例,Return add,Buffer (96bytes),i,long_ptr,高地址,低地址,Para2,Para1,EBP,char shellcode = (前面的shellcode) char large-string128; void main(int argc, char *argv) char buffer96; int i; long * long-ptr = (long * )large-string; /* 用buffer的首

48、地址填满large-string */ for(i=0;i32;i+)*(long-ptr+i)=(int)buffer; /* 将shellcode填入large-string的前面部分 */ for(i=0;istrlen(shellcode);i+) large-stringi = shellcodei; strcpy(buffer ,large-string); ,shellcode,2019/4/25,网络入侵与防范技术,86,7.4.5 shellcode使用示例,这是一个利用栈溢出的程序。当strcpy 函数调用返回时,其返回地址RET已被修改为buffer 的首地址,而该地址正

49、好存放的是shellcode。 于是,shellcode被执行,成功获得一个交互式shell。这是由于strcpy执行时不进行边界检查所致。,2019/4/25,网络入侵与防范技术,87,7.4.5 shellcode使用示例,以上说明的是攻击我们自己的程序的原理。实际上,被攻击程序的代码及其缓冲区地址对攻击者来说是未知的,这就增加了攻击的难度。 一个有效地解决这个问题的办法是使用NSR模式,下面介绍NSR模式在此例中的应用。,2019/4/25,网络入侵与防范技术,88,7.4.5 shellcode使用示例,首先,用猜测的buffer地址填充整个large- string; 然后,把shellcode 放置在large-string 的中部,前部用空指令NOP填充;再将large-string 的内容放入注入到带有缓冲区溢出隐患的程序,就可能获得一个shell。前部填充的N

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 其他


经营许可证编号:宁ICP备18001539号-1