最近在挖掘固件漏洞,有些路由器没有现成设备,要验证时只能通过qemu模拟的方式来完成。在此记录下QEMU的使用过程
参考文章:TOTOLINK 路由器漏洞分析+QEMU模拟入门
环境配置 QEMU安装 为安装方便,笔者直接选择使用apt install的方式来安装qemu,想要使用源码编译的话可以参考官网
1 2 sudo apt-get install qemu-system # qemu系统模拟 sudo apt-get install qemu-user-static # qemu用户模拟
固件 固件型号 :TOTOLink X6000R
固件版本 :v9.4.0cu.852_20230719
固件架构 :Aarch64
固件可以直接在官网 下载,使用binwalk
工具提取其文件系统。
QEMU-User模拟 将qemu-aarch64-static
程序复制到固件文件系统下,使用chroot设置文件系统为根目录,然后通过qemu-user模拟固件shttpd程序
1 sudo chroot . ./qemu-aarch64-static ./usr/sbin/shttpd
可以看到成功运行shttpd程序,不过如果要测试命令注入漏洞返回shell还是要使用系统模拟,并且用户模拟程序,我跑shttpd结果是打不开网页的。
QEMU-System模拟 system模拟方式则更加全面,包括cpu,外设等等。
基本条件:
内核镜像
虚拟磁盘镜像
网卡(非必须,不过要测试路由器,还是需要的)
下载内核,虚拟磁盘镜像 Debian官网有提供针对QEMU的各类架构的Linux内核系统、虚拟磁盘镜像下。下载地址
这里我选择arm64-virt镜像 。下载后重命名为zip文件,解压后得到7个文件
1 2 3 4 5 6 7 8 9 10 11 ❯ tree ./ ./ ├── image.qcow2 ├── initrd ├── kernel ├── readme.txt ├── ssh_user_ecdsa_key ├── ssh_user_ed25519_key └── ssh_user_rsa_key 0 directories, 7 files
其中readme.txt
给定了qemu启动命令,启动命令,你会发现打印很多日志后,成功获取到shell。
1 2 3 4 5 6 7 8 9 10 11 12 13 # (Try to) boot with: sudo qemu-system-aarch64 \ -machine 'virt' \ -cpu 'cortex-a57' \ -m 1G \ -device virtio-blk-device,drive=hd \ -drive file=image.qcow2,if=none,id=hd \ -device virtio-net-device,netdev=net -netdev user,id=net,hostfwd=tcp::2222-:22 \ -kernel kernel \ -initrd initrd \ -nographic \ -append "root=LABEL=rootfs console=ttyAMA0" # You can use Ctrl-a x to exit from QEMU.
出现shell后使用root:root登录即可,注意这里我设置了网卡为tap_qemu,因此如果需要宿主机和虚拟机相互连通,需要进行虚拟网卡的设置。
配置虚拟系统网卡 配置一张可供host,guest通信的虚拟网卡命令如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 # 安装 brctl 网桥配置工具 sudo apt-get install bridge-utils # 安装 tunctl 虚拟网卡配置工具 sudo apt-get install uml-utilities # 添加一个网桥 br0 sudo brctl addbr br0 # 设置网桥 br0 的网段及掩码,并启用网桥 sudo ifconfig br0 192.168.5.1/24 up # 新建一张虚拟网卡 tap0 sudo tunctl -t tap0 # 设置虚拟网卡 tap0 的 ip 地址及掩码,并启用该虚拟网卡 sudo ifconfig tap0 192.168.5.11/24 up # 将虚拟网卡 tap0 添加到网桥 br0 中 sudo brctl addif br0 tap0
创建完毕后ifconfig返回信息如下,发现新增br0和tap0两个网卡,其中br0负责桥接宿主机和客户机,tap0负责宿主机ip:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 ❯ ifconfig br0: flags=4099<UP,BROADCAST,MULTICAST> mtu 1500 inet 192.168.1.1 netmask 255.255.255.0 broadcast 192.168.1.255 ether f2:5f:4f:59:38:2c txqueuelen 1000 (Ethernet) RX packets 0 bytes 0 (0.0 B) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 0 bytes 0 (0.0 B) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500 inet 172.17.178.131 netmask 255.255.240.0 broadcast 172.17.191.255 inet6 fe80::215:5dff:fee8:a09b prefixlen 64 scopeid 0x20<link> ether 00:15:5d:e8:a0:9b txqueuelen 1000 (Ethernet) RX packets 130737 bytes 132443978 (132.4 MB) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 66566 bytes 6308721 (6.3 MB) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536 inet 127.0.0.1 netmask 255.0.0.0 inet6 ::1 prefixlen 128 scopeid 0x10<host> loop txqueuelen 1000 (Local Loopback) RX packets 447386 bytes 1366419777 (1.3 GB) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 447386 bytes 1366419777 (1.3 GB) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 tap0: flags=4099<UP,BROADCAST,MULTICAST> mtu 1500 inet 192.168.1.11 netmask 255.255.255.0 broadcast 192.168.1.255 ether 8e:8a:46:56:b0:40 txqueuelen 1000 (Ethernet) RX packets 0 bytes 0 (0.0 B) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 0 bytes 0 (0.0 B) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
修改以上qemu启动脚本,添加网卡参数:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 sudo qemu-system-aarch64 \ -machine 'virt' \ -cpu 'cortex-a57' \ -m 1G \ -device virtio-blk-device,drive=hd \ -drive file=image.qcow2,if=none,id=hd \ -netdev tap,id=tapnet,ifname=tap0,script=no \ # 配置一个主机侧的TAP网络设备,命名为tapnet,使用主机的tap0网卡 -device virtio-net-device,netdev=tapnet -netdev user,id=net,hostfwd=tcp::2222-:22 \ # 虚拟机使用虚拟网卡,对应设备为前面创建的tapnet设备 -kernel kernel \ -initrd initrd \ -nographic \ -append "root=LABEL=rootfs console=ttyAMA0"
此时登入shell,检查虚拟机的网络配置,这里我的虚拟机没有ifconfig命令,因此选择使用ip命令(不得不感慨chatgpt的强大与方便~~~)
1 2 3 4 5 root@debian:/# ip link show 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP mode DEFAULT group default qlen 1000 link/ether 52:54:00:12:34:56 brd ff:ff:ff:ff:ff:ff
发现已有eth0网卡,那么就要将其ip设置为与宿主机同一网段(192.168.1.0/24)。
1 2 3 4 # 设置ip地址 ip addr add 192.168.1.2/24 dev eth0 # 设置网关 ip route add default via 192.168.1.1
设置好后发现互相ping不通,显示目标不可达,查看ip route发现路径不对:
1 2 3 4 5 6 root@debian:/# ip route default via 10.0.2.2 dev eth0 onlink 10.0.2.0/24 dev eth0 proto kernel scope link src 10.0.2.15 172.17.176.0/20 dev eth0 proto kernel scope link src 172.17.178.111 172.17.178.0/24 dev eth0 proto kernel scope link src 172.17.178.111 192.168.1.0/24 dev eth0 proto kernel scope link src 192.168.1.2
因此更换default为192.168.1.0/24,同时删除其他错误项:
1 2 3 4 5 ip route del default ip route del 172.17.176.0/20 ... ip route add 192.168.1.0/24 dev eth0 ip route add default via 192.168.1.1 dev eth0
ip address show
也显示有问题,使用ip addr del
删去无关项即可
Tips:这里我用的是WSL,发现linux虚拟机无法ping通Windows主机,是Windows主机的防火墙拦截掉了。使用powershell管理员用户输入以下命令即可。
1 New-NetFirewallRule -DisplayName "WSL" -Direction Inbound -InterfaceAlias "vEthernet (WSL)" -Action Allow
SSH连接QEMU虚拟机 只能进行shell连接是不够的,添加ssh连接,方便后续上传固件以及gdbserver等内容
上传并执行固件 系统已经成功模拟,接下来我们要让其能够模拟执行固件。
使用scp命令上传固件
1 scp -r ./squashfs-root root@192.168.1.2:/root/
回到qemu命令行,使用chroot更改根目录为固件的根目录并且启动web服务/usr/sbin/shttpd
,不过这里发现访问页面404。发现是执行路径的原因
在/web
路径下执行/usr/sbin/shttpd
解决该问题
WSL GUI问题解决 成功模拟固件后,还需要能够通过浏览器页面访问呀,因此这里再浅谈一下如何使用WSL2开启GUI的浏览器访问固件页面。
参考链接:在适用于 Linux 的 Windows 子系统上运行 Linux GUI 应用
这里仅介绍chrome浏览器的安装
1 2 3 4 5 6 # 将目录更改为 temp 文件夹: cd /tmp # 使用 wget 下载: wget https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb # 安装: sudo apt install --fix-missing ./google-chrome-stable_current_amd64.deb
然后使用google-chrome
命令即可,打开后成功访问固件模拟主页