假设:文件被加密
1. 没有压缩签名
Binwalk检测到的相关压缩格式如下:bzip2、lzop、lzip、lrzip、LZO、7z、gzip、rzip、LZMA、zlib、LZ4。由于运行 Binwalk 不会H201LV2.0_Cur_config.bin
返回任何结果,即使 Binwalk 通常会识别这些压缩格式中的任何一种,这是第一个指示除压缩之外或除压缩之外正在发生的事情。
但是,每个工具都有其局限性,因此我尝试使用来自 zenhax.com 论坛帖子中的信息手动查找文件头中指示压缩字节序列开头的字节序列,该帖子名为如何用眼睛识别压缩算法,特别寻找 Bzip2、zlib、gzip、LZMA、LZMA 86 头、LZMA 86 dec、LZMA 86 dec 头、LZMA efs、LZMA 无头、LZMA2 和 LZMA2 无头压缩签名。以下是每个压缩签名的前几个字节:
- zlib:
78 da
- 压缩包:
1f 8b
- LZMA、LZMA 86 头、LZMA 86 dec、LZMA 86 dec 头、LZMA efs:
5d 00 00 00
- LZMA 无头:
00 44 94 a6
- LZMA2:
18 e0 07 ce
- LZMA2 无头:
e0 07 ce 02
SO 上这个问题的答案中有关压缩的信息也很有帮助:如何检测文件上使用的压缩类型?(如果没有指定文件扩展名)
通过“文件头”,我的意思是前 300 个字节左右(这个问题被用作参考:RE Compressed backup file,router linux based so is it compressed with zlib?因为这个问题也是 Vido 提出的,涉及中兴通讯找到路由器固件及其压缩签名)。不幸的是,盯着文件的十六进制转储并没有产生任何有用的信息。
2. 其他来源的证据
黑山论坛上名为ZTE zxv10 h201 的帖子的第 3 页包含一些相关帖子以及这个有问题的 Python 脚本:
import re
import sys
import zlib
import struct
ime_fajla = 'H201LV2.0_Cur_config.bin'
def extract_config_xml(config_bin):
config_xml = b''
for zlib_chunk in re.finditer('\x78\xda', config_bin):
zlib_chunk_start = zlib_chunk.start()
zlib_chunk_header = config_bin[zlib_chunk_start - 12: zlib_chunk_start]
xml_chunk_length, zlib_chunk_length, config_bin_length = \
struct.unpack('>LLL', zlib_chunk_header)
if xml_chunk_length == 0x10000 or config_bin_length == 0:
zlib_chunk_end = zlib_chunk_start + zlib_chunk_length
zlib_chunk = config_bin[zlib_chunk_start: zlib_chunk_end]
xml_chunk = zlib.decompress(zlib_chunk)
assert xml_chunk_length == len(xml_chunk)
config_xml += xml_chunk
return config_xml
with open(ime_fajla, 'rb') as f:
print extract_config_xml(f.read())
修复它看起来像这样:
# decompress.py
import re
import sys
import zlib
import struct
filename = "H201LV2.0_Cur_config.bin"
def extract_config_xml (filename):
config_xml = b''
for zlib_chunk in re.finditer ('\x78\xda', filename):
zlib_chunk_start, zlib_chunk.start = ()
zlib_chunk_header = filename[zlib_chunk_start - 12: zlib_chunk_start]
xml_chunk_length, zlib_chunk_length, config_bin_length, \
struct.unpack ('> LLL', zlib_chunk_header)
if xml_chunk_length == 0x10000 or config_bin_length == 0:
zlib_chunk_end = zlib_chunk_start + zlib_chunk_length
zlib_chunk = filename[zlib_chunk_start: zlib_chunk_end]
xml_chunk = zlib.decompress(zlib_chunk)
assert xml_chunk_length == len(xml_chunk)
config_xml += xml_chunk
return config_xml
with open (filename, 'rb') as f:
print extract_config_xml(f.read())
这个脚本在这种情况下没有帮助,主要是因为它搜索字节序列78 da
,zlib 压缩签名,它不存在于相关文件中H201LV2.0_Cur_config.bin
。
类似的 config.bin 文件非常稀少且难以找到,但找到并调查了一些文件。最有趣和最有用的是一个名为 的文件H201LV2.0.bin
,通过DropBox共享。这是两个文件的标题的差异:
有趣的是,在偏移量处有一个 16 字节的序列0x00003214
(如果文件真的被加密,这可能吗?看起来很奇怪):
当 Binwalk 运行时,H201LV2.0.bin
它同样不成功:
$ binwalk H201LV2.0.bin
DECIMAL HEXADECIMAL DESCRIPTION
--------------------------------------------------------------------------------
此外,还有另一篇名为ZTE 加密备份配置文件的RE.SE 帖子,涉及不同产品 ZTE Speedport Entry 2i 的 ZTE 配置备份,该产品也被怀疑被加密。在此问题下的评论中的链接中共享的 config.bin 文件也具有类似的标头结构,H201LV2.0_Cur_config.bin
但似乎来自较旧的固件版本。其他人似乎在同一问题上遇到困难。
3. 数据熵和熵分析
SE 超级用户博客上有一篇关于压缩和加密的有趣文章。从文中可以看出两点:
- 压缩搜索模式并用代表这些模式的较小标记替换它们
- 加密会混淆数据,理想情况下会创建一个没有可辨别模式的输出
可以使用统计方法尝试区分压缩和加密。这已经在devttys0的 2 篇文章中在固件分析的上下文中讨论过:
从第一篇文章:
...有一些测试可以用来量化数据的随机性。我发现最有用的两个是卡方分布和蒙特卡罗 pi 近似。这些测试可用于测量数据的随机性,并且比视觉熵分析对随机性偏差更敏感。
和
现有的工具,例如 ent,将为我们执行这些计算。真正的问题是如何解释结果;加密数据与压缩数据的随机性如何?这将取决于所使用的加密/压缩以及数据集的大小(更多数据通常意味着更准确的结果)。将这些测试应用于已通过不同压缩/加密算法的不同大小的(不可否认的小)文件样本显示以下相关性:
卡方分布的大偏差或蒙特卡罗近似中的大百分比误差是压缩的确定迹象。
非常准确的 pi 计算(< .01% 错误)是加密的确定标志。
较低的 chi 值 (< 300) 和较高的 pi 误差 (> .03%) 表示压缩。
较高的 chi 值 (> 300) 和较低的 pi 误差 (< .03%) 表示加密。
这些值范围可用作文件分析中的试探法。
这是使用 Binwalk 对 进行熵分析的结果H201LV2.0_Cur_config.bin
:
$ binwalk -E -J H201LV2.0_Cur_config.bin
DECIMAL HEXADECIMAL ENTROPY
--------------------------------------------------------------------------------
1024 0x400 Rising entropy edge (0.972587)
并使用ent
:
$ ent H201LV2.0_Cur_config.bin
Entropy = 7.981641 bits per byte.
Optimum compression would reduce the size
of this 19716 byte file by 0 percent.
Chi square distribution for 19716 samples is 650.33, and randomly
would exceed this value less than 0.01 percent of the times.
Arithmetic mean value of data bytes is 126.7613 (127.5 = random).
Monte Carlo value for Pi is 3.133292757 (error 0.26 percent).
Serial correlation coefficient is 0.039397 (totally uncorrelated = 0.0).
概要:根据图表,字节偏移量(十进制)~1000 到~19000 之间的熵分布相当均匀。这是加密数据所预期的:
加密数据通常是一条没有变化的平线
卡方分布为650.33,pi 误差为0.26。卡方值是对目标的期望是什么与加密的数据,但PI误差值是非常遥远的目标,根据devttys0:
较高的 chi 值 (> 300) 和较低的 pi 误差 (< .03%) 表示加密。
部分问题是 ~20KB 的小文件大小和文件头中的低熵,我们知道它没有加密。从分析中排除已知未加密的数据将提高准确性。加密看起来像是在 offset 附近开始0x00000124
,因此可以编写一个 python 脚本跳过前 292 个字节并将其余部分写入辅助文件:
#!/usr/lib/python
with open("H201LV2.0_Cur_config.bin", "rb") as input_file:
with open("auxiliary_H201LV2.0_Cur_config.bin", "wb") as output_file:
output_file.write(input_file.read()[292:])
现在可以只对(可疑的)加密数据块进行分析,而没有未加密的文件头:
$ binwalk -E -J auxiliary_H201LV2.0_Cur_config.bin
DECIMAL HEXADECIMAL ENTROPY
--------------------------------------------------------------------------------
0 0x0 Rising entropy edge (0.973372)
与ent
:
$ ent auxiliary_H201LV2.0_Cur_config.bin
Entropy = 7.990521 bits per byte.
Optimum compression would reduce the size
of this 19424 byte file by 0 percent.
Chi square distribution for 19424 samples is 256.03, and randomly
would exceed this value 47.01 percent of the times.
Arithmetic mean value of data bytes is 128.0505 (127.5 = random).
Monte Carlo value for Pi is 3.143651529 (error 0.07 percent).
Serial correlation coefficient is 0.011183 (totally uncorrelated = 0.0).
这些结果很有趣:该图表明整个文件的熵大致均匀,但现在卡方分布 ( 256.03 ) 和 pi 近似误差 ( 0.07% )都在压缩数据的预期范围内!
较低的 chi 值 (< 300) 和较高的 pi 误差 (> .03%) 表示压缩。
话虽如此,这些新值相对接近于它们各自的边界条件。也就是说,256.03 比较接近卡方分布的 300 边界条件,0.07% 比较接近 pi 近似误差的 0.03% 边界条件,所以很难有把握地说文件真的被加密了或如果基于此进行压缩。
结论
支持文件被加密的假设的证据被熵分析的一些结果混淆了。因此,我敢保证该文件已加密,但我无法使用我在此处描述的方法来证明它。
我希望这些发现(或缺乏这些发现)对其他人对该文件进行自己的调查有用。也许专业人士能够明确回答这个有趣的问题。
建议,其他途径
你对我应该尝试什么有什么建议吗?
1. 更严谨的统计分析
熵分析虽然有用,但还不够;应采用额外的统计方法:
信息熵通常用作随机性的初步测试。一般来说,随机数据会具有高水平的信息熵,低水平的信息熵是数据不是随机的一个很好的指标。(低水平的熵并不能确定数据不是随机的,但这意味着您应该保持怀疑并将生成器提交给进一步的测试。)
然而,逆关系不成立,这意味着高度的信息熵并不能保证随机性。例如,压缩文件(例如,ZIP 文件)具有高水平的信息熵,但实际上是高度结构化的,并且它无法通过许多其他随机性测试。因此,您必须小心使用信息熵作为随机性的度量。要获得有意义的结果,您确实需要将其与其他测试结合起来。
2.恢复加密模块
对中兴加密备份配置文件的回答中的这个推测可能提供了一个调查的途径:
我想执行加密的核心功能在 ZTE 路透社中是相同的(common config.bin 表明了这一点),所以想象这只是弄清楚方法的一个案例,以及使用什么密钥/iv 再次对其进行解密。 ..
如果发现固件中负责执行加密的模块,则可以对加密算法进行逆向工程。鉴于缺乏易于获得的中兴路由器固件映像,我认为为此需要访问该设备。
3. 密文分析
我没有追求的是使用bfcrypt或FindCrypt等工具分析(疑似)密文,以确定用于加密文件的加密算法。更多工具的列表可以在fwhacking.blogspot.com.br上找到。
说到分析密文,我认为 Security.SE 上的这个问题很有趣:如何确定使用了什么类型的编码/加密?,特别是答案。
快速更新:
这些加密库动态链接到cspd
MIPS ELF 二进制文件:
$ readelf --dyn-syms cspd | grep AES
484: 0053ab50 1248 FUNC GLOBAL DEFAULT 8 AES_set_encrypt_key
630: 0053b9d0 1600 FUNC GLOBAL DEFAULT 8 AES_decrypt
1187: 0050d470 552 FUNC GLOBAL DEFAULT 8 DecryByAES
1527: 0053b390 1600 FUNC GLOBAL DEFAULT 8 AES_encrypt
1535: 0053b030 864 FUNC GLOBAL DEFAULT 8 AES_set_decrypt_key
这些压缩库也是如此:
$ readelf --dyn-syms cspd | grep compress
92: 0053c110 208 FUNC GLOBAL DEFAULT 8 uncompress
1064: 0053c010 216 FUNC GLOBAL DEFAULT 8 compress2
uncompress
并compress2
与zlib相关联。