原来的:
通过 breenmachine@foxglovesecurity
译者:Serene@知道创宇404室
非技术人员热衷于推销产品或服务的技术特性,但有时营销走得太远,需要加以控制。如果打破这个规则,就会导致 FUD(恐惧不确定性和怀疑)市场:
“这个狼”
上面的宣传视频“狼来了”处处表明惠普打印机是安全的,购买非惠普打印机就接近于疏忽犯罪。例如,开篇的黑白文字写着“世界上有数亿台商用打印机,只有不到2%是安全的”,从这里开始,视频中的“狼”执行了一系列不太可能的攻击,利用不安全的打印机访问公司网络和敏感数据,显然意味着 HP 打印机对这些攻击免疫。
尽管“Printer Hacking Wiki”() 和相关的 PRET() 工具包提供了非常好的资源,但似乎没有人深入研究现代 HP 商用打印机的安全性来验证 HP 的安全声明。
所以我们买了两台打印机,MFP-586() 和 M553(),正如惠普视频中的“狼”所说,“狩猎开始了”。
本文提到的RCE漏洞已于2017年8月21日报告给惠普,惠普已修复并发布安全公告:本文涉及的所有代码均放在Github上:
1. 打印机攻击向量
在上面的视频及其续集中打印机无法设置默认,“狼”执行了一系列不太可能的攻击。忽略这些攻击是无缘无故且非常不切实际的事实,让我们看看以下相关的打印机安全问题:
接下来,针对上述 2 种攻击向量,我们将重点关注在现代 HP 打印机上测试过的一系列安全问题。
2.测试常见的打印机漏洞
我们首先审查了打印机中现有的安全空间,并在此过程中发现了“打印机开发工具包”- PRET。该工具包包含许多预定义的攻击方法,可以针对来自不同制造商的打印机。它更像是常见攻击的模板,而不是特定打印机的特定漏洞。因此,我们需要做一些研究,看看 HP 打印机可能会受到哪些漏洞的影响。
在 PRET 工具包中发现了以下问题:
目录遍历 - 远程存储的打印作业披露
PRET 工具包具有三种模式,每种模式都指定工具包将尝试与打印机通信的“语言”。这些模式是打印机作业语言 (PJL)、PostScript (PS) 和 PCL。每种模式都有一组不同的常见漏洞和一些常见问题。PJL 是一种允许计算机在打印作业时与打印机进行通信的语言,而且这种语言还经过扩展,能够执行一些管理任务。PJL的功能之一是对打印机上文件的管理非常有限,例如存储和删除文件的能力,但仅限于特定位置,这是使用PJL在文件系统上无法逃脱的一个小“监狱”语。
从上面的截图来看,当我们列出“/”目录下的文件时,在根目录下,我们只能看到“PostScript”目录。
这里的一个常见漏洞是“目录遍历”,它涉及请求对文件和目录名称进行特殊操作以试图逃脱这个“监狱”。我们在两台 HP 打印机上发现了一个目录遍历序列,如下所示:
遗憾的是,此时无法检索文件内容或写入任何文件,任何尝试都将导致打印机崩溃并重新启动。
进一步排查,发现只能在一个特定路径下获取文件内容,对目录遍历顺序稍作修改:
这里的“Jobs”目录是存储打印作业的地方,通过 PRET 可以检索打印机上存储的任何作业的内容,如下所示:
对“PIN 保护”作业和不安全作业的测试产生了相同的结果,使得保护打印作业的安全功能变得不那么诱人了。
PostScript 作业操作
某些类型的打印作业可以在打印前自动处理。例如,网络上的任何人都可以在所有打印作业的页面上放置任意图像和字体,如下所示,其中水印“FOO”不是要打印的原始文档的一部分:
不安全的出厂重置功能
PRET 工具包似乎包含两个未记录的或至少不明显的方法,用于将 HP 打印机重置为出厂默认设置,从而将“管理员”密码重置为默认的无密码。这可以通过 PJL 接口和 SNMP 实现,默认情况下它们是不安全的,即使已在设备上设置了管理密码。
除此之外,即使管理员已保护 PJL 和 SNMP 接口,也可以将 SNMP 社区字符串重置为默认值“public”!这可以通过利用 HP 一项鲜为人知但默认启用的功能来实现,该功能允许在启动时通过 DHCP 或 BOOTP 服务器重新配置打印机。
每次打印机启动时,当它从 DHCP 服务器获取 IP 地址时,它还会在 DHCP 响应中查找一些特殊的配置选项。其中一个选项指定了一个 TFTP 服务器,打印机可以从该服务器检索应用各种配置设置的配置文件。在这些设备的详细手册中,惠普正确地声明任何手动配置的设置都优先于 DHCP 配置的设置。但是,DHCP 配置中有一些选项允许清除手动配置的设置,包括以下内容:
启用这些选项的 DHCP 服务器配置文件将与项目代码一起发布在 GitHub 上()
3.不安全的默认设置
受先前测试结果的启发,我们想看看是否可以找到可应用于打印机的安全设置组合,以防止上述攻击。具体来说,找出管理员应该如何做才能使任何用户都无法重设“管理员”密码。
我们发现这是可能的,但现实世界中的管理员不太可能成功锁定这些打印机的管理界面,至少他们需要更改以下默认设置,并注意没有迹象表明这些设置与 Security 有什么关系的用户相关联。我们将在管理菜单中显示完整路径,以演示这些设置在打印机中的隐藏程度:
如果忽略上述任何一项,网络上的攻击者就有可能重置设备,从而获得管理访问权限。
4. 深入挖掘:提取操作系统和固件
我们在打印机上花费了数千美元,并且在发现 RCE 漏洞之前不会停止研究。第一步是获取打印机上实际运行的代码,看起来 HP 已经采取了一些措施来防止用户从打印机中提取操作系统和固件,尽管我们可以绕过这些限制。
首先,HP 发送的设备还包括符合 FIPS 标准的加密硬盘驱动器。当插入这些特殊驱动器之一时,驱动器上的所有数据都会被加密。如果移除驱动器,则没有加密密钥。任何人都无法读取数据。此外,即使我们能够设置或恢复此密钥,正在使用的加密细节也不清楚,需要在从驱动器读取数据之前发现。
相反,我们只是从 HP 移除了支持 FIPS 的驱动器,并插入了一个不支持加密的普通东芝笔记本电脑硬盘:
重启设备后,我们可以告诉打印机将操作系统和固件从 USB 密钥安装到新的未加密驱动器上:
关闭打印机,卸下驱动器,然后将许多文件从驱动器读取到标准 PC。然而,一些更有趣的文件仍然难以捉摸,尤其是“/Windows/”和“/Core/bin”目录中的 HP DLL 文件,我们知道这些文件的存在是因为我们的目录遍历漏洞可以在 PRET 中被利用看到它们:
不幸的是,当驱动器插入 PC 时,我们没有找到这些目录。经过广泛调查,我们应用了两种不同的方法从这两个来源检索文件。
检索/视窗/
第一个是 Windows 目录,Linux 实用程序“grep”用于搜索对 Windows 目录中存在的各种文件的引用:
文件“NK.bin”似乎每次都返回,经过一番调查发现打印机上运行的操作系统是Windows CE 的一个版本,Windows CE 内核存储在/CEKERNEL/NK.bin 中。我们可以使用公开可用的工具 Nkbintools 来提取此 Windows CE 内核的内容并检索 Windows 目录的确切内容:
检索/Core/bin
目录/Core/bin 的内容更难检索。当硬盘连接到 PC 时,/Core/bin 目录实际上是可见的,但是与 /Windows/ 目录不同,它是空的:
在无法弄清楚为什么该目录看起来是空的之后,我们又进行了一次尝试。
首先,我们查看硬盘上与/Core/关联的分区:
下一步是使用 Linux“dd”实用程序拍摄该分区的映像,它完全忽略文件系统并拍摄分区的原始映像,将其保存到本地文件。
最后,应用了一种称为“文件雕刻”的技术,该技术通常用于硬盘部分故障或文件系统损坏时的数据恢复。我们使用的工具称为“scalpel”,它指定了一个配置文件来“分解”在原始磁盘映像“image.bin”中发现的任何可疑 DLL 文件。结果似乎有数百个 DLL 文件,其中许多是无效的,并且都有一个数字而不是文件名:
由于我们最感兴趣的是 .NET DLL 文件,因此可以使用“monodis”工具来尝试反汇编每个 DLL,只打印有效 DLL 文件及其名称的列表。虽然脚本的输出很乱,但足以确认我们已经提取了我们正在寻找的 DLL 文件:
5.固件和惠普软件“解决方案”逆向工程
通过访问设备上运行的代码,我们可以开始深入了解打印机中可能导致远程代码执行的一些功能,尤其是与惠普软件“解决方案”安装和固件更新相关的功能。
HP 软件解决方案利用 HP 的 OXP 平台和 SDK 来扩展打印机的功能,第三方公司可以开发这些解决方案,但 SDK 的访问权限由 HP 严格控制,并且 SDK 开发的任何最终版本的软件都必须经过签名在它可以安装到打印机上之前由 HP 提供 另一方面,如果我们能找到绕过这些控件的方法,我们就可以创建一个适用于所有现代 HP 打印机的恶意解决方案。
过去,恶意固件更新一直是在各种打印机上获得代码执行的一种方法。惠普已经转向新的固件更新平台和文件格式,似乎没有安全研究人员对其进行详细审查。
BDL格式逆向工程
HP 解决方案和固件更新都包含一个扩展名为“.BDL”(捆绑包)的文件。这是一种没有公开文档的专有二进制格式,我们决定对这种文件格式进行逆向工程,这将使我们深入了解固件更新和软件解决方案的构成。
由于固件文件又大又复杂,为简单起见,我们首先获取第 3 方软件解决方案“ThinPrint”的副本,与 81MB 的固件更新文件相比,该文件具有 2.1MB 的“BDL”文件。首先,我们在 BDL 文件上使用了一个名为 binwalk 的工具,它会检查二进制文件并尝试提取其中包含的任何已知文件格式。binwalk 是专门为对这些类型的包进行逆向工程而开发的,该工具输出一个包含以下内容的 ZIP 文件:
我们在十六进制编辑器中手动检查了 zip 文件和 BDL 文件,以确定 ZIP 文件在 BDL 文件中的位置:
(ZIP 文件由十六进制编辑器中的 binwalk 提取并显示 CRC-32 校验和)
(BDL 文件突出显示 ZIP 部分并计算 CRC-32)
请注意,在上面的两个屏幕截图中,我们已经在十六进制编辑器中计算了所选部分的“CRC-32”校验和。在第一种情况下,对于 ZIP 文件,CRC-32 校验和是在整个文件上计算的。在第二种情况下,对于 BDL 文件,CRC-32 是在我们怀疑包含压缩文件的部分计算的(基于前几个字节匹配)。当两个 CRC-32 校验和达到相同的“6D AC 9A 2F”值时,我们的猜想得到证实。
还要考虑上面十六进制编辑器中用红色圈出的部分,注意“2F 9A AC 6D”出现在 ZIP 文件的开头之前,它只是 ZIP 文件的 CRC-32 校验和,其字节顺序颠倒了。
看到这里,我们对zip文件做了一个小修改(只是修改了其中一个文件的内容),计算修改后的ZIP的CRC-32校验和,将BDL中的ZIP文件替换为修改后的ZIP文件。BDL 文件中的 CRC-32 校验和被更新以匹配新修改的 ZIP 文件,BDL 文件被上传到打印机。
不幸的是没有成功,出现以下错误:
进一步调查在打印机调试日志文件中发现以下内容:
显然有一个额外的 CRC 校验和在 ZIP 文件被替换时被损坏。经过调查,包括编写自定义 python 脚本来识别文件中的 CRC-32 校验和,在 ThinPrint BDL 文件中推导出以下字段:
仅具备上述知识还不够,当 BDL 文件上传到打印机时,更新所有校验和,上面列出的长度仍然会导致某种校验和失败。
这里我们决定另辟蹊径,理论上可以创建一个与原始 ZIP 文件具有相同长度和 CRC-32 校验和的 ZIP 文件,并且如果创建了,则无需更新 BDL 中的任何字段文件!
我们用 Python 编写了一个自定义工具来完成这项工作,它位于我们的 Github 存储库 ( ) 中。该工具允许修改原始 BDL 文件,方法是将其替换为具有相同长度和 CRC-32 校验和但内容任意不同的 ZIP 文件。这个工具有点像 hack,可能只适用于 ThinPrint BDL。
以这种方式修改的 BDL 文件被上传到打印机并确认可以工作,但没有对代码进行恶意更改。当我们尝试替换任何 ZIP 中的 DLL 文件时,我们会收到 DLL 签名验证错误。
6.逆向工程固件签名验证
一旦我们对 BDL 文件的工作原理有了大致的了解,我们就开始检查固件更新过程和周围的安全控制。首先,我们刚刚在十六进制编辑器中查看了惠普的固件更新文件,相关文件类型为“.BDL”,指出文件末尾有一个签名块:
此签名块不在“ThinPrint”解决方案 BDL 中,这说明软件解决方案包和固件可能会有不同的处理方式。
从签名块中的信息来看,似乎正在使用该文件的行业标准签名验证,特别是使用 SHA256 的 RSA。但是,使用安全加密算法的事实并不意味着该文件已通过安全验证。一些常见的实施错误可能导致不安全的签名验证。
为了找出代码中执行签名验证的位置,我们将仔细操作的固件文件上传到设备,注意不要以与 ThinPrint 解决方案类似的方式使校验和或长度无效。走到这一步会从打印机的调试日志中产生以下错误:
查看从打印机中提取的反编译代码,确定这条消息是在类文件HP.Mfp.Services.Installation.Fim.Fim中产生的:
进一步的逆向工程将我们带到了执行签名验证的地步,在快速审查代码后,我们没有发现允许绕过或操纵固件签名验证的严重错误。
HP 解决方案包的 DLL 签名验证逆向工程
我们对 BDL 格式进行了部分逆向工程,在打印机上执行恶意代码的第一步显然是用修改后的 DLL 文件替换 BDL 中打包的一个 DLL 文件,但是这没有成功,在打印机调试日志中,发生以下错误:
这条详细的错误消息直接将我们指向了正在执行签名验证的代码位置,“HP.ExtLib.Package.Process”:
深入挖掘打印机无法设置默认,我们检查了“signedObject.ValidatePeSignature”下的代码:
快速查看这段代码,我们怀疑这里可能存在一些问题。在第 11 行,从 DLL 文件的第 60 个字节读取一个数字,在第 14 和 15 行,从 DLL 文件中读取另外两个数字到变量 int32_2 和 int32_3 中。在第 19-22 行,这两个新变量用于指定加载到名为 numArray2 的数组中的 DLL 文件的一部分。从第 22 行开始,其余代码对 numArray2 进行操作。
仔细检查上述过程,我们怀疑可以通过这种方式操纵读入 int32_2 和 int32_3 的数字,因为验证签名的 DLL 文件部分可以与打印机上运行的实际可执行代码分开。
7. 构建恶意解决方案
破解HP对DLL文件的数字签名验证
为了验证上述怀疑,我们在 C# 中重新实现了一个几乎完全相同的算法副本,该副本在打印机上执行签名验证。然后该程序在 Visual Studio 调试器中运行,输入一个由 HP 签名的有效 DLL 文件。在上面“ValidatePeSignature”的代码示例中(下面新程序的第 65 行),执行在第 22 行中断,这是从 DLL 文件中读取 numArray2 的地方:
注意,此时我们可以在上面的调试窗口中看到int32_1、int32_2、int32_3和numArray2的值,并且numArray2的内容被dump到磁盘上的文件“Foo.txt”中:
我们的程序不需要知道这些到底是什么意思,所以就不分析了。
接下来,在 HxD 十六进制编辑器中复制粘贴,将文件“Foo.txt”附加到名为“HPwn.dll”的自定义未签名 .NET DLL 的末尾,红色字体的字节是新添加的:
然后必须小心处理 DLL 文件,以便 HP 签名验证算法将文件末尾定义的新字节加载到 numArray2 中。仔细分析上面的 ValidatePeSignature 代码,结合十六进制编辑器中相应的字节值,揭示以下内容:
在这些偏移处检查我们新添加的未签名 DLL 文件,我们看到它们当前设置为 0:
显而易见的问题是,我们应该如何设置int32_2和int32_3的值,才能将粘贴在DLL文件末尾的Foo.txt中的字节读取到numArray2中呢?
再次查看ValidatePeSignature的代码,20-22行是相关的:
如果(文件。位置!=(长)(int32_2 + 8))
文件。Seek((long) (int32_2 + 8), SeekOrigin.Begin);
file.Read(numArray2, 0, int32_3 - 8);
所以读入 numArray2 的字节将是 DLL 文件中 int32_2+8 和 int32_3-8 之间的字节。
我们想强制算法读取插入到 DLL 文件末尾的“Foo.txt”的内容,该文件从 0x1200 开始,长度为 11360 字节(如果您想验证数字,请参见上文粘贴 Foo.txt)。 txt 到 DLL 调试器中的屏幕截图显示了 numArray2) 的长度。考虑到这一点,计算出 int32_2 和 int32_3 值很简单:
如下所示:
现在,对这个新的 DLL 文件 HPwn.dll 运行签名验证算法,我们得到以下结果:
8.获得任意代码执行
在为 HP 的“解决方案”包构建了我们自己的方法,以及绕过其数字签名验证机制的另一种方法之后,唯一剩下的障碍是构建与 HP 平台兼容的恶意软件。
创建恶意软件
我们以HP ThinPrint客户端主类中的反编译代码为例制作恶意软件:
幸运的是,这段代码非常简单。只要有从打印机中提取的 HP.ExtLib.dll 副本,完成仿冒应该是比较简单的。下图是我们修改后的大部分结果,只是相同的方法和接口,只是执行不同的操作:
该项目的副本将发布在 GitHub() 上。“DoBadStuff”函数只执行以下操作:
1.从下载文件
2.在打印机上执行文件中指定的命令
3. 等待 5 秒
4.重复操作
必须克服的一个技术障碍是,项目需要用于编译的 .NET Compact Framework 版本仅包含在 Visual Studio 2008 Professional 中。具体来说,该项目需要针对“Windows CE 设备”:
最终我们获得了 Visual Studio 2008 Pro 的副本并成功构建了项目。
测试恶意软件
在新添加的 DLL 文件中执行签名验证过程后,使用我们 GitHub 中的 python code() 将该 DLL 加载到 BDL 中,修改后的 BDL 文件成功上传到打印机:
回想一下,我们的恶意软件从中下载文件,在这种情况下,文件“blar”包含一个简单的命令,可以让打印机“ping”我们的其他服务器。我们可以通过监控第二台服务器来确认命令执行成功: