3. 固件层IoC定位:固件提取与分析、后门账户检测、硬编码凭据发现

固件层,说白了就是物联网设备的“灵魂”。你想想看,一个摄像头、一个智能插座,它所有的行为逻辑都写在固件里。攻击者最喜欢干的事,就是在固件里埋雷——藏个后门账户、写死一组硬编码密码、或者留个调试接口。我们做失陷指标定位,固件层是绕不过去的硬骨头。

我个人习惯,拿到一台疑似受控设备,第一件事不是通电跑流量,而是先想办法把固件“请”出来。为什么?因为固件里的IoC是最底层的证据,它不会像网络流量那样随风而逝。

3.1 固件提取:从物理层到二进制

固件提取没有万能钥匙。不同的芯片、不同的存储介质,手法完全不一样。我把它分成三类:

提取方式 适用场景 工具/方法 我踩过的坑
芯片直读 SPI Flash、NAND Flash CH341A、树莓派+flashrom 焊盘太脆弱,吹下来容易断脚
JTAG/SWD调试 MCU、SoC有调试接口 OpenOCD、JLink、Bus Pirate 厂商可能锁了调试口,需要电压扰动
OTA/升级包截获 设备有网络升级功能 Burp Suite、mitmproxy、串口日志 固件可能分片加密,需要逆向升级协议
我的小技巧: 如果设备能正常开机,优先尝试串口(UART)获取启动日志。很多厂商会在boot阶段打印内存布局和文件系统挂载信息,这些信息能帮你快速定位固件在Flash中的偏移量。

我记得有一次,一个智能门锁死活无法通过JTAG连接。折腾了两天,最后发现是厂商在PCB上留了一排没焊接的测试点。用万用表一量,其中一个点直连SWD的SWCLK。焊上排针,一次就读出了固件。所以说,别光盯着现成的接口,PCB上的“裸铜点”往往是惊喜。

3.2 固件分析:解包、文件系统与字符串狩猎

拿到固件二进制文件后,第一步是识别它的“身份”。用binwalk是最快的:

# 扫描固件中的文件签名
binwalk -Me firmware.bin

# 如果binwalk识别不出,试试手动查看文件头
hexdump -C firmware.bin | head -50

binwalk会递归解包,把藏在固件里的文件系统、内核镜像、引导加载程序全扒出来。常见的文件系统有SquashFS、JFFS2、YAFFS2、CramFS。如果是SquashFS,用unsquashfs就能解开。

解包之后,真正的狩猎开始了。我会在文件系统里重点翻这几个目录:

  • /etc/passwd、/etc/shadow —— 本地账户信息,后门账户最爱藏在这里
  • /etc/init.d/、/etc/rc.d/ —— 启动脚本,恶意服务可能在这里注册
  • /bin、/sbin、/usr/bin —— 二进制程序,尤其是名字看起来可疑的(比如“telnetd”、“debugd”)
  • /www、/web —— Web管理界面,硬编码凭据经常出现在CGI脚本或JS文件里

字符串搜索是发现IoC的利器。我会用strings配合正则表达式:

# 搜索所有可打印字符串,过滤出疑似密码或密钥的内容
strings -n 6 firmware_filesystem/* | grep -iE '(password|passwd|pwd|secret|key|token|admin|root|debug)'

# 搜索硬编码的IP地址或域名(C2服务器地址)
strings firmware_filesystem/* | grep -E '([0-9]{1,3}\.){3}[0-9]{1,3}'
重点: 不要只搜明文密码。很多厂商会用Base64或简单的XOR编码“隐藏”凭据。我曾经在一个路由器固件里发现一个叫“cfg_mgr”的二进制文件,用strings没看到任何密码。后来用IDA Pro反编译,发现它把管理员密码用XOR 0x55编码后硬编码在.data段。解码后是“admin:admin123”。这种“掩耳盗铃”式的编码,在IoT固件里太常见了。

3.3 后门账户检测:不只是找“root:root”

后门账户分两种:一种是厂商留下的调试/维护账户,另一种是攻击者植入的。检测方法也不一样。

3.3.1 厂商后门

这类后门通常有固定的用户名和密码,比如“admin:admin”、“root:123456”、“support:support”。我会用一份已知的IoT默认密码字典去碰撞。但更隐蔽的厂商后门,是藏在/etc/shadow里的“幽灵账户”——它的UID是0(root权限),但用户名看起来像普通服务名。

# 检查UID为0的账户
awk -F: '$3 == 0 {print $1}' firmware_filesystem/etc/passwd

# 检查没有密码的账户(密码字段为空)
awk -F: '$2 == "" {print $1}' firmware_filesystem/etc/shadow

嗯,这里要注意。有些厂商会把后门账户的密码哈希值设为一个固定的MD5值,比如“$1$xxxxx”。如果你在shadow文件里看到多个账户共享同一个哈希值,那基本可以断定是后门。

3.3.2 攻击者后门

攻击者植入的后门,通常表现为:

  • 新增了一个不认识的账户(比如“syslogd”、“ftpuser”)
  • 修改了现有账户的密码哈希
  • 在/etc/inetd.conf或/etc/xinetd.d/里添加了远程访问服务

我建议的做法是:拿一份同型号设备的“干净”固件做对比。用diff命令比较两个固件文件系统的/etc目录,任何差异都值得深究。

警告: 不要只依赖自动化工具。我曾经遇到一个案例,攻击者把后门账户的用户名改成了“nobody”,UID也改成了65534(普通用户),但他在/etc/sudoers里给这个账户配置了NOPASSWD权限。这种“伪装成普通账户的超级后门”,自动化脚本很难发现,必须人工审查sudo配置。

3.4 硬编码凭据发现:从源码到二进制

硬编码凭据是IoT固件里最常见的IoC之一。它可能出现在:

  • Web前端的JavaScript文件(比如AJAX请求里写死了Basic Auth的账号密码)
  • CGI脚本或可执行文件(用strings或反汇编查找)
  • 配置文件(XML、JSON、INI文件里明文存储)
  • 动态链接库(.so文件里导出函数中硬编码的密钥)

对于二进制文件中的硬编码凭据,我推荐用radare2或Ghidra做静态分析。以Ghidra为例:

# 在Ghidra中搜索字符串“password”或“key”
# 然后交叉引用(XREF)找到使用该字符串的代码位置
# 检查该代码是否在比较用户输入与硬编码值

为什么会这样?因为很多嵌入式开发者图省事,直接在代码里写:

if (strcmp(user_input, "SuperSecretKey123") == 0) {
    grant_admin_access();
}

这种字符串在二进制里是明文的,strings一搜就出来。但有些开发者会“聪明”一点,把字符串拆成多段,或者用异或运算混淆。这时候就需要动态分析了——在模拟器(比如QEMU)里运行固件,观察内存中的字符串拼接过程。

我的经验: 硬编码凭据往往不止一组。厂商可能为不同权限级别(普通用户、管理员、超级管理员)分别硬编码了凭据。我在一个IP摄像头的固件里发现过三组硬编码:一组用于Web登录(admin/12345),一组用于RTSP流媒体访问(user/pass),还有一组用于ONVIF协议(operator/operator)。攻击者只要拿到其中一组,就能横向移动。

3.5 知识体系:固件层IoC定位全景图

下面这张图,是我自己总结的固件层IoC定位流程。每次做固件分析,我都会按这个框架走一遍,不容易漏东西。

固件层IoC定位流程 1. 固件提取 芯片直读 (SPI/NAND) JTAG/SWD调试接口 OTA/升级包截获 2. 固件解包与分析 binwalk 扫描 文件系统挂载 strings 字符串提取 反汇编/反编译 3. IoC检测与定位 后门账户检测 硬编码凭据发现 C2/后门服务识别 输出:固件层IoC清单

这张图的核心逻辑是:提取是基础,分析是手段,检测是目的。三者缺一不可。很多新手只做到第二步(解包+strings),就以为完事了。其实真正的IoC往往藏在第三步——需要你结合上下文去判断。

总结一下: 固件层的IoC定位,本质上是一场“找不同”的游戏。你拿到的固件,和厂商发布的原始固件之间,任何差异都可能是失陷指标。后门账户、硬编码凭据、异常服务、可疑的启动项——这些都是攻击者留下的脚印。保持怀疑,逐行审查,你总能找到蛛丝马迹。