举个小栗子说明溢出漏洞利用原理及其检测原理
2017-10-12 15:13
309 查看
一、溢出漏洞利用概述
溢出漏洞利用,是指在存在缓存溢出安全漏洞的计算机中,攻击者可以用超出常规长度的字符数来填满一个域,通常是内存区地址。在某些情况下,这些过量的字符能够作为“可执行”代码来运行。从而使得攻击者可以不受安全措施的约束进行攻击行为。下面以栈布局说明溢出漏洞利用过程。
正常栈布局
RBP : 栈基地址寄存器,指向栈底地址;
RSP : 栈顶寄存器,指向栈顶地址;
RIP:指令地址寄存器,指向指令所在地址。
函数调用时,当前函数的下一个执行命令入栈(RIP,即RET返回地址),RBP入栈,然后把当前RSP的值给RBP;
RSP根据函数执行而移动,根据空间需要移动所指位置,例如入栈局部变量,RSP的值会跟着减小,保证RSP一直指向栈顶。
![](http://blog.nsfocus.net/wp-content/uploads/2017/09/ba699c007a95874010a26926d1b9baa7.png)
栈溢出利用过程说明
栈上的内容填充是从低地址向高地址填充的。
请注意,我们开始使坏啦:
1)给var1填充巧妙构造的超长字符串,超过var1高地址(0x7fffffffdee8),并继续覆盖更高地址的内容,可以看到会把RBP(0x7fffffffdef0)和RET返回地址(0x7fffffffdef8)都给覆盖了;
2)RET返回地址指向var1地址(0x7fffffffdee8),var1里面有我们精心制造的字符串,说白了,有我们的恶意代码;
3)被调用函数执行返回命令时,会读取RET返回地址,便会读取var1里面的恶意代码,并进行执行,无意中执行了恶意代码。
也就是,通过缓冲区溢出,我们能改变程序原有的执行流程,去执行我们准备好的代码。
直观示意请见下面的溢出栈布局图:
![](http://blog.nsfocus.net/wp-content/uploads/2017/09/178a06684582e7bcbf47436a6f89e22c.png)
二、存有溢出漏洞的代码
漏洞代码内容代码很简单,可以看到这段代码用了危险函数strcpy!!
![](http://blog.nsfocus.net/wp-content/uploads/2017/09/a6e51b02e8f150ff14ef5a9ef16e567c.png)
漏洞编译并运行
编译命令
![](http://blog.nsfocus.net/wp-content/uploads/2017/09/1a5b995720b9348644860d70dbe18645.png)
注意后面两个参数必须要加上,要不然,后续的漏洞利用会比较麻烦,这两个参数是关闭linux系统的堆栈溢出保护机制。
-z execstack:表示允许栈中存放可执行代码;
-fno-stack-protector:表示关闭堆栈保护机制,可以任意覆盖RIP的值,如果编译没有加上这个参数,程序执行过程会进行值(被称为金丝雀值)校验,看RIP是否被篡改了,如果篡改了,说明发生了栈溢出,会调用__stack_chk_fail函数,进行安全退出并丢出一个错误。
我们这次是为了研究溢出漏洞利用的流程和原理,不是进行高级漏洞挖掘研究,所以,先关闭系统本身的保护机制。
正常结果
![](http://blog.nsfocus.net/wp-content/uploads/2017/09/d9d2d660ec05c9a78ad7ee48df3a73fa.png)
异常结果
![](http://blog.nsfocus.net/wp-content/uploads/2017/09/0f73f84a8b0609bc7bb0220a1654bf45.png)
字符串过长,程序崩溃了。
三、GDB下的漏洞利用执行
RIP控制设定断点后,执行查看寄存器内容和栈内容
![](http://blog.nsfocus.net/wp-content/uploads/2017/09/21f6fc0c97d4a37d11fcd4c46bc616ce.png)
继续执行,填充288个B字符后的栈内容情况
![](http://blog.nsfocus.net/wp-content/uploads/2017/09/2e68d0a61f4bee1a9db98ecb95f7058a.png)
继续执行,strcpy执行完毕返回,查看寄存器和栈内容,可以看到rbp被覆盖了,但是rip并没有被覆盖,从栈中可以看出,是尝试把0x4242424242424242赋值给rip,然而linux 64位系统的rip最大值是0x00007fffffffffff,因而,rip控制失败。
![](http://blog.nsfocus.net/wp-content/uploads/2017/09/40ab91784dc98f8696ecc019f2b70cea.png)
![](http://blog.nsfocus.net/wp-content/uploads/2017/09/c16a292350893573a002235d20a189a0.png)
调整输入字符串,再次尝试控制RIP
可以计算返回地址的相对位置:0x7fffffffdd38- 0x7fffffffdc30=0x108=264(十进制)
因而,可以构造字符串:”B” * 264 + “C” * 6 通过gdb调试,可以看到,这次我们能控制rip的取值了,是我们尝试的0x434343434343。
![](http://blog.nsfocus.net/wp-content/uploads/2017/09/7159f757fbebb89eed95c61bb570f2c5.png)
基于我们不断探索的精神,我们继续尝试,把RIP指向缓存起始地址,即我们可以控制内容的地方。构造字符串:”B” * 264 + “\x7f\xff\xff\xff\xdc\x40″(反序),因为是小端模式,因此内存地址需要反序。
![](http://blog.nsfocus.net/wp-content/uploads/2017/09/0d8f80ce77e6d5e0b14bc8dfc4e3eabc.png)
OK,目前为止,我们已经可以控制RIP指向我们的缓存空间了,下一步就是把shellcode注入到我们的缓存空间中,见下面小节。
Shellcode代码注入
Shellcode是一串机器可以直接识别的操作码,一般短小精悍,可以实现很多关键功能,是溢出漏洞利用的完美搭档。
Shellcode可以自己编写,也可以使用MetaSploit的shellcode生成器来生成。
当然,也可以直接从网上找现成的使用。
推荐个网站:https://www.exploit-db.com/shellcode/,里面有各种操作系统的各种shellcode代码,可以用来研究学习。
攻击者可以利用shellcode实现不同的攻击用途。
例如:可以实现蠕虫木马的下载;可以打开被沦陷系统的端口,以便接收C&C控制服务器的指令;也可以提权运行系统的命令行shell;以及获取系统关键资料文件等等。
我们这次用shellcode实现对系统的关键文件(/etc/passwd)的读取。
在gdb设定断点后,开始执行查看栈内容,可以看到shellcode内容和返回地址都已经填充成我们期望的数据。
![](http://blog.nsfocus.net/wp-content/uploads/2017/09/6cb656c14b1d50587f1092b64b509625.png)
![](http://blog.nsfocus.net/wp-content/uploads/2017/09/95450187561567459c8e2f184c4cf27c.png)
继续执行,可以看到我们成功调出来了系统的关键文件(/etc/passwd)的内容!
![](http://blog.nsfocus.net/wp-content/uploads/2017/09/f100a7132bb8333df1af9b85bd8ef748.png)
细心的小伙伴会发现,我在shellcode之前填充了好多”\x90”,这是NOP空命令,作为缓冲作用,rip的值落在这个范围内都会顺利下滑到shellcode正常执行。
也就是说,就算rip地址稍微有点偏差,也会正常利用成功。
四、实际环境下的漏洞利用执行
实际环境执行gdb调试好的字符串参数直接运行,失败!
检查打印信息,我们会发现缓存地址变化非常随机,无法提前预知,就算咱们有NOP缓冲区也失效了。
![](http://blog.nsfocus.net/wp-content/uploads/2017/09/f066e1a2f8435ac271e81706ecc72bb2.png)
这正是linux的另一种保护机制,通过地址随机化,防止溢出利用攻击。
那先关闭这个机制,再次验证。
关闭这个机制的命令:sudo bash -c “echo 0 > /proc/sys/kernel/randomize_va_space”
关闭randomize_va_space后的实际环境运行情况
![](http://blog.nsfocus.net/wp-content/uploads/2017/09/15da623c712d122f6780f020be5a581d.png)
OK,利用成功!
五、溢出漏洞利用样本
在这个小节,我们自己编写个溢出漏洞利用样本,并进行漏洞利用攻击。溢出漏洞利用样本程序
计算缓存大小,并获取rsp寄存器的值,用这个值预估返回地址(retAddr = rsp + RSP_RET_DIFF+ adjustment)。
![](http://blog.nsfocus.net/wp-content/uploads/2017/09/021b6c00a8c862849247be6592877d21.png)
申请缓存存储空间,并在其中输入我们期望的内容(NOP段+shellcode+填充内容+返回地址),填充内容是为了构造合适的字符串长度,保证栈上返回地址内容被覆盖成我们期望的返回地址。
![](http://blog.nsfocus.net/wp-content/uploads/2017/09/1d1d12257748aaabeb4020b2eb75150b.png)
调用我们之前编译好的有漏洞程序victim。
一点小提醒:为了防止内存泄漏,malloc分配的空间使用完毕要记得释放,对应的指针也要置为NULL,防止指针误用。
![](http://blog.nsfocus.net/wp-content/uploads/2017/09/020894206da7ac50b20bd91250cd7149.png)
溢出漏洞利用程序编译运行
编译
![](http://blog.nsfocus.net/wp-content/uploads/2017/09/fce28f13843f6e2248215907c2cabb4d.png)
运行
![](http://blog.nsfocus.net/wp-content/uploads/2017/09/6b0e7378711da2ca8cb9fa63c7d68367.png)
直接运行发现出问题了,不能正常执行!
查看打印信息,可得知我们用的返回地址(0x7fffffffde60)跟缓存的起始地址(0x7fffffffdc80)差距很大,因而程序不能进入shellcode代码区正常执行。
因此,需要调整下返回地址,返回地址构成是:(retAddr = rsp + RSP_RET_DIFF+ adjustment),我们可以通过参数调整这个adjustment值,见下面小节。
调整返回地址偏差,继续运行样本
![](http://blog.nsfocus.net/wp-content/uploads/2017/09/894bbc6115f5a74f95d9e61e7f140ae8.png)
OK,正常执行我们的shellcode代码!
对比返回地址(0x7fffffffdc9c)和缓存起始地址(0x7fffffffdc80),可以发现两者并不一致,返回地址是在缓存起始地址之后,但也正常执行了。
原因很简单,因为我们在缓存里面填充了很多NOP作为缓冲,返回地址只要落在NOP缓冲区任何一个地方,都能下滑到shellcode代码区进行正常运行。
可能有人会问,都能看到缓存起始地址了,干嘛还折腾用rsp预估返回地址呢,多麻烦呀?
大家可以想想实际情况,应该没有哪个应用程序会主动暴露缓存起始地址(我们的漏洞程序纯粹为了调试,把缓存的起始地址给打印出来了),因而需要一个参考地址进行预估返回地址是多少,所以我们就用了rsp值作为参考地址。
我们已经了解了溢出漏洞利用原理,下面我们开始看看针对这种漏洞的检测原理。
六、溢出漏洞利用检测
溢出漏洞利用检测思路目前比较常用的主要有三种:基于漏洞特征检测、基于Exploit特征检测、基于攻击特征检测。
1)基于漏洞特征检测:对漏洞攻击手段和技术细节比较了解后,研究其触发攻击的必要条件,可以分析出其对应的识别规则,例如缓存区溢出检测、目录遍历检测、远程命令注入检测、远程文件包含检测等;
2)基于Exploit特征检测:从漏洞利用程序中分析独特特征,做为识别规则,例如返回地址检测、ROP Chain检测等;
3)基于攻击特征检测:通过检测漏洞利用相关的相对独立的组件来发现攻击,例如shellcode代码检测、畸形参数攻击检测等等。
基于漏洞特征检测
本文中的漏洞程序检测
从前文可知,victim被攻击的触发条件正是输入一段超长的参数,导致溢出而被利用攻击;
检测方法就是对victim的输入参数进行检查,如果超过一定值(例如256),就要产生告警发现攻击行为。
下图的红线之间的就是输入参数。
![](http://blog.nsfocus.net/wp-content/uploads/2017/09/0b6ad9ba10504c9da96e82612c53c44c.png)
实际案例的检测机制:Microsoft Windows DCOM RPC接口长主机名远程缓冲区溢出漏洞(MS03-026)(CVE-2003-0352)
冲击波蠕虫就是利用这个漏洞进行传播攻击的,Windows Dcom RPC的主机名字段一般不是很长,服务端用栈缓存区存储这个值,但是拷贝时没有做长度检查,导致一个超长的串触发溢出执行任意指令。
检测方法:解码RPC协议,获取主机名,检查其长度,如果超过一定值,就要告警发现攻击行为。
下图的红线之间的就是主机名(够长吧。。)
![](http://blog.nsfocus.net/wp-content/uploads/2017/09/acd52810af7757b6c86067e8f4d04a22.png)
基于Exploit特征检测
本文中的漏洞利用检测
从victim输入参数进行分析,可以看到返回地址非常明显,可以作为检测规则。
发现输入参数有返回地址,就要告警有攻击行为。
下图的红线所标识的就是返回地址特征。
![](http://blog.nsfocus.net/wp-content/uploads/2017/09/f36f1c0d10f91c77c13978c591c1cc5d.png)
实际案例的检测机制:Microsoft Windows工作站服务远程缓冲区溢出漏洞(MS03-049)(CVE-2003-0812)
可以分析出带有返回地址的匹配特征。
![](http://blog.nsfocus.net/wp-content/uploads/2017/09/04ffb863c56fbf279146f6112f04a700.png)
![](http://blog.nsfocus.net/wp-content/uploads/2017/09/99357184f780a23df0e187d31f9cef41.png)
基于攻击特征检测
本文中的漏洞利用检测
可以通过识别输入参数的shellcode特征进行匹配,如果参数包含shellcode肯定是异常行为。
![](http://blog.nsfocus.net/wp-content/uploads/2017/09/b975023c4331926ff26adbab5e7f2d92.png)
同样,对于我们的溢出漏洞利用样本,进行静态分析,如果检测到有shellcode,就可以说明这个样本文件存在异常。
实际案例的检测机制:Microsoft Windows DCOM RPC接口长主机名远程缓冲区溢出漏洞(MS03-026)
Exploit中夹带的是典型的自解码MetaSploit Shellcode,对于这种Shellcode的解码器做粗略的静态匹配检测其实只要匹配“\xd9\x74\x24\xf4”就可以了。
![](http://blog.nsfocus.net/wp-content/uploads/2017/09/2b115c75516ce0a08ac2c1f2ff9ce849.png)
相关文章推荐
- 常见SQL Server 2000漏洞及其相关利用2
- [更新]Elasticsearch 代码执行漏洞利用检测工具
- Apache Tomcat远程命令执行漏洞(CVE-2017-12615) 漏洞利用到入侵检测
- 利用VC检测程序内存溢出
- Canny边缘检测算法原理及其VC实现详解(一)
- Canny边缘检测算法原理及其VC实现详解(二)
- 网站漏洞检测之用户密码找回网站漏洞的安全分析与利用
- 菜鸟版Expliot编写指南之PNP溢出漏洞分析+利用
- glibc下各种堆溢出漏洞利用条件和方法总结
- web上存漏洞及原理分析、防范方法(文件类型检测漏洞)
- Canny边缘检测算法原理及其VC实现详解
- Canny边缘检测算法原理及其VC实现详解(一)
- ASP上传漏洞之利用CHR(0)绕过扩展名检测脚本
- Canny边缘检测算法原理及其VC实现详解(一)
- ThinkPHP框架任意代码执行漏洞的利用及其修复方法
- Openssl“心脏出血”漏洞分析及其利用
- 利用 outlook 2000 漏洞发送邮件的原理
- Windows下的HEAP溢出及其利用
- Canny边缘检测算法原理及其VC实现详解(一)