概述
在研究固件时,把固件跑起来是不必可少的一步,通常有两种方法,一种是用qemu等工具来搭建模拟环境;另一种就是买成品。固件模拟比起买成品显然有更大的优势:除了节约财力外,更重要的是模拟环境通常直接拥有shell,方便调试,而成品一般不会给shell,只能尝试通过NDAY来拿shell。因此,学会固件模拟,是iot安全研究不可绕过的重点。
固件模拟的三种方法
现成自动化工具:FirmAE等
FirmAE具有一键式模拟固件的能力,提供shell、gdb调试甚至fuzz功能,但是成功率有限,而且耗时较长:

qemu用户模拟
演示固件下载:AX12 V1.0 升级软件_腾达Tenda官方网站
qemu是最常用的固件模拟工具之一,有两种模拟方式:用户模拟和系统模拟。
用户模拟通常是对某个二进制程序进行模拟,由于只是对单个程序进行模拟,该程序的很多前置服务都没启动,在模拟中会出现很多报错。
在用户模拟时,先使用chroot命令来指定固件的文件系统目录为根目录(这样/bin才会找到固件的文件系统的bin而不是本机的bin),然后使用命令./qemu-xxx-static 来启动对应二进制程序,xxx代表指令集,如:
sudo chroot ./ ./qemu-mips-static ./usr/sbin/httpd
可以看到,httpd已经启动:

访问127.0.0.1,抓包,可以看到web页面:

但是在后续请求中会报错,页面丢失:

报错:

原因就是之前提到的,必要的前置服务没有启动。有时候用户模拟也可以满足漏洞挖掘/复现的需求,前置服务没有启动的问题,可以通过启动项和逆向来分析,通过手动执行启动项的命令或者patch该二进制程序的逻辑来解决报错。
可以参考:
手把手带你分析mips架构下固件分析与漏洞挖掘 – IOTsec-Zone
qemu系统模拟
概述
qemu系统模拟是把整个操作系统给模拟出来(可以结合kvm虚拟化模块来提升效率,注意虚拟化和模拟的区别),然后直接在这个模拟的操作系统里面跑固件,这种方法成功率最高,也基本能还原固件的所有功能。
一般有三种方式:
1、直接使用固件自带的内核和文件系统
很多时候固件的压缩包会自带内核,qemu可以直接指定该内核和固件的文件系统来模拟,这种方法最省事,但是成功率相对比较低
2、网上下载对应内核,使用固件的文件系统
这种方法不使用固件自带的内核,而是从网上下载对应版本,但是文件系统还是用的固件的,成功率比第一种高一些。
3、网上下载对应内核和默认文件系统,跑起来后再通过scp等方法把固件文件系统传到模拟系统上运行。
这种方法成功率最高,相比之下也最麻烦。
此处演示第三种方法。
演示
先判断固件的指令集和操作系统型号:


从openwrt下载对应版本:
Index of /releases/19.07.1/targets/malta/be/
直接下载vmlinux-initramfs.elf文件,该文件包含了简单的文件系统,可以直接跑起来。
首先是配置网卡。
找到自己用的物理网卡名称,我的是ens33,之前已经创建并加入到vqfx-br网桥中,所以此处直接新增一个tap0,加入到该网桥即可:
# 1. 创建tap0虚拟网卡,指定当前用户权限
sudo tunctl -t tap0 -u $(whoami)
# 2. 关闭tap0的默认IP(后续通过桥接获取网段)
sudo ifconfig tap0 0.0.0.0 up
# 3. 将tap0添加到vqfx-br桥接(关键:让虚拟机通过桥接接入192.168.x.x)
sudo brctl addif vqfx-br tap0
# 4. 确认桥接状态(应看到vqfx-br包含tap0和原有接口)
sudo brctl show vqfx-br
然后使用命令启动模拟系统:
qemu-system-mips -M malta -kernel openwrt-19.07.1-malta-be-vmlinux-initramfs.elf -m 512 -nographic -net nic,model=pcnet -net tap,ifname=tap0,script=no,downscript=no -append "console=ttyS0"
启动后在模拟系统的终端执行:
# 配置静态IP(与主机vqfx-br同网段,如192.168.x.200)
ifconfig eth0 192.168.x.200 netmask 255.255.255.0 up
# 添加默认网关(指向主机vqfx-br的IP,确保路由互通)
route add default gw 192.168.x.149 eth0
测试,能ping通即可。
接下来关闭防火墙,否则ssh连接可能被ban:
/etc/init.d/firewall stop
启动ssh服务,openwrt中通常是dropbear程序负责:
/etc/init.d/dropbear start
主机ssh成功登录:

上传固件:
tar -czvf ugw_firmware.tar.gz squashfs-root/
scp ugw_firmware.tar.gz root@192.168.x.x:/tmp/
连不上执行:ssh-keygen -f "/home/yourusername/.ssh/known_hosts" -R "192.168.x.x"
模拟系统中解压并运行:
cd /tmp
tar -xzvf ugw_firmware.tar.gz
然后就可以运行固件了
先挂载:
mount --bind /proc proc
mount --bind /dev dev
mount --bind /sys sys
启动httpd
cd squashfs-root
chroot . sh
./sbin/procd &
./sbin/ubusd &
/usr/sbin/httpd
此时会报错,说端口80不可用:

这是因为openwrt自带的web服务uhttpd默认启动,把端口占了,所以需要ctrl c跳出去,关掉自带的uhttpd服务(动作要迅速)。

关掉后即可启动:

但是还是会报原来用户模拟时候的错误,原因依然是前置服务没启动,重新启动前置服务:
cd squashfs-root
chroot . sh
./sbin/procd &
./sbin/ubusd &
/usr/sbin/httpd
发现还是报错,ps aux|grep ubusd发现拥有多个ubusd,怀疑是因为固件的文件系统会和openwrt的文件系统产生冲突,启动httpd服务之后连页面都进不去了。
尝试使用非openwrt系统来搭建环境,这里参考了H3C系列部分路由器(CVE-2025-2725~2732)漏洞复现 – IOTsec-Zone
使用的环境是:Index of /~aurel32/qemu/mipsel,vmlinux-3.2.0-4-4kc-malta 和debian_squeeze_mipsel_standard.qcow2。
使用的固件是H3C NX15:H3C NX15V100R013 软件版本及说明书-新华三集团-H3C
命令如下:
ubuntu:
sudo tunctl -t tap0
sudo ifconfig tap0 192.168.0.1/24 up
echo 1 | sudo tee /proc/sys/net/ipv4/ip_forward > /dev/null
sudo iptables -t nat -A POSTROUTING -o ens33 -j MASQUERADE
sudo iptables -A FORWARD -i tap0 -j ACCEPT
sudo iptables -A FORWARD -o tap0 -j ACCEPT
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,ifname=tap0,script=no,downscript=no \
-nographic
qemu:
ip addr add 192.168.0.2/24 dev eth0
ip link set eth0 up
ip route add default via 192.168.0.1
ubuntu:
tar -czvf ugw_firmware.tar.gz squashfs-root/
scp ugw_firmware.tar.gz root@192.168.x.x:/tmp/
qemu:
tar -xzvf ugw_firmware.tar.gz
cd /tmp/squashfs-root/
mount --bind /proc proc
mount --bind /dev dev
mount --bind /sys sys
cd squashfs-root
chroot . sh
./sbin/procd &
./sbin/ubusd &
./usr/sbin/lighttpd -D -f ./etc/lighttpd/lighttpd.conf
可能在启动ubusd的时候会出现如下报错:

这是由于缺少了/var/run这一目录导致的,ubusd会在这目录下创建usock,所以手动创建一个即可启动ubusd:
mkdir /var
cd /var
mkdir run
启动lighttpd时候可能会有如下错误:

同样也是少了该文件,手动创建即可启动:

由于缺少result字段,所以显示异常,但是各个接口的可以正常访问,成功模拟:
