计算机组成原理 / 反汇编实验(3)缓冲区溢出攻击

目录

    • 实验概述
    • 实验内容
      • 3.2.1 阶段1 Smoke
      • 3.2.2 阶段2 Fizz
      • 3.2.3 阶段3 Bang
      • 3.2.4 阶段4 Boom
      • 3.2.5 阶段5 Nitro

实验概述

实验目的:加深对IA-32函数调用规则和栈结构的具体理解。
实验目标:对一个可执行程序“bufbomb”实施一系列缓冲区溢出攻击。
实验要求:设法通过造成缓冲区溢出来改变该可执行程序的运行内存映像,继而执行一些原来程序中没有的行为,例如将给定的字节序列插入到其本不应出现的内存位置等。
实验语言:c。
实验环境:linux

实验内容

实验中你需要对目标可执行程序BUFBOMB分别完成5个难度递增的缓冲区溢出攻击。5个难度级分别命名为Smoke(level 0)、Fizz(level 1)、Bang(level 2)、Boom(level 3)和Nitro(level 4),其中Smoke级最简单而Nitro级最困难。

3.2.1 阶段1 Smoke

  1. 任务描述:构造一个攻击字符串作为bufbomb的输入,而在getbuf()中造成缓冲区溢出,使得getbuf()返回时不是返回到test函数继续执行,而是转向执行smoke
  2. 实验设计:设计攻击字符串用来覆盖getbuf函数内的数组buf,进而溢出并覆盖ebp和ebp上面的返回地址。
  3. 实验过程:
    在bufbomb的反汇编源代码中找到smoke函数,记下它的开始地址,如图3.1.1所示:
    计算机组成原理 / 反汇编实验(3)缓冲区溢出攻击_第1张图片
    可以看见smoke函数首地址为0x8048c18。同样在bufbomb的反汇编源代码中找到getbuf函数,观察它的栈帧结构,如图3.1.2所示:
    计算机组成原理 / 反汇编实验(3)缓冲区溢出攻击_第2张图片
    可以看到getbuf的栈帧是0x38+4个字节,而buf缓冲区的大小是0x28(40个字节)。所以构建攻击字符串的大小应该是0x28+4+4=48个字节。攻击字符串的最后4个字节应是smoke函数的地址。这样的攻击字符串如 图3.1.3所示:
    计算机组成原理 / 反汇编实验(3)缓冲区溢出攻击_第3张图片
  4. 实验结果:
    如图3.1.4所示,阶段一成功!
    计算机组成原理 / 反汇编实验(3)缓冲区溢出攻击_第4张图片

3.2.2 阶段2 Fizz

  1. 任务描述:构造一个攻击字符串作为bufbomb的输入,而在getbuf()中造成缓冲区溢出,使得getbuf()返回时不是返回到test函数继续执行,而是转向执行fizz()
  2. 实验设计:设计攻击字符串用来覆盖getbuf函数内的数组buf,进而溢出并覆盖ebp和ebp上面的返回地址以及传入fizz的cookie值。
  3. 实验过程:
    在bufbomb的反汇编源代码中找到fizz函数,记下它的开始地址以及调用参数时的关于ebp偏移量,如图3.2.1所示:
    计算机组成原理 / 反汇编实验(3)缓冲区溢出攻击_第5张图片
    可以看见fizz函数首地址为0x8048c42,而且参数存放在[ebp+0x8]处。通过makecookie制造自己的cookie值,如图3.2.2
    计算机组成原理 / 反汇编实验(3)缓冲区溢出攻击_第6张图片
    计算机组成原理 / 反汇编实验(3)缓冲区溢出攻击_第7张图片
  4. 实验结果:如图3.2.4所示,阶段二成功!
    计算机组成原理 / 反汇编实验(3)缓冲区溢出攻击_第8张图片

3.2.3 阶段3 Bang

  1. 任务描述:设计包含攻击代码的攻击字符串,所含攻击代码首先将全局变量global_value设置为你的cookie值,然后转向执行bang()。
  2. 实验设计:设计攻击字符串用来覆盖getbuf函数内的数组buf,进而溢出并覆盖ebp和ebp上面的返回地址,同时攻击字符串在覆盖缓冲区时写入函数的栈帧,当被调用函数返回时,将转向执行这段攻击代码。
  3. 实验过程:
    在bufbomb的反汇编源代码中找到bang函数,记下它的开始地址以及调用全局变量时的偏移地址,如图3.3.1所示:
    计算机组成原理 / 反汇编实验(3)缓冲区溢出攻击_第9张图片
    可以看见bang函数首地址为0x8048c9d,然后利用x命令来判断一些参数存放在0x804d100还是0x804d108处,如图3.3.2所示,其初始值均为0,而程序运行时cookie地址上的内容会变为cookie的值(如图3.3.3),我们需要做的就是,在程序运行时将global_value的值设置为cookie的值;
    计算机组成原理 / 反汇编实验(3)缓冲区溢出攻击_第10张图片
    于是攻击字符串中代码部分应该如图3.3.4所示:
    计算机组成原理 / 反汇编实验(3)缓冲区溢出攻击_第11张图片
    下面将bang_qbw.s文件编译再反编译之后,即可得到恶意代码的字节序列,如图3.3.5所示;
    计算机组成原理 / 反汇编实验(3)缓冲区溢出攻击_第12张图片
    然后寻找栈桢中字符串存放的起始地址即ebp-0x28=0x55683df0-0x28=0x55683dc8,如图3.3.6所示:
    计算机组成原理 / 反汇编实验(3)缓冲区溢出攻击_第13张图片
    于是攻击字符串如图3.3.7所示(等价的写法):
    计算机组成原理 / 反汇编实验(3)缓冲区溢出攻击_第14张图片
    其中最后4个字节0x55683dc8就是攻击代码存放的首地址。
  4. 实验结果:如图3.3.8所示,阶段三成功!
    计算机组成原理 / 反汇编实验(3)缓冲区溢出攻击_第15张图片

3.2.4 阶段4 Boom

  1. 任务描述:构造一个攻击字符串,使得getbuf函数不管获得什么输入,都能将正确的cookie值返回给test函数,而不是返回值1
  2. 实验设计:设计攻击字符串用来覆盖getbuf函数内的数组buf,进而溢出并覆盖ebp和ebp上面的返回地址,同时攻击字符串在覆盖缓冲区时写入函数的栈帧,当被调用函数返回时,将转向执行这段攻击代码。
  3. 实验过程:
    在bufbomb的反汇编源代码中找到test函数,记下它的调用getbuf的下一条语句的地址(0x8048dbe),如图3.4.1所示:
    计算机组成原理 / 反汇编实验(3)缓冲区溢出攻击_第16张图片
    和bang的攻击类似,将getbuf的返回地址赋值为字符串的首地址,如图3.4.2所示,也就是 (%ebp-0x28)=0x55683dc8,并且要在字符串首地址处插入恶意代码。而本题恶意代码要求将cookie的值赋给返回值,也就是%eax,同时继续返回test函数。
    计算机组成原理 / 反汇编实验(3)缓冲区溢出攻击_第17张图片
    由于不能破坏栈桢,所以要执行到test函数调用gutbuf后,输入“123456”,观察test函数的栈桢中存放的ebp值,如图3.4.3所示:
    计算机组成原理 / 反汇编实验(3)缓冲区溢出攻击_第18张图片
    其中0x08048dbe为getbuf返回值,所以0x55683e20为所需要的ebp值。
    由于C语言返回时用eax来作为返回值的,所以攻击字符串中攻击代码部分应该如图3.4.4所示:
    计算机组成原理 / 反汇编实验(3)缓冲区溢出攻击_第19张图片
    所以攻击字符串应该如图3.4.5所示:
    计算机组成原理 / 反汇编实验(3)缓冲区溢出攻击_第20张图片
    其中反选部分就是防止栈破坏被发现而保护的ebp值。
  4. 实验结果:如图3.4.6所示,阶段四成功!
    计算机组成原理 / 反汇编实验(3)缓冲区溢出攻击_第21张图片

3.2.5 阶段5 Nitro

  1. 任务描述:与阶段四类似,构造一攻击字符串使得getbufn函数返回cookie值至testn函数,而不是返回值1
  2. 实验设计:设计攻击字符串用来覆盖getbuf函数内的数组buf,进而溢出并覆盖ebp和ebp上面的返回地址,同时攻击字符串要求需要将cookie值设为函数返回值,复原/清除所有被破坏的状态,并将正确的返回位置压入栈中,然后执行ret指令以正确地返回到testn函数。
  3. 实验过程:
    在bufbomb的反汇编源代码中找到getbufn函数,观察它的栈帧结构,如图3.5.1所示:
    计算机组成原理 / 反汇编实验(3)缓冲区溢出攻击_第22张图片
    发现字符串区域变大了很多,而且这次实验不同之处在于栈的位置不确定,显然不可能完全不确定,应该是一定范围内的不确定,仔细思考发现这个区域应该比0x208小,所以可以在攻击字符串中拆入适量的nop指令来达到顺利的执行攻击代码。
    在bufbomb的反汇编源代码中找到testn函数,记下它的调用getbufn的下一条语句的地址(0x8048e3a),如图3.5.2所示:
    计算机组成原理 / 反汇编实验(3)缓冲区溢出攻击_第23张图片
    再来想一想攻击代码该怎么写,其实和level3也差不多,不同的是由于每次ebp的值可能是不同的,所以还原ebp只能相对地址,于是又想到其实每次旧的ebp – 新的ebp = 常数。而这个常数是多少呢,gdb一下,得出0x24。但由于当我们的攻击代码运行时新的ebp的值已被覆盖,所以要另想一个办法间接地得出新的ebp。于是,想到当函数返回时,esp = 新的ebp + 4,得到:
    旧的 ebp – (esp + 4)= 0x24
    旧的 ebp = esp + 0x28
    所以攻击字符串中的攻击代码应该如图3.5.3所示:
    计算机组成原理 / 反汇编实验(3)缓冲区溢出攻击_第24张图片
    接下来寻找一个合适的返回地址,首先在getbufn第一行,push ebp中设置断点,如图3.5.4查看ebp的值;打开-n开关,执行五次testn后,观察攻击字符串的开始地址,所以总的攻击字符串如图3.5.5以及3.5.6所示:
    计算机组成原理 / 反汇编实验(3)缓冲区溢出攻击_第25张图片
    计算机组成原理 / 反汇编实验(3)缓冲区溢出攻击_第26张图片
    地址依次为0x55683dc8、0x55683dd8、0x55683de8、0x55683e38、0x55683d48,选择其中的最小值0x55683d48,测试发现第二次失败,如图3.5.5:
    计算机组成原理 / 反汇编实验(3)缓冲区溢出攻击_第27张图片
    适当的修改地址值,修改为0x55683c80时,符合要求,故总的攻击字符串如图3.5.6所示:
    计算机组成原理 / 反汇编实验(3)缓冲区溢出攻击_第28张图片
  4. 实验结果:如图3.5.7所示,阶段五成功!
    计算机组成原理 / 反汇编实验(3)缓冲区溢出攻击_第29张图片

你可能感兴趣的:(汇编,反汇编,ubuntu,linux,c++)