
1. 项目概述从一台闲置路由器开始的探索手头有一台几年前买的某米路由器型号是R3G已经吃灰很久了。最近整理东西翻出来想着与其让它彻底报废不如拿来练练手看看能不能挖出点有意思的东西。这其实也是很多安全研究员和爱好者的一个常见起点利用手边退役或闲置的设备进行安全研究和漏洞挖掘实战。家用路由器作为家庭网络的入口和核心其安全性至关重要。一旦被攻破意味着家庭内所有联网设备都可能暴露在风险之下。因此对路由器进行安全分析不仅是一次技术挑战更是对“边界安全”最直接的实践。这次分享的目标很明确就是针对这台某米路由器R3G进行一次从信息收集到漏洞验证的完整流程复现。我不会涉及任何高深的、未公开的0day挖掘而是聚焦于一个安全研究者或者说“脚本小子”进阶之路的常规操作固件提取、逆向分析、模拟调试、寻找潜在漏洞点。整个过程更像是一次“考古”和“解构”我们将像拆解一个黑盒一样一步步揭开这台路由器的内部构造并尝试理解其中可能存在的安全隐患。无论你是对嵌入式安全感兴趣的新手还是想了解硬件漏洞挖掘流程的开发者希望这篇基于真实设备的长文能给你带来一些实用的思路和可复现的步骤。2. 前期准备与固件获取工欲善其事必先利其器。在开始对路由器“动手”之前我们需要搭建一个适合的分析环境并想方设法拿到路由器的“灵魂”——它的固件。2.1 分析环境搭建我的主力分析环境是一台Ubuntu 22.04的虚拟机分配了足够的CPU和内存建议4核8G以上。为什么用Linux因为后续的很多工具链在Linux上运行最为顺畅。以下是核心工具的安装清单固件提取与分析工具binwalk用于固件解包的神器能自动识别并提取固件中的文件系统、内核等。firmware-mod-kit一套固件修改工具包有时用于重组固件。file命令基础但重要用于识别文件类型。逆向工程工具IDA Pro或Ghidra静态反汇编和分析二进制文件。Ghidra是NSA开源的工具功能强大且免费是我的首选。radare2另一个强大的开源逆向工程框架命令行操作非常灵活。模拟调试环境qemu-system全系统模拟可以模拟运行整个固件包括内核和用户态程序。对于MIPS架构的路由器需要安装qemu-system-mips等包。qemu-user-static用户态模拟用于在x86主机上直接运行MIPS/ARM架构的二进制程序配合chroot使用效率更高。firmadyne一个自动化的固件模拟框架但配置稍复杂我们后续会用手动方式达到类似目的。网络与调试工具gdb-multiarch支持多架构的GNU调试器配合QEMU使用进行动态调试。strace/ltrace跟踪系统调用和库函数调用理解程序行为。netcat,tcpdump,nmap基本的网络探测和抓包工具。安装这些工具在Ubuntu下非常方便基本上通过apt-get install即可搞定大部分。例如sudo apt-get install binwalk qemu-user-static gdb-multiarch strace ltrace netcat tcpdump nmap。Ghidra则需要去官网下载独立安装包。2.2 固件获取的多种途径对于某米路由器获取固件有几种常见方法我尝试了其中两种途径一官方渠道下载这是最直接、最合法的方式。访问某米路由器的官方支持页面查找对应型号R3G的历史固件版本。通常厂商会提供.bin格式的固件文件用于手动升级。我成功下载到了一个名为miwifi_r3g_firmware_2.28.xx.bin的文件。这种官方固件是进行漏洞挖掘的主要对象因为它代表了设备实际运行的代码。注意务必下载与你设备硬件版本匹配的固件。不同版本间硬件可能有差异固件不通用。同时建议下载多个历史版本有时旧版本漏洞更多分析起来也更有代表性。途径二从设备本身提取如果无法从官网下载或者想分析设备当前运行的、可能被修改过的固件就需要从设备上提取。这通常需要一些硬件接口或利用已有的软件漏洞。对于某米R3G一种常见的方法是通过设备的调试接口如UART串口。你需要拆开路由器找到主板上的UART引脚通常是TX、RX、GND有时还有VCC用USB转TTL模块连接电脑使用串口终端工具如minicom或screen连接。如果运气好引导程序bootloader如U-Boot没有禁用交互或者系统启动了串口登录你就可以获取一个shell。在shell中可以使用dd命令将整个MTDMemory Technology Device分区如mtd0代表整个Flash备份出来或者直接备份/dev/mtdblockX。例如在获取shell后cat /proc/mtd # 查看MTD分区信息 dd if/dev/mtdblock0 of/tmp/full_flash.bin # 备份整个Flash需注意空间然后通过TFTP、SCP或者甚至base64编码后分段echo出来等方式将备份文件传回分析主机。这个过程需要对Linux系统和路由器架构有一定了解并且存在变砖风险操作需谨慎。我这次主要使用从官网下载的官方固件进行分析因为它更干净、更标准适合作为分析起点。3. 固件解包与初步分析拿到miwifi_r3g_firmware_2.28.xx.bin这个文件后第一步就是“拆开”它看看里面到底装了些什么。3.1 使用Binwalk进行解包binwalk是固件分析的第一步也是最自动化的一步。在终端中执行binwalk miwifi_r3g_firmware_2.28.xx.bin输出结果会显示这个二进制文件中嵌入的所有可识别部分。典型的输出可能包含TRX firmware header一种常见的路由器固件封装格式。LZMA compressed data压缩的内核或文件系统。Squashfs filesystem只读压缩文件系统通常包含路由器的操作系统、Web管理界面、各种服务程序等。这是我们的主要目标。接下来使用binwalk的提取功能binwalk -e miwifi_r3g_firmware_2.28.xx.bin-e参数代表提取extract。命令执行后会在当前目录生成一个_miwifi_r3g_firmware_2.28.xx.bin.extracted的文件夹。进入这个文件夹你就能看到被提取出来的内容。通常你会找到类似0.trx、120.squashfs这样的文件。120.squashfs就是包含根文件系统的Squashfs镜像。3.2 挂载与探索文件系统Squashfs是只读的我们需要将其挂载到本地目录进行浏览。首先安装支持工具sudo apt-get install squashfs-tools。然后创建挂载点并挂载mkdir squashfs-root sudo mount -t squashfs -o loop 120.squashfs squashfs-root/现在进入squashfs-root目录你就仿佛进入了路由器的根文件系统。可以开始探索了。关键目录与文件/bin,/sbin,/usr/bin,/usr/sbin存放可执行程序包括busybox嵌入式Linux的瑞士军刀和各种守护进程如httpd、telnetd、dropbear等。/etc配置文件目录。重点关注/etc/config/OpenWrt类系统的配置、/etc/init.d/启动脚本、/etc/passwd和/etc/shadow用户和密码哈希但家用路由器通常使用硬编码或动态生成。/www或/webWeb管理界面的文件CGI脚本、HTML、JS。这是漏洞的高发区因为它是面向外部的接口。/lib共享库文件。分析程序依赖哪些库库中是否有已知漏洞函数如strcpy,sprintf等是快速寻找漏洞点的方法。/proc和/sys在真实系统或模拟环境中运行时才有内容是内核信息的接口。在探索过程中我特别关注了/www目录因为某米的Web管理界面功能丰富交互复杂是潜在的攻击面。果然在/www/cgi-bin/目录下发现了多个CGI可执行文件例如luci、api等。这些就是处理Web请求的后端程序。3.3 识别目标与架构信息使用file命令查看关键二进制文件的架构file squashfs-root/bin/busybox file squashfs-root/www/cgi-bin/luci输出显示为“ELF 32-bit LSB executable, MIPS, MIPS32 rel2 version 1 (SYSV), dynamically linked...”。这确认了该路由器使用MIPS架构。这对于后续的模拟和调试至关重要因为我们需要对应架构的QEMU和工具链。同时查看/etc/os-release或/proc/version的模拟内容如果有可以了解系统是基于OpenWrt还是其他定制系统。某米路由器大多基于OpenWrt进行深度定制。4. 建立模拟调试环境静态分析固件文件能发现很多信息但要真正理解程序逻辑、验证漏洞动态调试是必不可少的。我们需要让这个MIPS架构的固件在我们的x86电脑上“跑起来”。4.1 使用QEMU进行用户态模拟全系统模拟qemu-system-mips比较重启动慢且需要适配内核。对于分析单个用户态程序如Web CGI用户态模拟qemu-user-static更加高效便捷。步骤一准备根文件系统我们已经有了squashfs-root但它可能缺少一些运行时所需的设备节点。我们可以复制一份作为模拟环境的基础cp -r squashfs-root ./qemu-rootfs cd qemu-rootfs步骤二使用chroot与qemu-user-static关键是要将qemu-mips-static这个解释器拷贝到目标文件系统中并利用chroot“切换根目录”到该文件系统。# 首先将宿主机的qemu-mips-static拷贝到目标根文件系统 sudo cp $(which qemu-mips-static) ./qemu-mips-static # 然后使用chroot并指定qemu解释器来运行目标shell sudo chroot . ./qemu-mips-static /bin/sh如果一切顺利你会得到一个#或$提示符这已经是在模拟的MIPS环境中了你可以执行ls、ps等基本命令。但此时网络、/proc、/sys等可能还不完善。步骤三配置网络与必要目录为了让Web服务能运行我们需要在chroot环境中挂载一些虚拟文件系统并设置网络。这通常在chroot之前完成cd qemu-rootfs sudo mount -t proc /proc proc/ sudo mount -t sysfs /sys sys/ sudo mount -o bind /dev dev/ # 如果需要网络可以设置一个TAP设备并桥接但初期调试可以不联网然后再次执行sudo chroot . ./qemu-mips-static /bin/sh。4.2 启动Web服务进行交互测试在chroot环境中尝试启动Web服务器。首先查看启动脚本cat /etc/init.d/httpd # 或 uhttpd, lighttpd具体名称需查看找到启动命令例如可能是/usr/sbin/uhttpd。尝试直接运行它可能会因为缺少配置或环境而失败。需要根据错误信息调整比如复制必要的配置文件到正确位置或者设置环境变量如PATH,LD_LIBRARY_PATH。一个更简单粗暴的方法是直接运行我们感兴趣的CGI程序并模拟HTTP请求。例如我们可以写一个简单的C程序使用execve调用CGI并设置好环境变量REQUEST_METHOD,QUERY_STRING等来模拟GET/POST请求。或者更直接地用echo通过管道传递数据echo GET /cgi-bin/luci HTTP/1.0\r\n\r\n | ./qemu-mips-static /www/cgi-bin/luci这可以测试CGI程序是否能被正常触发以及是否有明显的崩溃。4.3 使用GDB进行动态调试动态调试是漏洞挖掘的核心。我们需要在QEMU用户态模拟中附加GDB。步骤一以调试模式启动程序在chroot环境外使用qemu-mips-static的-g参数指定一个调试端口sudo chroot . ./qemu-mips-static -g 1234 /www/cgi-bin/luci这条命令会让luci这个CGI程序启动并暂停等待GDB在端口1234上连接。步骤二使用GDB多架构调试打开另一个终端启动gdb-multiarchgdb-multiarch (gdb) set architecture mips (gdb) target remote localhost:1234 (gdb) file ./qemu-rootfs/www/cgi-bin/luci # 加载带符号的二进制文件如果有的话连接成功后你就可以像调试本地程序一样设置断点、单步执行、查看内存和寄存器了。例如b *main在入口处断点c继续运行。实操心得在MIPS架构下函数调用的参数传递规则前几个参数通过寄存器$a0-$a3传递和x86不同需要熟悉MIPS汇编。Ghidra的反编译功能可以极大地帮助理解程序逻辑。将二进制文件导入Ghidra进行初步分析找到可疑函数如处理HTTP参数、调用危险函数strcpy/sprintf的地方记下其地址然后在GDB中对这些地址下断点进行动态跟踪观察参数内容和缓冲区状态。5. 漏洞挖掘实战以Web CGI为例有了模拟和调试环境我们就可以开始有针对性的漏洞挖掘了。Web管理界面是路由器最暴露的攻击面其中的CGI程序是重点目标。5.1 攻击面枚举与危险函数定位首先对/www/cgi-bin/下的所有二进制文件进行初步筛查。使用file确认它们是MIPS ELF文件。然后可以使用strings命令快速查看字符串寻找可能包含参数名的字符串如username、password、action、set等这能提示我们程序的输入点。更系统的方法是使用静态分析工具。将CGI程序加载到Ghidra中。在Ghidra中我们可以搜索危险函数调用在“Search For Strings”或“Search Program Text”中搜索strcpy,sprintf,strcat,gets,system,popen等不安全的C库函数。这些函数是缓冲区溢出和命令注入的典型源头。分析main函数或HTTP请求处理入口找到程序入口跟踪其如何解析QUERY_STRING或POST数据。通常路由器CGI会使用getenv(“QUERY_STRING”)或从标准输入读取POST数据然后使用strtok、sscanf或自定义函数进行解析。关注字符串处理逻辑仔细审查任何将用户输入复制到固定大小缓冲区的代码。注意数组或缓冲区的声明大小在栈上或全局数据区以及复制前是否进行了长度检查。以我分析的luci程序为例在Ghidra中搜索strcpy发现了多处调用。其中一处位于一个名为parse_form_data的函数中。反编译代码显示该函数从一个全局指针获取数据并使用strcpy复制到一个局部数组而该数组的大小是固定的比如256字节。如果源数据长度超过256字节就会发生栈缓冲区溢出。5.2 动态验证与POC构造静态分析找到了可疑点接下来需要用动态调试来验证。定位函数地址在Ghidra中找到parse_form_data函数的起始地址例如0x00401234。设置断点在GDB中连接到等待调试的luci进程然后设置断点b *0x00401234。构造输入我们需要模拟一个HTTP请求来触发这个函数。编写一个简单的Python脚本使用socket或requests库向模拟环境如果Web服务已启动或直接向qemu-mips-static运行的进程发送HTTP请求。请求中需要包含超长的参数值。# 示例构造一个超长的“data”参数 import requests url http://192.168.1.1/cgi-bin/luci # 假设模拟环境IP是192.168.1.1 long_string A * 500 # 生成500个A data {action: set, data: long_string} response requests.post(url, datadata) print(response.status_code)如果直接通过管道测试可以这样echo -e POST /cgi-bin/luci HTTP/1.0\r\nContent-Type: application/x-www-form-urlencoded\r\nContent-Length: 520\r\n\r\nactionsetdata$(python3 -c \print(A*500)\) | sudo chroot . ./qemu-mips-static /www/cgi-bin/luci观察崩溃发送请求后在GDB中观察程序是否在strcpy处崩溃。查看寄存器$pc程序计数器是否指向了异常地址或者栈指针$sp是否被破坏。如果$pc被覆盖为0x41414141‘A’的ASCII码是0x41那就确认了存在栈溢出漏洞并且可以控制执行流。5.3 漏洞利用的挑战与思路在路由器环境下漏洞利用比在桌面系统上更具挑战性主要原因有DEP/NX数据执行保护现代路由器固件可能启用了NX位使得栈上的数据不可执行。这意味着即使覆盖了返回地址跳转到栈上也会导致崩溃。需要转向ROPReturn-Oriented Programming技术。ASLR地址空间布局随机化内核和库的加载地址可能随机化增加了定位gadget的难度。但很多嵌入式设备为了节省资源或兼容性ASLR可能较弱甚至关闭。架构差异MIPS的指令集和内存模型与x86不同ROP链的构造更复杂。例如MIPS在函数调用时返回地址保存在$ra寄存器而非栈上但某些情况下如栈溢出覆盖了保存的寄存器区域仍然可以劫持控制流。权限限制即使获得了代码执行能力也可能只是在www或nobody用户权限下需要进一步提权到root。初步利用思路信息泄露首先需要绕过ASLR。可以寻找程序本身存在的内存信息泄露漏洞比如一个格式化字符串漏洞或者一个读取内存的CGI接口来泄漏libc的基地址。ROP链构造使用ROPgadget这类工具针对目标二进制和libc库搜索可用的gadget。由于是MIPS架构需要寻找如jalr $t9、lw $ra, X($sp);jr $ra这类能控制跳转的指令片段。执行命令最终目标是执行系统命令比如启动telnet服务、下载并执行恶意程序。可以构造ROP链调用system()函数参数指向我们放置在内存中的命令字符串如/bin/telnetd -l /bin/sh。注意事项在实际漏洞挖掘中从发现漏洞到完成利用是一个漫长且需要深厚功底的过程。对于初学者能够通过动态调试确认漏洞的存在使程序崩溃并控制$pc或$ra就已经是巨大的成功。这证明了漏洞的可利用性。完整的武器化利用Weaponized Exploit需要更多的研究和测试。6. 其他攻击面与自动化辅助除了Web CGI路由器的攻击面还有很多其他网络服务使用netstat -an在模拟环境中运行或分析启动脚本查看路由器还开放了哪些端口。常见的有23端口Telnet可能被禁用、22端口SSH如Dropbear、53端口DNS服务、1900端口UPnP等。这些服务对应的二进制文件同样需要分析。云管理功能某米路由器通常有配套的手机App和云服务。这涉及到与云端通信的客户端程序可能存在于固件中。分析其通信协议、认证逻辑也可能发现漏洞。硬件接口如前所述的UART串口如果未做保护可以直接获取终端。JTAG接口更是能直接读写内存和Flash。无线协议Wi-Fi协议栈的实现驱动和用户态工具也可能存在漏洞但分析难度更高。为了提高效率可以借助一些自动化工具进行初筛checksec检查二进制文件的安全属性NX, PIE, RELRO等。ROPgadget/ropper自动搜索ROP gadget。firmwalker一个脚本自动遍历提取出的文件系统寻找敏感文件、密码、密钥、脚本等。基于符号执行或模糊测试的工具如AFLAmerican Fuzzy Lop的QEMU模式可以对CGI程序进行模糊测试自动生成能触发崩溃的输入。但这需要将目标程序编译到支持AFL插桩对于黑盒的固件二进制需要利用afl-qemu模式配置过程较为复杂。7. 常见问题与排查技巧实录在实际操作中你会遇到各种各样的问题。这里记录了一些我踩过的坑和解决方法。问题1Binwalk提取失败或提取出的文件系统不完整。原因固件可能使用了非标准的封装格式、加密或自定义的压缩算法。排查用hexdump或xxd查看固件文件头尾寻找特征魔术字。尝试不同的提取工具或选项如binwalk -Me递归提取或firmware-mod-kit中的extract-firmware.sh。手动搜索文件系统魔术字hexdump -C firmware.bin | grep -i sqsh或... | grep -i hsqs(Squashfs的反序魔数)。如果怀疑加密需要逆向分析升级程序或Bootloader找到解密例程。问题2QEMU用户态模拟运行程序时提示“找不到动态链接器”或“无法执行二进制文件”。原因qemu-user-static需要与目标架构和动态链接器路径匹配。有时固件使用的动态链接器路径比较特殊如/lib/ld-uClibc.so.0。排查file命令确认二进制架构是MIPS 32位小端MIPSEL。使用readelf -l binary查看程序头Program Headers找到INTERP段指定的动态链接器路径。在chroot环境中确保该路径下存在正确的动态链接器。如果没有可能需要从固件其他位置复制或寻找兼容的版本。直接指定链接器运行./qemu-mips-static -L /path/to/rootfs /path/to/binary其中-L参数指定根文件系统路径。问题3在chroot的QEMU环境中程序运行崩溃错误信息模糊。原因缺少必要的环境变量、配置文件、设备节点或内核功能。排查使用strace在宿主机上用qemu-mips-static配合strace运行程序sudo chroot . ./qemu-mips-static -strace /bin/ls 21 | head -50。观察程序在哪个系统调用上失败如open一个不存在的文件ioctl调用失败。检查依赖用ldd命令在模拟环境下查看二进制缺失的库./qemu-mips-static -L . /usr/bin/ldd /www/cgi-bin/luci。确保所有需要的.so文件都在/lib或/usr/lib下。创建缺失的设备节点有些程序需要/dev/null,/dev/urandom等。在qemu-rootfs/dev/目录下使用sudo mknod创建它们。简化环境先尝试运行最简单的程序如/bin/busybox ls确保基础环境没问题再逐步排查目标程序。问题4GDB连接QEMU后设置断点无效程序不中断。原因断点地址可能设置不正确由于PIE或加载地址偏移或者程序在GDB连接前已经执行过了断点。排查在Ghidra中查看的地址通常是基于默认基址如0x00400000。但QEMU加载时基址可能不同。在GDB连接后使用info files或info proc mappings查看程序段的实际加载地址。使用带符号的地址如果Ghidra分析出了函数名在GDB中可以直接用函数名下断点如b parse_form_data前提是正确加载了符号文件编译时的调试信息通常固件中不包含。在程序入口点下断点b *_start或b *main确保在程序一开始就停住。问题5发送超长HTTP请求测试时程序没有崩溃但返回了错误页面。原因可能存在输入长度检查或者错误处理逻辑避免了崩溃。也可能是请求格式不对未触发到有漏洞的代码路径。排查静态分析更仔细回到Ghidra查看可疑函数附近是否有长度检查代码如strlen、if (len sizeof(buf))等。动态跟踪在解析输入的函数开始处下断点单步跟踪观察我们的超长数据是否被正确传递到了危险的strcpy函数以及复制前缓冲区的状态。尝试不同参数和请求方法漏洞可能存在于特定的参数名如Cookie头或特定的HTTP方法GET/POST处理中。参考其他路由器漏洞如D-Link DIR-815的hedwig.cgi漏洞就是通过超长Cookie触发的尝试构造类似的畸形请求。漏洞挖掘是一个需要极大耐心和细致观察的过程。每一个异常现象背后都可能隐藏着一个漏洞而每一个“失败”的测试都能帮助你更深入地理解目标程序。保持好奇心多动手实践从每一次崩溃和调试中积累经验是提升技能的唯一途径。这台某米R3G路由器就像一座等待探索的微型城市而你就是那位拿着放大镜和地图的探险家。