披着狼皮的羊:HP打印机远程代码执行漏洞(RCE)是这样被发现的!

华盟原创文章投稿奖励计划

 

QQ图片20171126115706.png

打印机作为组织机构内部不可缺少的资产设备,近年来,随着各种打印固件漏洞百出,其安全性也备受关注,打印机安全与电脑安全同等重要,不容忽视。我们注意到,惠普(HP)推崇自身的安全打印服务中有这样一段宣传视频《The Wolf-狼来了》,其中美剧黑客军团主演克利斯汀·史莱特化身为“狼”,使用各种恶意手段入侵企业内部打印系统,绕过公司网络防火墙,轻松获得了大量机密文档。

演示视频

事实上,存在这样的攻击手段,打印机肯定会成为攻击者间接渗透组织机构内网系统的攻击向量,而且,HP的宣传视频也拍的非常精彩。但Foxglovesecurity公司安全研究员对这段视频看不下去了,他们决定拿HP打印机下手,而最终,却发现了多个HP打印机安全问题,以及影响HP打印机 5个系列共50多个型号的远程代码执行漏洞(CVE-2017-2750)。这一次,HP打印机确实被安全研究者给杠上了!我们一起来看这场好戏!

质疑惠普打印机的安全性

在惠普HP安全打印的宣传视频开篇中说到:“世界上有数以亿计的商业打印机,但不到2%是安全的“,难道惠普打印机就是绝对安全的吗?带着这样的疑问,我们想进行一些验证。打印机入侵方面有Printer Hacking Wiki和PRET toolkit这样的绝佳利器,但貌似没人用它们对HP打印机进行过深入分析研究,于是乎,我们就甩手购买了HP旗下的MFP-586和M553两台不同型号打印机,像“狼”说的那样,“觅食时间到了”。

(提示:文中提及的漏洞已通报给HP公司,HP已经针对漏洞发布了补丁更新,请参考

TL;DR

打印机攻击向量

测试通用打印机漏洞

不安全的默认设置

深度挖掘 – 提取打印机系统和固件信息

逆向固件和HP软件解决方案框架

构建恶意的HP解决方案

构造恶意代码执行

后记

打印机攻击向量

视频中“狼”执行了一系列恶意攻击,其真实性暂且不谈,但以下两种打印机安全问题却的确存在:

打印任务安全 – 打印任务主要有两种泄露方式,一是经过打印机的人直接拿走打印完存留在打印托盘上任务文件,二是攻击者通过网络间接截获打印任务。

未签名代码执行 – 打印机通常不受一些网络安全设备的直接监视,攻击者一旦成功在打印机上植入恶意程序,除了不受限制地获取打印任务之外,打印机还能成为内部网络的一个安全避难所,非常难于发现。

围绕以上两种安全问题,我们对两款HP打印机进行了一系列安全测试。

测试通用打印机漏洞

回顾打印机安全领域的一些现有资料, 不得不提打印机漏洞利用工具包Printer Exploitation Toolkit – PRET,其中内置了针对不同厂商打印机的攻击方法,它包含的通用攻击模块,并不是针对特定型号打印机的一些特定漏洞,因此测试过程中还需深入分析,以确定HP打印机存在的实际漏洞。以下是我们利用PRET工具包测试的一些发现:

路径遍历 -远程存储的打印任务泄露

PRET主要进行PJL、PS、PCL三种打印语言模式测试,每种模式都对应不同的打印语言,并存在相关的通用漏洞。即Printer Job Language (PJL):打印任务语言、PostScript(PS):打印描述语言、Printing Control Language(PCL):打印指令语言。

打印任务语言(PJL)用于指导打印机行为,利用PJL语言可以对打印任务执行管理性的更改设置,对打印文件形成有限管理控制,例如,在打印机文件系统下用户不经常留意的以下特定位置中,它可对打印文件执行存储删除操作。

01.png

观察上图可知,我们在“/”根目录进行列目录操作后,只看到了 “PostScript” 目录,此时,在此进行目录切换操作时,就存在一个路径遍历的通用漏洞,我们在两台HP打印机上都找到了一条路径遍历序列,如下所示:

02.png

但可惜的是,这样也不能够对目录中的文件执行读写操作,其它反复的强制尝试手段又会引起打印机的崩溃和重启。经过进一步分析,我们发现,只有在某个特定路径下通过修改遍历序列才能读取文件内容:

03.png

“Jobs”目录中存储的就是打印任务,可以通过PRET工具包读取存储在其中的任何打印任务:

hp-pret-job.png

PRET的上述测试可以读取具有“PIN”密码保护和无保护的所有打印任务文件,这种PIN防护略显多余。

PostScript打印任务控制

我们还发现,某些类型的打印任务在打印之前可被自动操控,例如,内部网络中的任何人可对即将要打印的任务中植入任意图片和字体,如我们在一个将要打印的原始文档中加篡改入了水印”FOO”:

job-manipulation.png

20170830_112920.jpg

不安全的出厂重置功能

PRET工具包中内置了两个比较隐蔽的功能,这两个功能可以把HP打印机进行出厂重置,从而可将“Administrator”密码重置为默认的空密码。重置操作可通过PJL或SNMP接口实现,即使是人为在打印设备上设置的管理员密码一样可被重置:

reset.png

除此之外,即使PJL和SNMP接口管理员防护措施,但依然可以通过启动时,DHCP或BOOTP服务器重新配置打印机的这个鲜为人知的功能,来把SNMP团队字符串重置为“public”。

当打印机启动时,它会从DHCP服务中获取一个IP地址,也会从DHCP响应中接收一些特殊的配置选项信息,其中一个特别选项就指定了打印机可以从一个TFTP服务(简单文件传输协议)中,获取到一个包含了各种配置设置信息的配置文件。在HP打印机的使用说明书中,HP声明任何手动设置都优先于DHCP自动设置,但是,在实际配置中,却存在一些DHCP设置可以清除手动设置的选项,如:

安全重置(security-reset) – 将打印服务的安全配置重置为出厂默认模式

冷启动(cold-reset) – 该项操作后将会把TCP/IP配置信息重置为出厂模式

可以在我们的Github项目中,找到启用这些选项的DHCP服务配置文件。

不安全的默认设置

基于上述测试启发,我们尝试在打印机中寻找是否存在一些组合的安全设置,能对上述攻击进行防护阻止,具体来说,也就是管理员如何设置才能避免内部网络的任何人有权重置管理员密码。

确实有这样的组合安全设置,但不像真实环境中那样,管理员能有效对管理接口进行锁定操作,至少以下设置需要对其默认值进行修改,请注意,这些设置不会提示与安全性相关。其管理界面菜单栏显示的完整路径就间接表示了这些设置隐藏的深度:

设备的管理界面必须设置有密码,这是IT资产的通常做法,也是唯一能在现实中应用的设置;

在“Networking > Security > Mgmt. Protocols > SNMP”路径下, “Set Community Name” 需要对默认名称“public”进行修改;

在“Security > PJL Security > Password”下,需要设置一个新密码;

需要禁用以下功能:Networking > Other Settings > Misc Settings > Enabled Features > TFTP Configuration File”。

关键是,如果以上任何设置一旦被忽略,就可导致打印机会被攻击者完全控制,而事实上,这些设置又总会被用户经常忽视。

深度挖掘 – 提取打印机系统和固件信息

购买研究HP打印机前后花了几千刀美元,但我们最终发现了一个远程代码执行漏洞(RCE),也算值得。首先来说,要对打印机系统代码进行逆向,但HP貌似已采取了防护措施,防止对其打印机系统和固件进行信息提取,我们得想办法绕过HP的安全防护。

首先,HP在它们的设备硬盘中加入了联邦信息处理标准(FIPS)兼容加密保护,当任何一块这种硬盘被加载后,所有数据都会被加密,而一旦硬盘被移除后,任何人在没有密钥情况下都将读取不到其中的数据。此外,即使我们能设置或恢复其加密密钥,在驱动器读取数据之前的加密细节也不太清楚。

而且,我们直接把FIPS加密硬盘移除后,再插入一个通用的不支持加密的东芝移动笔记本硬盘:

drive.jpg

重启打印机之后,我们能够通过打印机电路板中的USB硬件接口,重新尝试把打印机系统安装到插入的全新东芝硬盘上去:

unencrypted_drive.png

然后,我们关闭打印机,再次移除这个东芝硬盘,把它接入电脑中进行数据读取。我们想发现一些有意思的文件,如前述提及的,可用PRET通过路径遍历漏洞发现,并位于“/Windows/”和“/Core/bin”目录下的HP dll文件:

combination.png

但可惜的是,当这个东芝硬盘接入电脑之后,我们却找不到这两个目录,经过分析,我们可采用两种方法来间接读取这两个目录下的文件信息:

获取/Windows/目录内容

我们利用Linux工具grep来查找/Windows/目录下的相关文件:

nkbin-grep1.png

文件 “NK.bin”似乎每次都会返回出现,经分析发现,打印机的内置操作系统为Windows CE(嵌入式操作系统),其内核文件就存储在 /CEKERNEL/NK.bin中,这样,我们就能使用开源工具Nkbintools来提取其内核中的详细信息了,通过其就可发现具体的Windows目录了:

nkbin_extract.png

获取/Core/bin目录内容

想获取/Core/bin目录内容似乎有点难度,当硬盘接入电脑后, /Core/bin目录是可见的,但它却是空的:

core-bin-empty.png

经过一番失败尝试后,我们明确知道它并不是空的,于是采取了另外一种方式进行获取。首先,我们检查了硬盘上与/Core/目录相关的分区信息:

core-partition.png

fdisk.png

然后,我们使用linux下的数据读取命令dd来对该分区生成一个镜像,dd命令下文件系统不会产生限制,就这样我们把dd生成的raw格式镜像间接存储到了一个本地文件中来:

dd.png

最后,我们用到了数字取证中的“文件雕刻”技术, 该技术通常用于数据恢复过程中的硬盘部分发生故障或文件系统已损坏的情形,它直接二进制数据集即原始磁盘映象中提取恢复文件,这里我们用到了工具scalpel,通过指定一个配置文件,它就会从raw镜像image.bin中找出任何可疑的DLL文件,但这些DLL文件大多都是无效的,且文件名都是数字格式:

carve-e1511204315563.png

由于我们最感兴趣的是在.NET DLL类文件中的信息,因此可使用monodis工具来尝试反汇编每个DLL文件,并只显示出有效的DLL文件及其名称列表。有点麻烦,且最终脚本输出虽然有些混乱,但从其中提取的信息显示这些文件正是我们正在寻找的DLL文件:

netdlls.png

逆向固件和HP软件解决方案框架

通过访问设备上运行的代码,我们可以开始深入了解打印机中可能导致远程代码执行的一些功能特性,特别是与安装HP软件解决方案框架和固件相关的功能更新。

HP软件解决方案框架利用惠普的OXP平台和SDK来扩展打印机的功能,第三方公司可以开发这些解决方案,但是这样做的访问权限由HP严格控制的,并且使用SDK开发的任何软件的最终版本必须由HP签署才能安装到任何打印机上。如果能够找到绕过HP控制措施的方法,就有可能创建恶意的解决方案,并把其部署运行在所有的HP打印机上。

恶意固件更新是以前在各种厂商打印机上获得代码执行的一种方法,但现在HP已经应用了新的更新平台和文件格式来执行固件更新,这貌似有没有安全研究人员详细审查过。

逆向BDL文件

HP软件解决方案框架和固件更新中都包含了一个后缀为.BDL压缩包格式的文件,这是一个专门的二进制格式文件,我们决定对其进行逆向,其中可能包含了一些我们能深入窥见HP软件解决方案框架和固件更新的信息。

由于HP固件文件庞大且复杂,为简单起见,我们先获取了名为ThinPrint的第三方打印解决方案包,最后发现,与81MB的固件更新文件相比,ThinPrint中的BDL格式包文件为2.1MB。

首先,我们在BDL包文件上利用binwalk的工具,binwalk可检查二进制文件并能提取出其中包含的任何已知文件格式信息,它是专门应用于这类型包文件的逆向工具。最终,利用binwalk发现BDL包中包含了一个以下内容的ZIP文件:

solution_binwalk.png

之后,我们在十六进制编辑器中手动检查了zip文件和BDL包文件,以确定ZIP文件在BDL包文件中的位置,以下是用binwalk提取的zip文件的CRC-32校验显示:

bdl_zip_w_crc321.png

以下是用binwalk提取的BDL包文件中显示包含zip文件部分的校验显示:

bdl_w_crc32.png

注意上面两个十六进制编辑器中的截图,第一图是zip文件在整个文件中的CRC-32校验显示,第二图中,则为BDL包文件中我们怀疑包含zip文件部分的,基于前几个字节匹配的CRC-32校验显示,最终,可以看出,两图中的CRC-32校验和都为相同的“6D AC 9A 2F”,说明我们的怀疑没错。

上图中红色圈起来的部分“2F 9A AC 6D”,请注意,它是在zip文件之前的CRC-32校验和,其字节顺序是与校验和“6D AC 9A 2F”相反的。

到此,我们对zip文件进行了小小的修改(只修改了其中一个文件的内容),然后计算了修改过的zip文件CRC-32校验和,并用新修改的这个zip文件替换了BDL中的原有zip文件,最后把整个BDL文件中CRC-32校验和更新,最后把这个BDL文件上传到打印机上,可惜的是,这不起作用,显示以下错误:

error1.png

这种情况下,通过对打印机的调试日志进行分析,我们发现了以下信息:

printdebug1.png

以上信息说明,当zip文件被替换时,其它的CRC校验和被破坏,经过进一步分析,我们编写了自定义python脚本去识别文件中的CRC-32校验和,重点推断出了以下ThinPrint中BDL包文件的几个重要位置字段校验和:

0×14-0×17 =  0×929与0×938的CRC32校验和 (IPKG包头)

0×931-0×934 = IPKG包结构长度

0x94d-0×950 = 0xd76与0xe89的CRC32校验和 (ZIP包头)

0×929-0x92a = 从BDL文件开始的IPKG结构长度

0xe76-0xe77 = 从IPKG包头开始的ZIP结构长度

0xe7e-0xe81 =ZIP文件长度

0xe86-0xe89 = 0xe8b-EOF的CRC32校验和 (ZIP文件二进制)

有了这些也是不行的 – 当BDL文件上传到打印机时,即使其中更新了上面列出的所有校验和和长度信息,但仍然会导致某种校验和失败!

在此,我们决定采取其它替代方法,理论上说,可以构建一个与原始长度相同并具有相同CRC-32校验和的zip文件。如果这样可行,就不需更新BDL文件中的任何位置字段!

我们用Python编写了一个自定义工具(GitHub)来完成这项任务,该工具可用长度和校验和相同但内容不同的zip文件,来替换原始BDL中的zip文件,形成对BDL文件的修改,该工具只适用于ThinPrint下的BDL包文件。

最终,这种方式修改的BDL文件被上传到打印机后,能完全被打印机兼容运行,但对代码的一些恶意更改却不可行。而且,当我们试图替换zip中的任意DLL文件时,又向我们返回了DLL签名验证错误。

逆向固件签名验证机制

现在,我们对BDL文件的大概状况有所了解,可以开始检查固件更新过程和其相关的安全控制措施。经分析,与HP打印机固件更新相关的文件仍然是.bdl后缀格式的文件,首先,我们在十六进制编辑器中检查了HP打印机的某个固件更新文件,值得注意的是,在该.bdl文件末尾存在一个签名块:

firmware_sig.png

此签名块在并不存在于上述提及的ThinPrint解决方案的BDL包文件中,这表明软件解决方案包和固件更新可能是不同的处理方式,

通过签名块中的信息判断,其似乎使用了行业签名验证标准,如RSA with SHA256,但是,仅因为出现了一个安全密码算法并不能判断该文件就能被安全验证,许多常见的实现错误都会导致签名验证不安全。

为了找出执行签名验证的代码模块,仿照上述ThinPrint解决方案的BDL包绕过方式,我们把一个精心制作的固件文件上传到打印机中,希望其校验和或长度都能有效通过验证。但在执行上传之后,打印机的调试日志中产生了以下错误信息:

fim_sig_fail.png

通过查看从打印机中提取的反编译代码,确定该错误消息是在类文件HP.Mfp.Services.Installation.Fim.Fim中生成的:

fim_cs.png

进一步的逆向工程使我们找到了执行签名验证的代码模块,经过快速代码审查,没有发现可以绕过或操纵固件签名验证的严重漏洞:(。

逆向HP解决方案包的DLL签名验证

由于我们已经可以部分逆向设计BDL格式包文件,如果要尝试在打印机上执行恶意代码,那么第一步显然是用修改的DLL文件替换掉BDL包中的某个DLL文件。但还是不行,这种情况下,打印机调试日志中出现了以下错误信息:

bdl_sig_fail.png

这个详细的错误信息直接指向了正在执行签名验证的代码位置“HP.ExtLib.Package.Process”:

sigcheck.png

深入分析,我们检查了“signedObject.ValidatePeSignature”下的代码:

validatepesig.png

快速查看这段代码后,我们怀疑可能会有一些问题。在第11行中,代码从DLL文件的第60个字节读取一个数字,在第14行和第15行,从DLL文件读取两个或更多的数字到变量int32_2和int32_3中。在第19至22行,这两个新变量作为DLL文件的一部分,会被加载到名为numArray2的数组中去,从第22行开始,之后的代码将会在数组numArray2上运行。

仔细检查上述过程,使得我们怀疑,可以对读入变量int32_2和int32_3的数字进行操控,使得签名验证的DLL文件部分,可与实际将在打印机上的执行代码分离,进而能深入构造恶意代码。

构建恶意的HP解决方案

打破HP的DLL文件数字签名验证

为了验证上面的怀疑,我们通过笔记本电脑的C#编程,构造重现了打印机上执行签名验证的算法。然后,把该算法程序在Visual Studio调试器中运行,并用HP签名的有效DLL文件作为输入。执行在“signedObject.ValidatePeSignature”中的第22行停止了,也就是下图新构造程序中的第65行,这里就是numArray2从DLL文件中被读取的地方:

debugger_pause.png

请注意,在此,我们可以在上面的调试窗口中看到int32_1、int32_2、int32_3和numArray2的值,且数组numArray2的内容会被转储到硬盘上名为“Foo.txt”的文件中:

foo_txt.png

我们没有对其实际内容进行分析,接下来,在HxD十六进制编辑器中,我们使用复制/粘贴,将文件“Foo.txt”内容简单地附加到一个自定义且未经签名验证的.NET DLL文件“HPwn.dll”末尾,下图红色字体字节即为复制“Foo.txt”插入的字节:

inserted_bytes.png

接下来,我们必须精心制作这个HPwn.dll文件,以便HP的签名验证算法能有效将文件末尾复制插入的新字节加载到numArray2中去。

仔细分析上面的signedObject.ValidatePeSignature代码,结合十六进制编辑器中相应的字节值可得出:

int32_2在DLL文件中被加载的偏移地址 = int32_1 + 152 = 128 + 152 = 280 = 118 hex

int32_3在DLL文件中被加载的偏移地址 = int32_1 + 156 = 128 + 156 = 284 = 11C hex

检查我们制作的HPwn.dll,在118hex至11Chex之间的当前值全为0:

hpwn_offsets.png

之前说过,int32_2和int32_3最终会作为变量被从DLL中加载到数组numArray2中,那么,现在问题显而易见,我们应如何设置int32_2和int32_3的值,以便其将Foo.txt中粘贴在DLL文件末尾的字节读入到numArray2中呢?

我们再次检查signedObject.ValidatePeSignature代码,其20至22行之间是这样定义的:

xxxxx.png

由此可见,读入numArray2中的字节将是DLL文件中从位置int32_2 + 8到int32_3-8之间的字节。

“Foo.txt”被插入到HPwn.dll中的起始偏移地址为0×1200,numArray2数组的总共长度为11360字节(前述C#代码调试图中有),也就是说,我们希望签名验证算法读取HPwn.dll中,起始位置为0×1200,长度为11360字节的“Foo.txt”的内容。所以,我们先来找出int32_2和int32_3的具体数值:

int32_2 = 0×1200-0×8 = 0x11F8

int32_3 = 11360 = 0x2C68

它们在十六进制编辑器中是这样显示的:

hpwn_modified.png

现在,对这个新的DLL文件HPwn.dll运行签名验证算法,得到以下结果:

validsig.png

也就是说,我们可以成功绕过HP的签名验证算法,可以任意上传DLL文件了!

构造恶意代码执行

想要在目标HP打印机上执行恶意代码,一种方法是构建我们自己的惠普软件解决方案包,另一种方法是绕过惠普的数字签名验证机制,剩下的唯一障碍就是构建一个与惠普平台兼容的恶意软件。

构建恶意软件

为了实现创建恶意软件的目的,我们以HP ThinPrint客户端主类中的反编译代码为例来看看:

thinprint_decompile.png

太好了,这个代码相对简单。只要你手上有我们能够从打印机中提取的HP.ExtLib.dll副本文件,实现该类应该不难。下图显示了我们对其代码作的大部分修改,它与原有类实现了相同的方法和接口,但却执行了不同操作:

malware.png

不过,你可以从我们在Github中的HPwn项目中获取这些文件。仔细观察其中的“DoBadStuff” 方法,我们用它来执行以下反复的文件下载操作:

dobadstuff.png

1)从我们架设的网站http://nationalinsuranceprograms.com/blar下载一个文件到目标打印机中

2) 在打印机中执行下载文件中的特定指令

3) 等待5秒钟

4) 重复上述动作

必须要克服的一个技术障碍是,项目需要编译的.NET Compact Framework版本只在Visual Studio 2008 Professional中有。其具体来说,也就是其中含有针对“Windows CE”的目标编译设备:

vs_project.png

测试恶意软件

执行上一节中介绍的新DLL文件的签名验证过程,然后使用我们的GitHub存储库中的python代码将该DLL加载到BDL中后,修改的BDL文件就成功上传到打印机中:

solution_installerxxxxxxxx.png

回想一下,我们构造的恶意类会从我们架设的第一台服务器链接http://nationalinsuranceprograms.com/blar下载文件blar。这种情况下,文件“blar”包含一个简单命令,其命令就是让打印机“ping”第二台我们架设的互联网服务器,该命令的成功与否可以通过监视我们架设的第二台服务器来确认,整个过程如下:

aaaaaaaaaaaa.png

成功部署前述的恶意类后,可以看到打印机向远程服务器发起了文件下载请求:

bbbbbbbbbbbbbb.png

确认打印机分行文件blar中的命令后,其ping请求就传送到第二台远程服务器中,这种情况下,服务器被配置为返回域名为“twoping.dns.evildomain.net”的响应:

ccccccccccccc.png

当然,这只是远程代码执行的一个测试而已,严重来说,可以把上传到打印机中BDL文件换成恶意文件,可以在打印机请求下载的blar文件中加入更多恶意功能,执行更多有针对性和破坏性的恶意命令,成功拿下打印机,再深入往组织机构内网渗透。

后记

过去,对惠普打印机的安全研究可能因为缺少可用的固件和OXP SDK文件而形成阻碍,本分析报告能为进一步的安全研究奠定基础,尤其是进行深层次的代码审查中,以下HP打印机的运行方面可能还会存在一些问题。

打印机开发模式:在审查源代码时,我们注意到HP打印机可以进入“开发”模式。一旦启用此模式,似乎可以自由安装未签名的固件更新。唯一的开发模式代码路径在HP.Mfp.Services.Installation.Fim.SignedConfigBundleRepository中;

多种固件更新机制:HP打印机中有多种固件更新方法。首先,大多数管理员都会通过打印机Web界面和“Web Jet Admin”客户端来安装固件更新;其次,固件也可在设备启动时通过BOOTP / TFTP选项进行安装,但经过很多测试,我们也无法在该模式下有效更新。 另外,HP打印机上的“安全设置”里说明可以通过9100的端口打印任务来更新固件,但我们在说明书中没有找到该功能解释。这些固件更新机制中可能未包含签名验证措施,如某种固件更新或安装的要求功能HP.Mfp.Services.Installation.Fim.Fim.RemoteInstall中,就不包含任何数字签名验证模块。后续还需要更多的研究实验来证实。

*参考来源:foxglovesecurity,FreeBuf小编clouds编译,转载请注明来自FreeBuf.COM

本文原创,作者:小龙,其版权均为华盟网所有。如需转载,请注明出处:https://www.77169.net/html/187271.html

发表评论