网络攻击与防御课程设计.docx
- 文档编号:25610305
- 上传时间:2023-06-10
- 格式:DOCX
- 页数:23
- 大小:266.16KB
网络攻击与防御课程设计.docx
《网络攻击与防御课程设计.docx》由会员分享,可在线阅读,更多相关《网络攻击与防御课程设计.docx(23页珍藏版)》请在冰豆网上搜索。
网络攻击与防御课程设计
甘肃政法学院
本科课程设计(设计)
题目缓冲区溢出攻击的原理分析及防范
计算机科学院院(系)计算机科学与技术专业09级计本一班
学号************
姓名李磊
指导教师武光利
成绩
完成时间年月
缓冲区溢出攻击的原理分析及防范
【摘要】:
利用缓冲区溢出漏洞进行攻击自诞生以来始终是网络攻击常用的手段,对信息安全危害极大。
如何检测缓冲区溢出成为研究的一个热点,并涌现出了各种各样的方案。
本次课程设计的目的旨在分析攻击的原理及防范措施。
关键字:
:
缓冲区溢出;漏洞;攻击;权限
Abstract:
Utilizationofbufferoverflowattackssincethebirthisalwaysthenetworkattackmeansusedforinformationsecurity,greatharm.Howtodetectbufferoverflowhasbecomearesearchhotspot,andemergedinavarietyofprogrammes.Thepurposeofthecurriculumdesignisaimedattheanalysisoftheattackprincipleandpreventionmeasures.
Keywords:
Bufferoverflow;Loophole;Attack;Jurisdiction
缓冲区溢出攻击的原理分析及防范
第一章引言
目前我国互联网已经进入宽带时期,网络用户和网络资源持续增长。
但是,互联网的开放性、商业化和应用系统的复杂性带来的安全风险也随之增加,各种安全漏洞的大量存在并不断攀升仍是网络安全的最大隐患,即使计算机系统装上了防火墙和防病毒软件,但遗憾的是系统本身的漏洞难以避免。
近年由CERT/CC发布的系统安全忠告中关于缓冲区溢出(又称堆栈溢出)漏洞占56.76%以上。
缓冲区溢出可以让普通用户通过运行一个“错误”的程序,来使系统运行只有在超级管理员环境下才能运行的程序。
一旦系统存在着缓冲区溢出漏洞,系统就有可能被黑客完全控制。
所以,缓冲区溢出漏洞是致命的。
缓冲区溢出攻击之所以成为一种常见的攻击手段,其原因在于缓冲区溢出漏洞太普通了,并且易于实现。
而且,缓冲区溢出所以成为远程攻击的主要手段,其原因在于缓冲区溢出漏洞给予了攻击者所想要的一切:
植入并且执行攻击代码。
被植入的攻击代码以一定的权限运行有缓冲区溢出漏洞的程序,从而得到被攻击主机的控制权。
本文简单介绍了缓冲区溢出的基本原理及本文讲述了漏洞的基本概念,并列述了漏洞的分类。
漏洞的种类繁多,主要就缓冲区漏洞的软件编写存在bug、系统配置不当、口令失窃、明文通讯信息被监听以及初始设计存在缺陷等方面作了简单的介绍。
本次课程设计的目的旨在分析攻击的原理及防范措施。
第二章系统漏洞
2.1漏洞的概念
漏洞也叫脆弱性,是在硬件、软件、协议的具体实现或系统安全策略上存在的缺陷。
从而可以使攻击者能够在未授权的情况下访问或破坏系统。
这些缺陷被非法用户利用,可以突破系统的审计和访问控制等安全机制,对系统及其承载数据的完整性、保密性和可用性造成威胁。
漏洞会影响到很大范围的软硬件设备,包括系统本身及其支撑软件、网络客户和服务器软件、网络路由器和安全防火墙等,即在不同的软硬件设备中都可能存在不同的安全漏洞问题。
漏洞无处不在,入侵者只要找到复杂的计算机网络中的一个漏洞,就能轻而易举地闯入系统。
所以,了解这些漏洞都有可能在哪里,对于修补它们至关重要。
通常,漏洞主要表现在软件编写存在bug、系统配置不当、口令失窃、明文通讯信息被监听以及初始设计存在缺陷等方面。
2.2漏洞的分类
2.2.1系统配置不当
(1)默认配置的不足:
许多系统安装后都有默认的安全配置信息,通常被称为easytouse。
但遗憾的是,easytouse还意味着easytobreakin。
所以,一定对默认配置进行扬弃的工作。
(2)管理员懒散:
懒散的表现之一就是系统安装后保持管理员口令的空值,而且随后不进行修改。
要知道,入侵者首先要做的事情就是搜索网络上是否有这样的管理员为空口令的机器。
(3)临时端口:
有时候为了测试,管理员会在机器上打开一个临时端口,但测试完后却忘记了禁止,这样就会给入侵者有洞可寻、有漏可钻。
通常的解决策略是:
除非一个端口是必须使用的,否则禁止它。
一般情况下,安全审计数据包可用于发现这样的端口并通知管理者。
(4)信任关系:
网络间的系统经常建立信任关系以方便资源共享,但这也给入侵者有可趁之机、间接攻击的可能,例如,只要攻破信任群中的一个机器,就有可能进一步攻击其他的机器。
所以,要对信任关系严格审核、确保真正的安全联盟。
2.2.2口令失窃
(1)弱不禁破的口令:
就是说虽然设置了口令,但是非常简单,入侵者可以轻而易举的攻破。
(2)字典攻击:
就是指入侵者使用一个程序,该程序借助一个包含用户名和口令的字典数据库,不断地尝试登录系统,直到成功进入。
毋庸置疑,这种方式的关键在于有一个好的字典。
(3)暴力攻击:
与字典攻击类似,但这个字典却是动态的,就是说,字典包含了所有可能的字符组合。
例如,一个包含大小写的4字符口令大约有50万个组合,1个包含大小写且标点符号的7字符口令大约有10万亿组合。
对于后者,一般的计算机要花费大约几个月的时间才能试验一遍。
2.2.3嗅探未加密通讯数据
(1)共享介质:
传统的以太网结构很便于入侵者在网络上放置一个嗅探器就可以查看该网段上的通讯数据,但是如果采用交换型以太网结构,嗅探行为将变得非常困难。
(2)服务器嗅探:
交换型网络也有一个明显的不足,入侵者可以在服务器上特别是充当路由功能的服务器上安装一个嗅探器软件,然后就可以通过它收集到的信息闯进客户端机器以及信任的机器。
例如,虽然不知道用户的口令,但当用户使用Telnet软件登录时就可以嗅探到他输入的口令了。
(3)远程嗅探:
许多设备都具有RMON,远程监控功能以便管理者使用公共体字符串进行远程调试。
随着宽带的不断普及,入侵者对这个后门越来越感兴趣了。
2.2.4设计存在的缺陷
(1)TCP/IP协议的缺陷:
TCP/IP协议现在已经广为应用、但是它设计时却是在入侵者猖狂肆虐的今天之很早以前设计出来的。
因此,存在许多不足造成安全漏洞在所难免,例如smurf攻击、ICMPUnreachable数据包断开、IP地址欺骗以及SYNflood。
然而,最大的问题在于IP协议是非常容易“轻信”的,就是说入侵者可以随意地伪造及修改IP数据包而不被发现。
现在Ipsec协议已经开发出来以克服这个不足,但还没有得到广泛的应用。
2.2.5软件编写存在bug
无论是服务器程序、客户端软件还是操作系统,只要是用代码编写的,都会存在不同程度的Bug。
Bug主要分为以下几类:
(1)缓冲区溢出:
指入侵者在程序的有关输入项目中了输入了超过规定长度的字符串,超过的部分通常就是入侵者想要执行的攻击代码,而程序编写者又没有进行输入长度的检查,最终导致多出的攻击代码占据了输入缓冲区后的内存而执行。
(2)意料外的联合使用问题:
一个程序经常由功能不同的多层代码组成,甚至会涉及到最底层的操作系统级别。
入侵者通常会利用这个特点为不同的层输入不同的内容,以达到窃取信息的目的。
(3)不对输入内容进行预期检查:
有些编程人员工作不负责任,对输入内容不进行预期的匹配检查,使入侵者输送炸弹的工作变得非常简单。
(4)Raceconditions:
多任务多线程的程序越来越多,在提高运行效率的同时,也要注意Raceconditions的问题。
比如说:
程序A和程序B都按照“读/改/写”的顺序操作一个文件,当A进行完读和改的工作时,B启动立即执行完“读/改/写”的全部工作,这时A继续执行写工作,结果是A的操作没有了表现。
入侵者就可能利用这个处理顺序上的漏洞改写某些重要文件从而达到闯入系统的目的,所以,编程人员要注意文件操作的顺序以及锁定等问题。
第三章本地缓冲区溢出的原理及实现
3.1缓冲区的概念
缓冲区,又称中立区、中立地带等,指的是两地的交界处因为战争或其他因素,而划定出的带状地区,此带状地区并不完全属于两方之中的一方,通常由两方共管或是由第三方协助管理。
缓冲区是地理空间目标的一种影响范围或服务范围,具体指在点、线、面实体的周围,自动建立的一定宽度的多边形。
缓冲区溢出的根本原因在于语言本身的一些特性。
从数据结构的角度来说,最根本的原因是由于指针、数组的存在,导致了一系列存储操作上的问题。
而直接的原因则是“没有对数组的越界加以监视和限制”。
程序编写者的经验不足或粗心大意使得缓冲区溢出几乎无处不在,导致程序不够健壮,为缓冲区溢出攻击留下了隐患。
缓冲区溢出攻击利用了程序设计语言的安全缺陷,及程序员编写代码时的疏漏,将特定的内容写到缓冲区以外的特定内存空间,以达到控制或破坏系统的目的。
同时也得满足以下几个条件:
(1)缓冲区溢出,首先要有一个缓冲区,当然不是所有的缓冲区都可以,要求是一块有固定大小的缓冲区,而且还要向这块缓冲区中拷贝数据。
(2)在程序中存在不规范,不安全的代码,这是发生缓冲区溢出攻击最主要的前提条件。
黑客就是最先利用这些不安全,不规范的代码,来首先取得系统的控制权的,然后才利用系统的控制权,进一步实施攻击,产生更大的危害。
(3)程序运行中栈的安排结构,有利于黑客展开缓冲区溢出攻击,这是因为在程序运行时通常栈是向下增长的,即后进栈的数据的地址小于先进栈的数据的地址。
这样当发生函数调用时,首先压栈的是该函数的参数,然后是函数的返回地址,接下来是基指针,然后在进入函数体以后还会保存一些寄存器的值,再把这些寄存器的值压入栈顶,最后才是函数体中声明的各个局部变量(即前文所说的缓冲区),也有可能包含一些函数指针。
因此,在函数运行中缓冲区的地址低于寄存器的地址,低于基指针的地址,低于返回地址的地址,低于该函数的参数的地址。
所以要是向缓冲区中拷贝超过其容量大小的数据,那么多出来的数据就会覆盖寄存器的值,覆盖基指针的值,覆盖返回地址的值覆盖参数的值,也完全可以覆盖上层函数中的缓冲区等等,只要拷贝的数据足够长。
而且栈所在的地址范围又低于代码所在的地址范围,这样也完全可能覆盖程序中的代码。
(4)既使上诉条件都满足,也不一定会发生缓冲区溢出攻击,只能说程序中存在缓冲区溢出漏洞,这是因为不是所有的漏洞都能被黑客利用。
有些只是程序中存在的缺陷,黑客并没有办法或者说暂时没有办法通过该漏洞取得系统的控制权限,来完成其进一步攻击的目的。
3.2缓冲区溢出攻击原理
当正常的使用者操作程序的时候,所进行的操作一般不会超出程序的运行范围,数据被添加到分配给该缓冲区的内存块之外,会发生缓冲区溢出,这时候就会出现数据泄漏或侵占了其它的数据空间。
缓冲区溢出的攻击原理就是越过缓冲区长度界限向程序中输入超出其常规长度的内容,造成缓冲区的溢出从而破坏程序的堆栈,使程序运行出现特殊的问题转而执行其它指令。
一般来说,单单的缓冲区溢出,并不会产生安全问题,如果将溢出送到能够以root权限或其它超级权限运行命令的区域去执行某些代码或者运行一个shell的时候,该程序就是以超级用户的权限控制了计算机。
图3.1缓冲区漏洞的例子
例如,有一段程序段如图3.1(a)所示,运行时当进入一个过程,就有一个活动记录累筑于栈顶。
sub的活动记录如图3.1(b)所示,包含连接数据、形式单元、局部变量、局部数组的内情向量和临时工作单元等。
其中连接数据有两个:
一个是老SP值,即前一活动记录的地址,另一为返回地址。
argv[1]是通过命令行传递给main的参数,由于strcpy()函数不进行越界检查,argv[1]中的内容将完整地复制到buf中,如果arg[1]中的内容长度超出了buf的范围,多余的内容将被写出buf的后续地址中,而在函数堆栈中,局部变量之后存放的有SP帧指针和函数返回地址。
因此黑客可以通过填写argv的内容,在strcpy出现缓冲区溢出时让程序转去执行相应的攻击代码,完成对系统的攻击。
如图3.1(c)所示,老SP值被修改指向缓冲区的地址返回地址被修改指向恶意代码的入口地址。
当sub返回时,程序将转去执行恶意代码,从而达到攻击目的。
因此,为防止缓冲区溢出攻击,开发软件时应该尽量使用带边界检查的函数,或主动进行边界检查。
3.3缓冲区溢出实现方式
3.3.1利用跳转指令实现溢出
在调用函数时,以下内容会依次压栈:
该函数的参数(按从右向左的顺序压栈),函数的返回地址,为该函数调用分配局部栈空间之前的EBP寄存器的值。
这些东西调试程序的时候看一看对应的汇编代码、对应地址处的内存内容和相关寄存器的值就会一清二楚。
函数调用完成后会执行ret指令,ret指令执行完后esp寄存器中会指向栈的原始区(执行函数调用之前的那个栈的栈顶),所以把shellcode放在栈的原始区,把返回地址修改后指令jmpesp的地址就可以,这条jmpesp指令的地址是通过在操作系统的几个核心DLL中查找的。
整个实验过程就是写代码时调用一个函数,然后在调用函数的过程中实现栈溢出。
图3.2溢出前后堆栈分布状态
对照图3.2,在程序正常执行时,memcpy函数被执行完毕后,指令指针会返回至ret地址处,继续执行memcpy函数调用处的后续指令;同时,执行完ret指令后ESP指针也会指向堆栈原始区(调用memcpy函数前一时刻的堆栈分布)。
因此,我们可以将溢出代码shellcode存在堆栈原始区,而剩下的工作就是在memcpy执行返回时让EIP指针指向原始区(也就是ESP指针指向的地址)即可。
如何通过ret返回地址确定此时的堆栈ESP指针指向呢?
在这里采用的方法是通过跳转指令“jmpesp”(无条件跳转至esp指向处执行)。
通过在用户地址空间中查找到包含有“jmpesp”指令的存储地址,用该地址覆盖ret返回地址就可以了。
在具体实现时,我们通过三个步骤完成缓冲区溢出:
(1)编写前导码。
所谓前导码就是用于覆盖局部变量到ret返回地址之间的堆栈空间(不包括ret返回地址空间)的指令码。
前导码仅是用于填充堆栈,所以其内容不受限制。
我们需要在实际的调试中来确定前导码的大小。
(2)查找jmpesp指令地址。
用”jmpesp”指令的地址覆盖ret,就可以在memcpy执行返回后,让CPU执行跳转指令,所以首要解决的是在用户空间中找到含有“jmpesp”指令的地址。
通过VC++6.0的反汇编功能得到“jmpesp”指令的机器码为0xFFE4。
利用FindJmpesp工具进行指令查找,确定一个含有“jmpesp”指令的内存地址。
(3)shellcode功能体。
shellcode功能体实现了溢出后主要的执行功能,如创建超级用户,提升用户权限等。
在这里我们通过自定义指令来实现弹出用户对话框。
攻击者可以利用缓冲区溢出漏洞,通过溢出来获取程序的控制权。
若此程序具有足够的权限,则攻击者就因此获得了系统的控制权。
要实施一次有效的缓冲区溢出攻击,攻击者必须完成如下任务:
(a)在程序的地址空间里植入适当的代码(称为shellcode)用于完成获取系统控制权等非法任务。
(b)通过修改寄存器或内存,让程序执行流跳转到攻击者植入的shellcode地址空间执行。
下面以栈溢出为例,简要介绍一下这两个任务的实现方法:
(a)shellcode植入:
当缓冲区溢出发生在程序的IO操作附近时,攻击者可以直接利用程序的输入,向程序中植入shellcode。
(b)程序执行流程的跳转:
shellcode植入后,缓冲区溢出便会发生,以上面的栈溢出为例,如图3.3,函数调用的返回地址被覆盖为AAAAA,这样当此函数执行完毕返回时,程序执行流会跳转到0xAAAAA(即shellcode)处继续执
行。
图3.3堆栈溢出
3.3.2定位参数地址实现溢出
首先看下面的代码片段。
Voidoverflow(constchar*ptr,intlen)
{
Charbuff[400];
Memcpy(buff,ptr,len);
}
其中第二参数len的值为第一参数ptr指向的字符串长度。
在函数参数ptr不为空的情况下,当len小于400时,该段代码能够正常运行。
overflow函数被调用执行时内存堆栈分布如图3.4左侧所示:
首先是overflow调用执行后的下一条指令地址入栈(ret返回地址),overflow调用前堆栈基址指针入栈(原ebp),接下来堆栈基址指针指向当前栈顶(ebp指向),最后esp栈顶指针减去若干字节(大于400)完成缓冲区划分。
而ebp指针减去400就应是局部变量buff指针指向。
图3.4缓冲区溢出前后堆栈的分布
当len大于400时,该段代码就会产生溢出,如图3.4右侧所示,溢出的数据会覆盖原ebp地址和ret返回地址,使其遭到破坏。
设想:
(1)用shellcode指令首地址覆盖ret返回地址,当buff缓冲区存放shellcode时,shellcode指令首地址即为buff缓冲区地址。
(2)保持原ebp基址不被溢出数据覆盖掉,即用overflow调用前的ebp基址覆盖原ebp基址。
(3)在shellcode相关指令被执行完成后,后续代码应继续被执行,利用跳转指令可以执行overflow后续代码。
所以溢出后的程序执行流程就是:
指令寄存器EIP指向buff基址执行shellcode指令,待shellcode相关指令完成后通过jmp跳转指令跳转至ret返回地址继续执行。
将shellcode指令按功能分为三部分来进行考虑。
第一部分是shellcode头,其主要功能是保护当前寄存器状态,为执行shellcode功能体做准备;第二部分是shellcode功能体,由其完成一定的功能如弹出对话框、添加新用户等;最后一部分就是shellcode尾,其功能是恢复寄存器状态、跳转至正常执行时下一条指令地址。
另外shellcode的最后4字节应该是覆盖ret返回地址的地址。
(1)shellcode头。
功能:
在内存堆栈中划分额外空间(shellcode功能体使用),并保护当前寄存器状态。
实现代码:
_asm
{
subesp,1024h
pushad
}
(2)shellcode功能体。
功能:
完成具体执行功能。
实现代码:
具体参见实现步骤。
利用ShellExecuteAAPI函数运行控制台程序net实现添加系统用户是一个不错的选择,net添加用户及提升用户权限命令如下:
新建用户:
netuserusernamepassword/add
用户所属组:
netlocalgroupadministratorsusername/add
调用执行:
ShellExecuteA(0,“open”,“net”,net执行参数,SWHIDE)
其中username是新建用户名称,password是用户口令,/add
ShellExecute的功能是运行一个外部程序(或者是打开一个已注册的文件、打开一个目录、打印一个文件等等),并对外部程序有一定的控制。
如果指定的文件是可执行文件,函数将以open的方式打开这个文件。
(3)shellcode尾。
功能:
恢复寄存器状态;shellcode功能体执行完成后,跳转到指定代码地址继续执行;使用新地址覆盖原ebp地址及ret返回地址。
实现代码:
_asm
{
popad
addesp,102Ch
movedx,OxXXXXXXXX
jmpedx
}
通过popad指令将恢复所有普通寄存器先前状态。
恢复栈顶指针。
通过jmp指令无条件跳转至0xXXXXXXXX处执行指令。
具体实现过程如下:
(1)使用VC编写项目文件:
CreateShellCode、OverFlowClient和OverFlowServer。
(2)生成shellcode功能体
(a)首先设置OverFlowClient项目为启动项。
(b)双击打开OverFlowClient.cpp源文件,在该源文件中需要填写的代码有:
kernel32.dll基址(第21行),LoadlibraryA函数的绝对内存地址(第23行)和shellExecuteA函数(隶属于Shell32.dll动态库)的绝对内存地址。
(c)编译并生成OverFlowClient.exe,执行OverFlowClient.exe,确定系统是否新建了jlcss用户,并隶属Administrators组。
(3)生成shellcode指令码
(a)设置CreateShellCode为启动项。
双击打开CreateShellCode.cpp源文件,CreateShellCode的工作流程是:
首先生成shellcode头,并将相关指令码写入shellcode.shc文件中;接下来是生成shellcode功能体,功能体代码来自OverFlowClient.exe中shellcode函数执行体,将功能体代码追加到shellcode.shc中;最后是生成shellcode尾,同样将其指令码追加到shellcode.shc中。
(b)这里需要填写的宏数值有:
SHELLCODEBODYSTART(OverFlowClient.exe中ShellCode主体起始偏移地址);
SHELLCODEBODYLEN(OverFlowClient.exe中ShellCode主体代码长度);
CORRECTRETURNADDR(OverFlowServer中overflow调用完成后程序正常执行返回地址,即OverFlow正常调用完成后的下一条指令地址);
在OverFlowServer中函数OverFlow调用执行前,ebp基地指针地址;
OverFlow溢出返回地址,即函数溢出后shellcode得以执行的首地址。
①获取SHELLCODEBODYSTART、SHELLCODEBODYLEN值
调试OverFlowClient.exe(将该项目设置为启动项)确定ShellCode函数入口偏移地址及函数体大小,调试过程参见图3.3所示。
图3.5shellcode函数开始、结束偏移地址
②根据调试结果填写CreateShellCode.cpp源文件中SHELLCODEBODYSTART宏和SHELLCODEBODYLEN宏的值。
③其它数值需要通过调试OverFlowServer来获取,而OverFlowServer的执行又依赖于shellcode.shc文件,所以暂且编译生成CreateShellCode.exe文件,执行该文件生成临时shellcode.shc文件。
(4)调用OverFlowServer
通过上述步骤,已经获得了ShellCode执行体指令码,还需要获取溢出后程序正常返回地址、OverFlow函数调用前ebp基础指针地址和shellcode执行的缓冲区首地址。
(a)OverFlow正常调用返回时的下一条指令地址。
设置OverFlowServerfiles为启动项,双击打开OverFlowServer.cpp文件。
程序首先打开存放shellcode指令码的文件(默认名称为shellcode.shc),读取shellcode.shc的全部内容至接收缓冲区中。
接下来就是利用memcpy函数实现接收缓冲区的拷贝,目标地址是OverFlow函数内的局部缓冲区,该缓冲区默认大小为450字节,需要根据实际调试结果重新确定其大小。
最后在OverFlow调用完成后
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 网络 攻击 防御 课程设计