固件下载地址:
GitHub - ameng929/NOE77101_Firmware
文件目录结构,这里只列出了一些主要的文件信息:
├── bin
├── ftp
├── fw
├── rdt
├── webloader.ini
└── wwwroot
├── SchneiderTFE.zip
├── cgi-bin
├── classes
├── conf
│ ├── Gcnftcop.sys
│ ├── bootp
│ ├── dhcp
│ ├── diag
│ │ └── chkdsk.out
│ ├── exec
│ │ ├── NOE77101.bin
│ │ └── kerVer
│ ...
├── html
│ ├── config.js
│ ...
├── rdt
│ └── rdt.zip
└── secure
注意到 wwwroot/conf/exec 目录下有一个文件 NOE77101.bin ,这就是要分析的固件文件。使用binwalk
命令查看文件内容,是一个Zlib类型的压缩文件:
➜ exec binwalk NOE77101.bin
DECIMAL HEXADECIMAL DESCRIPTION
--------------------------------------------------------------------------------
901 0x385 Zlib compressed data, default compression
用binwalk
提取文件内容,binwalk
会自动解压文件,得到文件夹 _NOE77101.bin.extracted:
➜ exec binwalk -e NOE77101.bin
DECIMAL HEXADECIMAL DESCRIPTION
--------------------------------------------------------------------------------
901 0x385 Zlib compressed data, default compression
➜ exec ls
NOE77101.bin _NOE77101.bin.extracted kerVer
binwalk
自动提取了文件到_NOE77101.bin.extracted目录下,并对其进行解压。此时文件夹下就有两个文件,一个zlib和一个被解压出来的:
➜ _NOE77101.bin.extracted ls
385 385.zlib
然后再用binwalk
查看385文件:
➜ _NOE77101.bin.extracted binwalk 385
DECIMAL HEXADECIMAL DESCRIPTION
--------------------------------------------------------------------------------
2054252 0x1F586C EST flat binary
2088936 0x1FDFE8 HTML document header
2108532 0x202C74 HTML document footer
2110048 0x203260 HTML document header
2115564 0x2047EC HTML document footer
2119528 0x205768 XML document, version: "1.0"
2119796 0x205874 XML document, version: "1.0"
2119912 0x2058E8 XML document, version: "1.0"
2192512 0x217480 Base64 standard index table
2192580 0x2174C4 Base64 standard index table
2211604 0x21BF14 VxWorks WIND kernel version "2.5"
2225264 0x21F470 Copyright string: "Copyright Wind River Systems, Inc., 1984-2000"
2321952 0x236E20 Copyright string: "copyright_wind_river"
3118988 0x2F978C Copyright string: "Copyright, Real-Time Innovations, Inc., 1991. All rights reserved."
3126628 0x2FB564 Copyright string: "Copyright 1984-1996 Wind River Systems, Inc."
3153524 0x301E74 VxWorks symbol table, big endian, first entry: [type: function, code address: 0x1FF058, symbol address: 0x27655C]
得知文件是VxWorks固件,符号表位置在0x301E74处,稍后会用到。
然后使用binwalk
查看架构,得知是PowerPC big endian:
➜ _NOE77101.bin.extracted binwalk -A 385
....
2045960 0x1F3808 PowerPC big endian instructions, function epilogue
2045968 0x1F3810 PowerPC big endian instructions, function prologue
2046180 0x1F38E4 PowerPC big endian instructions, function epilogue
3150948 0x301464 PowerPC big endian instructions, function epilogue
之后用IDA打开385文件,在打开时设置架构:
然后要求设置RAM和ROM,其实就是设置加载基地址:
在IDA中无法识别出任何函数,需要在程序开头位置按一下 “c” 键,就可以显示部分函数,但没有解析出所有的函数:
此时可以通过三种方式获得加载基地址:
- 通过跳转表获得基地址、通过字符串引用获得基地址
固件安全之加载地址分析 – 绿盟科技技术博客
- 使用IDA的Vxhunter插件
vxhunter/firmware_tools at master · PAGalaxyLab/vxhunter
这里为了方便选择Vxhunter插件,选择python版本下载后复制到plugin文件夹下,然后运行插件:
得到加载地址是0x10000:
然后发现依然没有解析函数,此时需要恢复函数名称。使用IDA脚本:
#coding=utf-8
from idaapi import *
from idc import *
symbol_interval = 16 #符号表间隔
load_address = 0x10000 #固件内存加载基址
symbol_table_start = 0x31eec4 + load_address #符号表起始地址
symbol_table_end = 0x348114 + load_address #符号表结束地址
ea = symbol_table_start
eaEnd = symbol_table_end
while ea < eaEnd:
offset = 0 #4个字节为一组数据
#将函数名指针位置的数据转换为字符串
create_strlit(get_wide_dword(ea-offset), BADADDR)
#将函数名赋值给变量sName
sName = get_strlit_contents(get_wide_dword(ea))
print(sName)
if sName:
#开始修复函数名
eaFunc = get_wide_dword(ea - offset +4)
set_name(eaFunc, sName)
create_insn(eaFunc)
ida_funcs.add_func(eaFunc, BADADDR)
ea += symbol_interval
代码中的符号表起始地址和符号表结束地址需要手动修改一下,可以在16进制编辑器中查看。在binwalk分析的时候得到符号表地址为0x301E74,然后在文件中找到这个位置,0x301E74即起始位置:
符号表每0x10为一组,一直找到结束的位置0x3293a4:
然后执行IDA脚本:
最后恢复完成:
在usrAppInit
函数中发现多处loginUserAdd
添加用户,这些字符串即后门账号和密码:
总结
此固件分析关键点在于确定程序基地址和如何恢复符号信息,只要恢复了符号信息就和阅读源码无异了。
References
固件符号表恢复
https://bbs.pediy.com/thread-266803-1.htm
固件安全之加载地址分析 – 绿盟科技技术博客
施耐德PLC以太网模块后门账户解密 – 灯塔实验室
https://p1kk.github.io/2021/06/11/iot/施耐德 NOE771/