天生我材必有用,千金散尽还复来。 仰天大笑出门去,我辈岂是蓬蒿人。 大鹏一日同风起,扶摇直上九万里。 十步杀一人,千里不留行。 事了拂衣去,深藏身与名。 安能摧眉折腰事权贵,使我不得开心颜! 且乐生前一杯酒,何须身后千载名? 愿将腰下剑,直为斩楼兰。
 

bufbomb-缓冲区溢出攻击实验

缓冲区溢出攻击

一、实验目的:
加深对IA-32函数调用规则和栈帧结构的理解

二、实验要求:

构造5个攻击字符串,对目标程序实施缓冲区溢出攻击。

5次攻击难度递增,分别命名为

Smoke    (让目标程序调用smoke函数)

Fizz         (让目标程序使用特定参数调用Fizz函数)

Bang       (让目标程序调用Bang函数,并篡改全局变量)

Boom     (无感攻击,并传递有效返回值)

Nitro      (栈帧地址变化时的有效攻击)

需要调用的函数均在目标程序中存在

三、实验内容:

getbuf函数:存在缓冲区溢出漏洞,buf只有0x28字节长度。

 

栈:

 

 

Smoke

任务是让目标程序调用smoke函数,观察这个栈,要想调用smoke函数就要把smoke函数的地址放到getbuf上面的返回地址处。

找到smoke函数的地址:0x8048c28

 

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

 

用管道输入,通过hex2raw之后输入bufbomb程序。成功:

      

 

Fizz:

构造攻击字串造成缓冲区溢出,使目标程序调用fizz函数,并将cookie值作为参数传递给fizz函数,使fizz函数中的判断成功,需仔细考虑将cookie放置在栈中什么位置。

先找到cookie值:每次运行之后,都有cookie,所以cookie值可以确定是:0x4bbafd61。小段存储:61 fd ba 4b

然后就是把这个值作为参数给fizz函数。观察栈发现,参数是放到了返回地址的上面,并且和返回地址相邻。先用fizz函数地址覆盖掉返回地址,可以执行fizz函数,并且要将fizz函数的返回地址覆盖掉,并用cookie覆盖掉上面的参数。这样就可以跳转到fizz函数,并且在跳转后自己取到cookie作为参数,fizz函数的返回地址就用00 00 00 00覆盖掉。

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

 

拼好后的样子:

 

成功:  

    

 

  Bang:

  要求更改全局变量

  要自己写一个恶意代码,更改全局变量,赋值为cookie,更改完还要转到bang函数继续执行。

  先找到全局变量的位置:在bang函数里看到有两个内存地址,正好和源程序里的判断相等对应,接下来确定哪一个是全局变量。

    

 

    用gdb调试,在getbuf函数设断点,运行,查看一下两个地址的值,很明显,0x804d100是全局变量。

    

 

    Mov指令赋值,之后要跳转到bang函数——将0x08048cad压栈,结合起来就是这样:

    

 

    然后用gcc –m32 –c 编译成.o可重定位目标文件,然后objdump –d 反编译出机器码。如如:

    

 

    这是恶意代码,我们需要的是这些16进制的机器码,我把它们放到buf区域里,然后执行就ok。

    要执行这些代码就需要让控制流可以跳到这,只要把这段恶意代码的首地址放到getbuf函数的返回地址处就可以了,也就是buf缓冲区的首地址放到返回地址。接下来找buf缓冲区的首地址:

    看一下getbuf函数,发现,在图中0x80491f7处,ebp减小 开辟了一段空间,也就是buf区域,eax寄存器中放的就是该空间的首地址,即buf首地址。

    

 

    用gdb调试,在下一行设置断点,查看eax的值:

      

 

    也就是 38 35 68 55

    拼好的字节码是:

    

 

    还是管道输入。

    成功:

    

 

  Boom:

  要求被攻击程序能返回到原调用函数test继续执行——即调用函数感觉不到攻击行为。也就是要恢复ebp的值。

  另外,构造攻击字符串,使得getbuf都能将正确的cookie值返回给test函数,而不是返回值1

  设置返回值也就是更改eax的值,可以用mov指令设置eax存的为cookie值。

  更改完要进入test函数继续执行下面的指令,也就是下图中这个位置,将这个地址压栈。

  

 

  综合起来,代码为:

  

 

  用同bang那关一样的方法,得到字节码:

  

 

  恶意代码准备好了,将返回地址更改为指向这个代码的位置,把恶意代码放到buf缓冲区内,返回地址和bang一样。

  接下来要恢复ebp的值,先得到ebp旧值。

  Gdb调试:在getbuf第一行,push ebp 设置断点。查看ebp的值。

  

 

  ebp=0x55683590,即90 35 68 55

  用这个值覆盖ebp值。ebp值在返回地址的低方位,放在返回地址前。

  综合如下:

  

 

    同样,管道输入。

  成功: 

    

 

    Nitro:

    构造攻击字符串使getbufn函数(注,在kaboom阶段,bufbomb将调用testn函数和getbufn函数),返回cookie值至testn函数,而不是返回值1

    需要将cookie值设为函数返回值,复原被破坏的栈帧结构,并正确地返回到testn函数。

 

    这里和上一个的不同之处在于地址空间随机化。还有这是在testn函数和getbufn函数里。

    

 

  ebp是随机的,但是ebp相对esp是绝对的,根据上面的图中结合栈结构得出

  ebp = esp + 0x24 + 4 = esp + 28

  getbufn函数返回后要从0x8048e4a开始执行,将这个地址压栈。

  设置cookieeax。

  综合得出恶意代码为:

  

 

  转换为字节码。

  

 

  getbufn函数:

  

 

  要填入0x208+4+4=528字节。

  因为随机,不知道程序会跳到哪里,所以把恶意代码放到最后面,用nop滑行。

  (nop不会执行任何操作,只有PC加一,机器码是90。)

  所以,前面塞满90,最后面写上恶意代码程序,以及最后要跳的位置。

     寻找要跳的地址:

  由于随机化,buf首地址不确定。用gdb调试:在0x8049218设断点,看eax的值。(每执行一次,要用c命令继续,进而执行下一次)

  例如:

  

    一共5次。

  

 

  

 

  

 

  

 

  

 

  buf首地址的取值范围在0x55683328~0x556833c8

  取最高地址0x556833c8(c8 33 68 55)作为返回地址,这样就会一路滑行到恶意代码,执行恶意代码。

  综合上述:

  

 

  同上管道输入。

  注意:hex2raw也要加-n!

  成功:

  

 

  有问题欢迎留言~

 

posted @ 2017-12-23 17:18  gudy  阅读(9881)  评论(3编辑  收藏  举报