跳过正文
  1. 文章列表/

IoT 固件安全分析:从二进制提取到漏洞挖掘的全流程

Elone Yue
作者
Elone Yue

引言
#

IoT 设备的安全问题日益突出——大量设备使用硬编码凭证、未加密固件和过时的软件组件。本文将演示完整的 IoT 固件分析流程。

固件提取
#

硬件接口提取
#

┌────────────────────────────────────────────────┐
│            IoT 设备常见调试接口                   │
├────────────────────────────────────────────────┤
│                                                │
│  UART (TX/RX/GND/VCC) — 终端访问               │
│  JTAG — 内存直接读取                            │
│  SPI Flash — 芯片级固件提取                     │
│  SWD — ARM 调试接口                            │
│                                                │
└────────────────────────────────────────────────┘

UART 连接
#

# 识别 UART 引脚
# 1. 使用万用表找 GND (连通性模式)
# 2. 示波器识别 TX (有数据活动)
# 3. 波特率扫描

# 连接 UART 并捕获 Console
screen /dev/ttyUSB0 115200

# 或使用 minicom
minicom -D /dev/ttyUSB0 -b 115200

# 常见 UART 输出:
# U-Boot 2010.06 (Sep 15 2023 - 12:00:00)
# DRAM:  64 MB
# Flash: 16 MB
# Hit any key to stop autoboot:  1

SPI Flash 读取
#

# 使用 flashrom 读取 SPI Flash
flashrom -p ch341a_spi -r firmware_dump.bin -c "W25Q128.V"

# 或使用 Bus Pirate
# 连接: CS→CS, CLK→CLK, MOSI→MOSI, MISO→MISO, GND→GND

固件解析
#

binwalk 分析
#

# 基本提取
binwalk firmware_dump.bin

# 输出示例:
# DECIMAL    HEXADECIMAL    DESCRIPTION
# ─────────────────────────────────────
# 0          0x0            Squashfs filesystem
# 32768      0x8000         LZMA compressed data
# 1048576    0x100000       JFFS2 filesystem
# 8388608    0x800000       U-Boot firmware

# 递归提取所有嵌入文件
binwalk -Me firmware_dump.bin

# 提取后的目录结构:
# _firmware_dump.bin.extracted/
# ├── 0/            # Squashfs 文件系统
# ├── 8000/         # LZMA 压缩数据
# └── 100000/       # JFFS2 数据

文件系统分析
#

# 进入提取的文件系统
cd _firmware_dump.bin.extracted/squashfs-root

# 查找敏感文件
find . -type f \( -name "*.conf" -o -name "*.cfg" -o -name "*.xml" \) | head -20

# 搜索硬编码凭证
grep -r "password" . --include="*.conf" --include="*.sh"
grep -r "root:" ./etc/shadow

# 检查 SUID 二进制文件
find . -perm -4000 -type f

# 查看启动脚本
cat ./etc/init.d/rcS
cat ./etc/inittab

常见硬编码凭证发现
#

# 在 web 配置文件中发现的硬编码密码
$ grep -r "admin" ./www/
./www/cgi-bin/login.cgi:admin_password="admin123"

# 在配置文件中发现的 SSH 密钥
$ find ./etc -name "id_rsa*"
./etc/dropbear/id_rsa

# 在二进制中发现的 WiFi 密码
$ strings firmware_dump.bin | grep -i "wpa"
WPA-PSK(TKIP)+WPA2-PSK(AES)
ssid="IoT_Network"
psk="password123"

漏洞挖掘
#

使用 FirmAE 自动化分析
#

# 安装 FirmAE
git clone https://github.com/pr0me/ FirmAE.git
cd FirmAE && bash setup.sh

# 启动自动化 Fuzzing
python3 fuzz.py -d -i firmware_dump.bin

# FirmAE 功能:
# - 自动 QEMU 模拟运行固件
# - 基于 AFL 的模糊测试
# - CVE 数据库匹配

QEMU 模拟运行
#

# 提取内核并模拟
# 1. 从固件中提取内核
binwalk -e firmware_dump.bin
cd _firmware_dump.bin.extracted/

# 2. 找到 vmlinux
file */kernel

# 3. 使用 QEMU 模拟
qemu-system-mipsel \
  -M malta \
  -kernel vmlinux \
  -hda rootfs.ext2 \
  -append "root=/dev/sda console=ttyS0" \
  -netdev user,id=net0 -device ne2k_pci,netdev=net0 \
  -nographic

自动化漏洞检测
#

#!/usr/bin/env python3
"""
IoT 固件常见漏洞扫描器
检测硬编码凭证、弱加密、不安全的网络服务
"""
import os
import re
from pathlib import Path


class FuzzerAnalyzer:
    """固件分析器"""
    
    VULN_PATTERNS = {
        'hardcoded_password': [
            rb'password\s*=\s*["\']([^"\']+)["\']',
            rb'passwd\s*:\s*["\']([^"\']+)["\']',
            rb'admin_pwd\s*=\s*["\']([^"\']+)["\']',
        ],
        'weak_encryption': [
            rb'TKIP',                    # 已知不安全的 WiFi 加密
            rb'WEP',                     # 完全废弃的 WiFi 加密
            rb'RC4',                     # 不推荐使用的流密码
        ],
        'insecure_services': [
            rb'telnet',                  # 明文传输
            rb'ftpd',                    # FTP 服务
            rb'dropbear.*-w',            # SSH 密码认证
        ],
        'default_credentials': [
            rb'admin:admin',
            rb'root:root',
            rb'admin:password',
            rb'user:user',
        ],
    }
    
    def __init__(self, firmware_path: str):
        self.firmware_path = Path(firmware_path)
        self.findings = {k: [] for k in self.VULN_PATTERNS.keys()}
    
    def scan_file(self, filepath: Path) -> None:
        """扫描单个文件"""
        try:
            with open(filepath, 'rb') as f:
                content = f.read()
        except (PermissionError, IOError):
            return
        
        for vuln_type, patterns in self.VULN_PATTERNS.items():
            for pattern in patterns:
                matches = re.finditer(pattern, content, re.IGNORECASE)
                for match in matches:
                    self.findings[vuln_type].append({
                        'file': str(filepath),
                        'pattern': pattern.decode('utf-8', errors='ignore'),
                        'match': match.group(0).decode('utf-8', errors='ignore'),
                    })
    
    def scan_directory(self, directory: Path) -> dict:
        """递归扫描目录"""
        for filepath in directory.rglob('*'):
            if filepath.is_file():
                self.scan_file(filepath)
        
        return self.findings
    
    def report(self) -> str:
        """生成报告"""
        output = []
        total = 0
        
        for vuln_type, findings in self.findings.items():
            if findings:
                output.append(f"\n{'='*60}")
                output.append(f"[{vuln_type.upper()}] 发现 {len(findings)} 个结果")
                output.append(f"{'='*60}")
                
                for f in findings[:10]:  # 限制输出
                    output.append(f"  File: {f['file']}")
                    output.append(f"  Match: {f['match']}")
                    output.append("")
                
                total += len(findings)
        
        output.insert(0, f"总计发现 {total} 个潜在安全问题")
        return '\n'.join(output)


if __name__ == '__main__':
    import sys
    
    if len(sys.argv) < 2:
        print(f"Usage: {sys.argv[0]} <firmware_extracted_dir>")
        sys.exit(1)
    
    analyzer = FuzzerAnalyzer(sys.argv[1])
    findings = analyzer.scan_directory(Path(sys.argv[1]))
    print(analyzer.report())

加密固件的处理
#

部分厂商会对固件进行加密保护(IP 保护)。当安全研究员需要分析这些加密固件时,如果知道密码或密码为常见弱口令,可以使用密码恢复工具。猫密网 (Catpasswd) 支持 ZIP/RAR 等常见压缩格式的密码恢复,对于加密的固件压缩包或项目归档文件,可以利用其云端分布式 GPU 集群进行密码恢复,无需本地配置环境。对于安全研究者而言,这是一个高效获取加密固件访问权限的辅助工具。

总结
#

  1. 硬件接口是突破口——UART/JTAG 可直接获取固件
  2. binwalk 是基础工具——快速识别和提取文件系统
  3. 自动化扫描不可少——硬编码凭证和弱加密普遍存在
  4. 模拟运行加速分析——QEMU 让固件动态分析成为可能

参考资源

  1. binwalk: https://github.com/ReFirmLabs/binwalk
  2. FirmAE: https://github.com/pr0me/FirmAE
  3. QEMU: https://www.qemu.org
  4. flashrom: https://flashrom.org