CSAPP实验三:缓冲区溢出炸弹(Buflab)

       本系列文章为中国科学技术大学计算机专业学科基础课《计算机系统》布置的实验,上课所用教材和内容为黑书CSAPP,当时花费很大精力和弯路,现来总结下各个实验,本文章为第三个实验——缓冲区溢出炸弹(Buflab)。

一、实验名称:buflab

二、实验学时: 3

三、实验内容和目的:

       掌握函数调用时的栈帧结构,利用输入缓冲区的溢出漏洞,将攻击代码嵌入当前程序的栈帧中,使得程序执行我们所期望的过程

四、实验原理:

       ·溢出的字符将覆盖栈帧上的数据

           -特别的,会覆盖程序调用的返回地址

           -赋予我们控制程序流程的能力

       ·通过构造溢出字符串,程序将“返回”至我们想要的代码上

五、实验步骤及结果:

       本实验需要你构造一些攻击字符串,对目标可执行程序BUFBOMB分别造成不同的缓冲区溢出攻击。实验分5个难度级分别命名为Smoke(level 0)、Fizz(level 1)、Bang(level 2)、Boom(level 3)和Nitro(level 4),其中,前2个为必做,后3个为选做,我选做了Bang,这一关有个坑,需要关闭进程地址空间随机化,很少有教程会提到,当时找了好久才解决

     1.Overview

       本次lab利用getbuf()方程不检查读取string长度的漏洞破坏该方程的 return address 从而达到对主程序造成破坏的目的。从getbuf() 的assembly code我们可以看到:

       位于 <0x8048fe6> 地址处代码为预读的 string 在 stack 创建了0xc(也就是12)个Byte 的空间。具体位置可以通过gdb在下一行设置 breakpoint 查找 %eax 的值得到,如下所示:

       通过gdb调试得到,getbuf()申请的12字节缓冲区首地址为 <0xffffb87c>,这个地址后面会用到。

       通常在P过程调用Q过程时,程序的stack frame结构如下图所示:

        为了覆盖被存在Return Address上的值(4 Bytes for m32 machine),我们需要读入超过系统默认12 Bytes大小的string。由于Saved ebp 占据了4 Bytes 所以当我们的input string 为20 Bytes时,最后4位Bytes 刚好覆盖我们的目标Return address.

      (Notes: 由于我们在输入文件下写入的都是character(字符)因此我们需要利用hex2raw这个小程序帮助我们将我们写入的character转换成所对应的二进制数列。)

      2. level0:Candle(smoke)

        Smoke任务的目标是构造一个攻击字符串作为bufbomb的输入,在getbuf()中造成缓冲区溢出,使得getbuf()返回时不是返回到test函数,而是转到smoke函数处执行。为此,你需要:

       1) 在bufbomb的反汇编源代码中找到smoke函数,记下它的起始地址:

        如以上实例中,smoke的开始地址是<0x08048e20>

        2) 同样在bufbomb的反汇编源代码中找到getbuf()函数,观察它的栈帧结构:

         如以上实例,你可以看到getbuf()的栈帧是0x18+4个字节,而buf缓冲区的大小是0xc(12个字节)

        3) 构造攻击字符串覆盖返回地址

        攻击字符串的功能是用来覆盖getbuf函数内的数组buf(缓冲区),进而溢出并覆盖ebp和ebp上面的返回地址,所以攻击字符串的大小应该是0xc+4+4=20个字节。并且其最后4个字节应是smoke函数的地址,正好覆盖ebp上方的正常返回地址。这样再从getbuf返回时,取出的根据攻击字符串设置的地址,就可实现控制转移。

        所以,这样的攻击字符串为:

00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 20 8e 04 08

       总共20个字节,并且前面16个字节可以为任意值,对程序的执行没有任何影响,只要最后四个字节正确地设置为smoke的起始地址<0x08048e20>即可,对应内存写入20 8e 04 08(小端格式)。

       通过Linux终端执行:

       至此,leve0任务smoke通过!

     3. level1:Sparker(fizz)

       level1 和 level0 大同小异,唯一的区别是本次要求跳入函数 fizz(int) 且该函数有一个参数(要求用所给cookie作参数)。

       原理与smoke相同,观察栈帧结构可以发现只需要在smoke攻击字串后面再继续覆盖调用栈帧的参数。

       我们知道在执行完ret指令后栈顶指针 %esp 会自动增加4以还原栈帧。

       通过查找fizz()得知:

        fizz()函数的起始地址为 <0x08048dc0> 与smoke相同,ebp+4为栈帧返回地址。执行完ret指令后栈顶指针 %esp 会自动增加4以还原栈帧。在fizz汇编代码段,cmp指令是将存放cookie的变量与%ebp+0x8处的值相比,此时参数地址也就是旧的ebp+4+8。我们只需要将自己的cookie放置在该位置即可。

        所以构造攻击文件fizz.txt如下:

00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 c0 8d 04 08 00 00 00 00 12 2c 46 22

       其中,<0x08048dc0>为fizz函数起始地址,<0x22462c12>为自己的cookie,通过参数传递给fizz。

       最后执行测试结果如下:

        至此,leve1任务fizz通过!

     4. level2:Firecracker(bang)

       level2的难度开始增加,除了需要跳转至目标函数bang() 地址为<0x08048d60>

       我们还需要执行一些自行设计的指令,因为该任务我们需要将global_value 的值改成我们的cookie,通过objdump -D bufbomb | less (注意D要大写我们才能看到header的代码,-d不会显示):

       通过objdump -D 反汇编可以看到:

       global_value的地址是<0x0804a1dc>, 目前该位置的初始值为 0 ;

       cookie的地址是<0x0804a1cc>, 目前该位置的值初始为 0,程序运行后会变为cookie的值。Cookie:0x22462c12

       我们需要做的就是,在程序运行时将global_value的值设置为cookie的值。

       构造自定义攻击指令bang.s:

       由于是Assembly code 不需要考虑 little endian的问题。先将global_value 用mov指令变cookie (0x0804a1dc前不加$表示地址),然后将bang()函数地址<0x08048d60>写给esp,再执行ret指令时,程序自动跳入bang()函数。

       指令 gcc -m32 -c bang.s 将assembly code写成machine code -->bang.o,再用objdump -d bang.o 读取machine code如下:

        将指令代码抄入攻击文件,除此之外我们还需要找到input string存放的位置作为第一次ret指令的目标位置,具体操作方法见Overview, 经过gdb调试分析getbuf()申请的12字节缓冲区首地址为<0xffffb87c>

       所以构造攻击字符串bang.txt如下:

c7 05 dc a1 04 08 12 2c 46 22 68 60 8d 04 08 c3 7c b8 ff ff

      使用sendstring获得新的攻击字符,执行程序测试运行结果

      提示运行失败,这里出现段错误是因为Linux系统默认开启了栈保护机制,用于阻止缓冲区溢出攻击

解决方法:

      安装execstack sudo apt-get install execstack

      修改程序堆栈的可执行属性 execstack -s bufbomb

      这还不够,还要关闭进程地址空间随机化:

      sudo -s

      echo 0 > /proc/sys/kernel/randomize_va_space

      再次测试运行结果:

       至此,leve2任务bang通过!

  • 13
    点赞
  • 83
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
malloclab是CSAPP(Computer Systems: A Programmer's Perspective)教材中的一个实验项目,旨在帮助学生了解内存管理和动态内存分配的细节。 实验的主要任务是实现一个简单的动态内存分配器。这个内存分配器需要提供malloc、free和realloc函数的功能,来动态管理内存。实验中提供了一个基本的代码框架,学生需要在这个框架上完成具体的实现。 整个实验可以分为三个部分:分配器的初始化、分配和释放内存的处理。 在初始化部分,学生需要定义一个初始的堆,为其分配一块内存,并根据实验要求设置好堆的初始状态。 在分配内存的部分,学生需要实现malloc函数。这个函数接收一个参数(需要分配的字节数)并返回指向分配内存的指针。学生需要根据实验要求分配内存,并保证分配的内存块满足对齐和避免碎片化的要求。 在释放内存的部分,学生需要实现free函数。这个函数接收一个参数(指向待释放内存块的指针)并将该内存块标记为可用。学生需要根据实验要求处理不同的情况,比如释放合并相邻的空闲块。 此外,实验还有一些额外的要求,如实现realloc函数,处理内存使用情况的统计等。 通过完成malloclab实验,学生可以深入了解内存管理和动态内存分配的工作原理。这个实验还提供了一个实践机会,让学生亲自动手实现一个简单的内存分配器,从而更好地理解和掌握相关的概念和技术。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值