前言
1.学习缓冲区溢出攻击需要有C语言和汇编的基础,以及一些操作系统知识2.我是个菜鸡,文章是边查资料边写的,如发现文中有错误,很大可能就是写错了
3.本文无实例,只有很少的技巧,主要是小结一下相关知识
4.缓冲区溢出涉及到许多技术,请不断深入学习
向一个缓冲区中放置比分配的空间还多的数据就可能导致缓冲区溢出,正常的缓冲区溢出条件会导致段越界发生,利用这种情况可以达到访问目标系统的目的。(由于操作系统都默认启动了一些安全机制,传统的缓冲区溢出攻击已经不在管用了)
缓冲区溢出的主要原因在于忽视了对输入数据的校验。
相关知识
缓冲区:用于存取数据的内存,位置和长度在编译时确定或在程序运行时动态分配。栈和堆都是缓存区。
缓冲区溢出:向缓冲区拷贝数据时,如果数据的长度大于缓冲区的长度,多出的数据覆盖该缓冲区邻近的(高地址)内存空间,破坏进程的数据。
缓冲区溢出攻击:缓冲区溢出时,如果邻近的内存被进程使用,则可能导致进程不正确运行,如果被覆盖的是函数的返回地址(call必须记住调用时当前的地址,所以需要先将返回地址push到栈中,一般函数调用的返回地址就在缓冲区后的高地址处),攻击者可以通过构造溢出的数据来改变原程序的执行流程,控制进程的执行流程。
Shellcode:用于利用软件漏洞而执行的代码。是一段16进制的机器码。一般的功能就是提权。
栈:一种后进先出的数据结构,向低地址增长。
堆:一种先进先出的数据结构,向高地址增长,使用完需要手动释放。
地址随机化机制(ASLR):一种在内核中使用的技术,使用后堆栈的起始地址动态变化,即进程每次启动时地址与上一次不同。(需要猜测地址)
Linux关闭/开启地址随机化机制
sudo sysctl -w kernel.randomize_va_space=0
目前randomize_va_space的值有三种,分别是[0,1,2](默认为2)
0 - 表示关闭进程地址空间随机化。(禁用)
1 - 表示将栈(stack)随机化。(除堆以外随机化)
2 - 表示在1的基础上增加堆(heap)的随机化。(全部随机化)
进程映像:进程在内存中的分布。(了解进程映像是攻击的基础)
Linux进程映像
32位与64位相似,只是大小不同
|代码(地址按源代码执行顺序从低到高排列) | 低地址
—————————————————————————————————————————
| 已初始化的全局变量 |
—————————————————————————————————————————
| 未初始化的全局变量 |
—————————————————————————————————————————
| 动态内存(堆结构) |
—————————————————————————————————————————
| 空闲 |
—————————————————————————————————————————
| 局部变量(栈结构) |
—————————————————————————————————————————
| 环境变量 | 高地址
Windows进程映像
结构与Linux大体一致,区别有:
1.局部变量位于堆栈的低地址区。
2.字符串变量先定义,后入栈,存放在低地址。
简写:
| 动态链接库的映射区 | 高地址
——————————————————————————————
| 代码段、数据段 |
——————————————————————————————
| 堆栈区 | 低地址
补充:Win7使用地址随机化机制,进程的地址空间每次运行皆不同,动态链接库的加载基址不随进程地址变化而变化,重启操作系统,动态链接库的加载基址变化。(不同版本的系统动态链接库及其加载基址不同)。
gcc栈检查
开启栈检查(默认开启):使用gcc编译时加入-fstack-protector选项。
关闭栈检查:使用gcc编译时加入-fno-stack-protector选项。
远程攻击:相比于本地攻击的唯一区别是攻击代码从网络传递(数据包),然后复制到缓冲区。
Exec-Shield:通过限制内存空间的读写和执行权限(除存放可执行代码的内存空间以外,对其余内存空间尽量禁止执行)来防御攻击的机制。由于通常情况下不会在栈空间里存放可执行代码,所以将栈空间的权限设为可读写且不可执行。
StackGuard:在编译时在各函数入口和出口插入用于检测栈数据完整性的机器语言代码的方法。用于保护ebp和返回地址。执行方法同gcc栈检查。
缓冲区溢出攻击经典方法
UNIX
Morris蠕虫:fingerd的缓冲区溢出漏洞
Linux
1.分析调试:(是否存在漏洞?如何利用?)
方法:在关键点设置断点
目标:缓冲区起始地址与函数返回地址的距离。
(1)记录函数的返回地址(第一条语句中esp的值,会动态变化),返回地址都是存放在被调用函数的栈帧中。
把地址看成字符串,跳转地址的最高两字节为’\0’。
(2)计算产生缓冲区溢出所需的字节数(会动态变化),目标缓冲区起始位置+跳转地址在攻击串中的位置,计算方法见 参考资料与深入学习 进行学习。
(3)查看esp,确定被修改的返回地址(ret语句中)。
补充:放置Shellcode的条件(放置位置需要实际调试确定)
(1)若缓冲区较大,可以容纳Shellcode(Linux64位系统缓冲区溢出攻击的前提),将Shellcode放置在跳转地址(函数返回)之前。
(2)若缓冲区不足以容纳Shellcode,将Shellcode放置在跳转地址之后。
(3)如系统未开启地址随机化,对于本地溢出,可以把Shellcode放在环境变量里(环境变量的空间很大,足以容纳Shellcode),优势是地址定位准确。
(4)进程跳转攻击
2.编写Shellcode
(1)写出简洁、能完成所需功能的代码。
(2)反编汇得到的可执行代码,用汇编语言实现相同的功能。
注意:
a.不同系统中汇编语法不同:
Linux: mov src, dest
Win32 : mov dest, src
b.避免Shellcode中的\x00:
编写没有机器码\x00的指令(比如用两个一样的值xor来代替0x00)
将Shellcode编码,新Shellcode=解码程序+编码的原Shellcode
c.在Linux系统中,系统调用的编号定义于/usr/src/linux/include/asm/unistd.h。
(3)提取操作码,写成Shellcode,并验证。
3.攻击(比如以root权限启动/bin/sh)
Windows
与Linux差不多。
进程跳转攻击:寻找动态链接库的映射区中的call esp和jmp esp指令,该地址是攻击的跳转地址,将该地址覆盖函数的返回地址,将Shellcode放在返回地址所在单元后,使溢出后通过动态链接库的映射区中的call esp和jmp esp指令跳到Shellcode。
通常用系统调用和较为基础的Win API实现,Shellcode中调用API比较麻烦,偷个懒 :·)
实例可以按照此文章练一下:https://blog.youkuaiyun.com/weixin_37477009/article/details/111171893
其他
比如printf类函数的字符串格式化bug。
缓冲区溢出攻击的防范
1.按照安全规范编程,使用安全函数,对输入数据做边界检查,并进行测试。
2.使用堆栈保护,即使发生缓冲区溢出,仅会破坏内存数据,不会执行恶意代码。
3.禁止堆栈执行,阻止进程被劫持。
参考资料与深入学习
《网络信息安全》 曾凡平著 7~11章(我开始就是看它学的,有典型的实例,可以都做一下)
《有趣的二进制:软件安全与逆向分析》 第3章(有典型的实例)
关闭Linux 内存地址随机化机制 https://blog.youkuaiyun.com/force_eagle/article/details/8024502
对抗栈帧地址随机化/ASLR的两种思路和一些技巧https://www.cnblogs.com/liqiuhao/p/7783688.html
Windows堆地址随机化原理剖析与改进http://d.wanfangdata.com.cn/periodical/xxwlaq201707001
缓冲区溢出攻击https://baike.baidu.com/item/%E7%BC%93%E5%86%B2%E5%8C%BA%E6%BA%A2%E5%87%BA%E6%94%BB%E5%87%BB/11056235#5
[转]缓冲区溢出攻击(含示例)https://www.cnblogs.com/elta/articles/4862924.html
利用gcc自带的功能-fstack-protector检测栈溢出及其实现https://www.cnblogs.com/leo0000/p/5719186.html
GCC 中的编译器堆栈保护技术https://www.ibm.com/developerworks/cn/linux/l-cn-gccstack/?S_TACT=105AGX52&S_CMP=tec-ccid#ibm-pcon
本文主要小结缓冲区溢出攻击相关知识。介绍了缓冲区、缓冲区溢出等概念,阐述了地址随机化机制等技术。讲述了UNIX、Linux、Windows等系统下缓冲区溢出攻击的经典方法,包括分析调试、编写Shellcode等步骤,最后提出按照安全规范编程等防范措施。
656





