使用Linux进行缓冲区溢出实验的配置记录
在基础的软件安全实验中,缓冲区溢出是一个基础而又经典的问题。最基本的缓冲区溢出即通过合理的构造输入数据,使得输入数据量超过原始缓冲区的大小,从而覆盖数据输入缓冲区之外的数据,达到诸如修改函数返回地址等目的。但随着操作系统和编译器针对缓冲区溢出问题引入防护机制,初学者想要由简入繁的学习和实践缓冲区溢出的原理变得困难。在 Linux 环境下,用户可以通过设置编译和系统环境来去除某些防护措施,从而方便的完成某些简单的缓冲区溢出实验。
1.关闭SSP( Stack Smashing Protector )
实现原理
SSP 是 gcc 提供的针对栈上缓冲区溢出提供检查的机制。典型的缓冲区溢出攻击会通过构造输入数据覆盖缓冲区外的数据,实现一定的溢出效果,如修改函数返回地址等。启用 SSP 机制后,在编译器生成的代码中,对于那些存在缓冲区的函数,函数开始时会在对应栈帧中入栈一个随机值( canary ),在函数调用结束准备返回时,编译器生成的代码会检查上述引入的随机值是否发生了变化,若发生变化则说明出现了缓冲区溢出,控制流会转移至对应的处理函数处。
以下列代码为例进行说明
void simpleCopy( char *src )
{
char buff[10];
strcpy( buff , src );
}
上述代码将缓冲区 src 中的数据简单的拷贝至 buff 数组中,而没有考虑 src 中的数据量是否超出了 buff 数组的容纳能力。
使用 gdb 查看得到 simpleCopy 的汇编如图所示。
在开启了 SSP 机制的 gcc 生成的代码中,函数开始数据处理之前,将 gs:0x14 处的值存放在了 %ebp - 12 处,在函数返回时,对 %ebp - 12 处的值进行检查,若此时值不等于 gs:0x14 处的值,则说明存在数据的覆盖和修改,程序会转入 __stack_chk_fail 执行。通过 simpleCopy("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")调用函数的结果如下图所示。上述 simpleCopy 函数中,缓冲区 buff 首地址为 %ebp - 22 , 而引入的 canary 存放在 %ebp - 12 处,当缓冲区存在数据溢出时,会修改 canary 的值,从而在函数返回时被检测到。
选项设置
gcc的编译设置中,默认设置SSP机制是有效状态,用户可在编译时加入 -fno-stack-protector 参数禁用SSP机制。
-fstack-protector //编译时启用SSP机制
-fno-stack-protector //编译时禁用SSP机制
2.关闭DEP( Data Execution Prevention )
在某些栈缓冲区数据溢出实践中,会将构造好的机器指令序列通过输入写入位于栈上的输入缓冲区中,同时,构造数据覆盖位于数据缓冲区外的函数调用的返回地址,将其值修改为缓冲区中构造好的机器指令序列的地址,这样当函数调用返回时,程序控制流会跳转至输入缓冲区中的构造指令序列,从而实现执行流的修改和劫持。而现代编译器中,为防止用户通过栈上的缓冲区构造数据,使用了DEP机制,即限制内存的属性,使得某些可写内存不可执行( 如栈 )或可执行内存不可写( 如.text段),从而达到防护的效果。
使用 gcc 进行编译时,可通过 -z execstack 参数,使得最终生成的程序中栈内存段具备可执行权限。
-z execstack //设置栈内存段具备可执行权限
在程序运行时,可通过查看 cat /proc/pid/maps 文件查看 pid 所对应的进程的内存映射情况,其中包括对进程的段的属性描述。
3.关闭ASLR( address space layout randomization )
在基础栈缓冲区溢出实践中,一个重要的步骤为定位某些目标的内存映射地址,如最简单的 shellcode 需定位注入栈上的构造指令序列的地址( 从而修改函数返回地址指向该指令序列),ret2libc 方法则需要攻击者定位位于内存中的标准库函数的内存映射地址等。ASLR ,即内存布局随机化机制由操作系统实现,其主要被划分为映像随机化、栈随机化和堆随机化这几类,分别针对程序的加载基地址、栈基址和堆基址进行随机化。
设计原理
已经编译完成的程序的各个段在内存中的加载基位地址是固定的,也就是说程序运行时的内存映射情况是固定的,攻击者可以通过多次调试运行程序,获得他们所需的目标地址。在编译好的 ELF 文件中,段头部表描述了程序需加载入内存的各个段的基地址,可通过 readelf -h filename 对其进行查看。对于运行中的程序,可以通过 cat /proc/pid/maps 查看 pid 对应的进程的内存映射情况,包括栈、堆的基地址等。
objdump -h hello //查看可执行文件hello的段头部表
cat /proc/pid/maps //pid为进程号,查看pid对应进程的内存映射情况
(1)通过 objdump -h hello 查看该 ELF 文件的.text 加载基地址为 0x08048370,而.rodata段的加载基地址为 0x08048558。
(2)通过 cat /proc/$$/maps 查看 shell 的内存映射情况(64位Ubuntu),可以看到 shell 进程的 stack 段的内存范围以及其属性为可读可写但不可执行,p 表示该虚拟内存段为私有的( private ),s 表示该虚拟内存段为共享的( shared )。
在过去的编译环境中,程序的数据段包括.text、.bss、.rodata 段加载进内存的基地址在编译时即已确定,程序运行时进程中 stack 和 heap 的起始地址也总是固定的,这就使得攻击者可以较容易的定位内存中目标的地址,从而进行攻击尝试。在引入 ALSR 机制后,对于程序的某个特定的段( .text 、stack 、heap ),操作系统会在加载时自其原始的起始基地址处加入一个随机大小的“填充”,对应的程序数据总是自“填充”区域后开始,由于每次使用的“填充”的大小并不固定,同一程序多次运行时的内存布局会发生变化,从而使得攻击者较难通过固定的地址去访问其所需要的目标。
选项设置
用户可通过cat /proc/sys/kernel/randomize_va_space 查看当前 ALSR 机制的运行情况。其中,为 0 表示 ALSR 机制未启用,为 1 表示 ALSR 机制会随机化 stack、vdso和 mmap 的起始基地址,为 2 表示除对上述目标进行随机化外还会对堆基地址进行随机化。用户可通过 echo 0 > /proc/sys/kernel/randomize_va_space 设置关闭 ALSR。
cat /proc/sys/kernel/randomize_va_space //查看 ALSR 机制的运行情况
echo > /proc/sys/kernel/randomize_va_space //设置关闭 ALSR 机制,需要 root 用户进行操作
上述对 /proc/sys/kernel/randomize_va_space 的操作为针对系统的全局设置,需要 root 权限且存在弊端,用户可通过以下命令将当前终端 /bin/bash 的 ALSR 机制关闭,则通过该 shell 运行的程序均不会启动 ALSR 机制。该终端关闭后上述设置即失效。
setarch `uname -m` -R /bin/bash
4.通过 gdb 获得目标地址
基础的缓冲区溢出实践通常需要确定运行状态下程序中的某些地址,如需要确定输入缓冲区的起始地址从而获得注入缓冲区中的机器指令的地址等。在 Linux 环境下,可通过 gdb 对程序进行动态调试,从而获得程序运行状态下的信息( 关闭 ALSR 机制后效果更好 ),基础的 gdb 操作可参见笔者的文章Linux下编辑、编译、调试命令总结——gcc和gdb描述。使用 gdb 可以方便的获取程序动态运行状态下的信息,但通过 gdb 动态调试获取的诸如缓冲区的起始地址等信息可能与程序实际运行时的信息并不相同,从而影响缓冲区溢出实践的效果。关于保证通过 gdb 动态调试程序获得的局部变量的地址与直接运行该程序时的地址一致的问题,笔者另外通过博文针对 Linux 环境下 gdb 动态调试获取的局部变量地址与直接运行程序时不一致问题的解决方案进行描述。
5.总结
为了完成基础的缓冲区溢出实践,用户可通过 gcc 的编译选项 -fno-stack-protector 关闭 SSP 保护机制,通过 -z execstack 选项使得生成的可执行程序的栈可执行,通过 setarch `uname -m` -R /bin/bash 设置关闭当前终端中运行程序的 ALSR 机制,并通过 gdb 动态调试获取某些所需要的程序局部变量的信息。
6.参考资料
1.Stack Smashing Protector - OSDev Wiki
2.protect against buffer overflow exploits
3.Address space layout randomization - Wiki
使用Linux进行缓冲区溢出实验的配置记录的更多相关文章
- Kali学习笔记33:Linux系统缓冲区溢出实验
之前做过一个Windows应用SLmail的缓冲区溢出的实验 这次来做一个Linux平台的缓冲区溢出实验: 缓冲区溢出是什么? 学过汇编的应该知道,当缓冲区边界限制不严格时,由于变量传入畸形数据或程序 ...
- 2018-2019-2 20165232《网络对抗技术》Exp1 缓冲区溢出实验
2018-2019-2 20165232<网络对抗技术>Exp1 缓冲区溢出实验 实验点1:逆向及Bof基础实践 实践任务 用一个pwn1文件. 该程序正常执行流程是:main调用foo函 ...
- 2017-2018-2 20179215《网络攻防实践》seed缓冲区溢出实验
seed缓冲区溢出实验 有漏洞的程序: /* stack.c */ /* This program has a buffer overflow vulnerability. */ /* Our tas ...
- SEED缓冲区溢出实验笔记
缓冲区溢出实验(Linux 32位) 参考教程与材料:http://www.cis.syr.edu/~wedu/seed/Labs_12.04/Software/Buffer_Overflow/ (本 ...
- 20191310Lee_yellow缓冲区溢出实验
缓冲区溢出实验 1.什么是缓冲区溢出 缓冲区溢出是指程序试图向缓冲区写入超出预分配固定长度数据的情况.这一漏洞可以被恶意用户利用来改变程序的流控制,甚至执行代码的任意片段.这一漏洞的出现是由于数据 ...
- Linux下缓冲区溢出攻击的原理及对策(转载)
前言 从逻辑上讲进程的堆栈是由多个堆栈帧构成的,其中每个堆栈帧都对应一个函数调用.当函数调用发生时,新的堆栈帧被压入堆栈:当函数返回时,相应的堆栈帧从堆栈中弹出.尽管堆栈帧结构的引入为在高级语言中实现 ...
- 2018-2019-2 20165225《网络对抗技术》Exp1 缓冲区溢出实验
2018-2019-2 20165225<网络对抗技术>Exp1 缓冲区溢出实验 声明 虽然老师在邮箱中要求要把虚拟机名改为个人名字缩写,但是我的kali好像不是很听话...重启数次也没用 ...
- Kali学习笔记21:缓冲区溢出实验(漏洞发现)
上一篇文章,我已经做好了缓冲区溢出实验的准备工作: https://www.cnblogs.com/xuyiqing/p/9835561.html 下面就是Kali虚拟机对缓冲区溢出的测试: 已经知道 ...
- Linux下缓冲区溢出攻击的原理及对策
前言 从逻辑上讲进程的堆栈是由多个堆栈帧构成的,其中每个堆栈帧都对应一个函数调用.当函数调用发生时,新的堆栈 帧被压入堆栈:当函数返回时,相应的堆栈帧从堆栈中弹出.尽管堆栈帧结构的引入为在高级语言中实 ...
随机推荐
- [转]Enabling CRUD Operations in ASP.NET Web API 1
本文转自:https://docs.microsoft.com/en-us/aspnet/web-api/overview/older-versions/creating-a-web-api-that ...
- JPA之@Entity、@Table、@Column、@Id
Java Persistence API定义了一种定义,可以将常规的普通Java对象(有时被称作POJO)映射到数据库.这些普通Java对象被称作Entity Bean.除了是用Java Persis ...
- Sqlserver 备份
Transact-SQL 语法规则 Transact-SQL 引用中的语法关系图使用下列规则. 大写 : Transact-SQL 关键字. 斜体 : Transact-S ...
- 从Object对象中读取属性的值
C#是强类型语言,强到多变态?一个对象没有定义某个属性,你想点出来,IDE直接给你报语法错误.远不如js那么自由,想怎么点怎么点. 如果你从别人接口中拿到的就是Object类型,你想获取某个属性的值怎 ...
- IBatis项目中com.ibatis.common.xml.NodeletException的解决方案
一 现象: 今天在写IBatis项目是总是提示我有如下异常: com.ibatis.common.xml.NodeletException java.util.NoSuchElementExcepti ...
- 使用AutoFac组织多项目应用程序
较复杂的应用程序都是由多个项目组织成的,项目可以划分成程序集(Assemblies)和宿主(Hosts),也就是应用程序的入口. Assemblies 通常是常见的类库项目,包括可以重用的功 ...
- 为什么说 LINQ 要胜过 SQL
如果你还没有沉溺于 LINQ,就会想这有啥大惊小怪的.SQL 并没有坏掉,为什么还要对它进行修补呢? 为什么我们还需要另外一种查询语言呢? 流行的说法是 LINQ 同 C#(或者 VB)集成在了一起, ...
- linux 用vi命令的使用以及vi编辑后的后续保存退出等相关命令的使用
一.首先用vi命令打卡要编辑的文件: 注意:vi命令的使用如下 打开或新建文件,并将光标至于第一行首:[root@centos6 /]# vi /etc/my.cnf 打开文件,并将光标移至最后一行行 ...
- JS实现的数组全排列输出算法
本文实例讲述了JS实现的数组全排列输出算法.分享给大家供大家参考.具体分析如下: 这段js代码对数组进行全排列输出,改进了一些老的代码 从n个不同元素中任取m(m≤n)个元素,按照一定的顺序排列起来, ...
- 浏览器根对象navigator之对象属性概览
第1章 connection[试验] navigator.connection 是只读的,提供一个NetworkInformation 对象来获取设备的网络连接信息.例如用户设备的当前带宽或连接是否被 ...