原文地址:https://blog.exodusintel.com/2018/09/10/truekey-the-not-so-uncommon-story-of-a-failed-patch/
在这篇博文中,我们将研究供应商提供的补丁CVE-2018-6661。该漏洞最初在2017年6月向Intel Security(McAfee)报告,并于2018年4月公开披露。此外,我们还联系了McAfee,了解在本文中讨论2018年8月的问题。
贡献者:Omar El-Domeiri和Gaurav Baruah
在Exodus,进行n天漏洞研究时,我们经常遇到失败的补丁或发现相邻的0-day漏洞。在2018年,我们的团队已经确定了24个公开披露的漏洞,据报道这些漏洞已经被修补,但事实上,由于补丁没有解决根本原因,这些漏洞仍然很脆弱。即使他们密切关注着软件更新和安全建议,失败的补丁仍会让用户处于危险之中。
供应商提供的补丁可能无法提高软件安全性的原因有很多。在某些情况下,一个补丁实际上可能会增加攻击面,从而引入新的漏洞。而在其他情况下,补丁可能不完整,留下了可以绕过补丁并触发易受攻击的代码的途径。通常,不完整的补丁是供应商在没有解决根本原因的情况下,专门为他们从披露中获得的PoC的结果。在CVE-2018-6661的案例中,我们发现了一个不完整的补丁,它为攻击者提供了多种绕过补丁的方式。
尽管有多个供应商提供的补丁,但Intel安全(McAfee)True Key软件的公开漏洞仍然是可以利用的。任何登录用户(包括Guest帐户)都可以向True Key服务发送一系列精心设计的请求,以通过DLL端加载攻击途径执行任意代码。因此,没有特权的用户可以在任何安装了True Key的Windows机器上升级特权到NT 授权\系统。
True Key 是一个密码管理器,支持多种登录方式,包括面部和指纹,电子邮件,主密码或使用可信设备。Windows,Mac OS X,Android和iOS设备可以免费使用,但需要订阅后才能存储超过15个密码。目前,True Key还与Adobe Flash捆绑在一起,并要求用户在安装过程中选择退出。
当在Windows上安装True Key时,它包括一个始终运行的服务,在loopback接口127.0.0.1上监听TCP30000端口,该接口使用系统特权运行。该服务通过提供RPC机制来协调True Key软件的各个组件的功能。对于此漏洞,我们特别感兴趣的是SecureExecuteRPC方法,该方法启动McAfee信任的可执行文件,其中信任通过数字签名进行验证。
通过检查供应商的补丁,我们可以看到补丁只解决了McAfee.TrueKey.Sync中的问题,并且仅适用于它的一个DLL依赖项,也就是McAfee.TrueKey.SDKLibAdapter导入。
当. net运行时将动态加载程序所需的DLL依赖关系。我们可以通过顶部的导入来确定直接依赖关系。由于Windows按照微软文档中讲述的指定顺序来搜索DLL, 因此可以在同一文件夹中提供已修改的DLL,以便将其导入。需要注意的是,系统导入包含在已知的DLL列表中,攻击者不能以这种方式使用系统导入。
该修补程序强制必须在C:\ Program Files \ TrueKey文件夹(更新版本中的C:\ Program Files \ McAfee \ TrueKey)中找到SDKLibAdapter库,这些文件夹无法由非特权用户写入。但是,该二进制文件也导入了NLog日志记录库,并且不为对应的DLL强制执行路径约束。因为它忽略了补丁是不完整的,因此可以利用nlog.dll来允许任意代码执行,就像McAfee.TrueKey.SDKLibAdapter.dll可以在补丁之前的版本中使用一样。此外,只要二进制文件依赖于已知DLL列表之外的DLL,任何其他McAfee签名的二进制文件都可用于利用此漏洞。有多种方法可以找到DLL依赖项。
在检查反编译的TrueKey服务二进制文件时,很明显它是基于Apache Thrift的服务。
Thrift是Facebook开发的一个软件库和一组代码生成工具,可以加速开发和实现高效,可扩展的
后端服务。它的主要目标是通过将每一种语言中最需要自定义的部分抽象到用每种语言实现的公共
库中,从而实现跨编程语言的高效和可靠通信。特别地,Thrift允许开发人员在一个语言无关的
文件中定义数据类型和服务接口,并生成构建RPC客户机和服务器所需的所有代码。
检查由thrift为SecureExecute命令自动生成的代码,我们可以将这种请求所需的数据类型收集到服务中。
从这段代码中,我们应该为RPC服务的子集创建自己的thrift文件,这对于开发是必要的。
SecureExecute函数有两个参数——一个32位整数clientId和一个指定要运行的可执行文件路径的字符串。在执行RPC请求之前,服务会验证client id是否与先前已发出的已知值匹配。
SecureExecute API请求的处理程序将创建一个SecureExecuteCommand对象,将其封装在CheckedCommand对象中并将其传递给runner.Sync()函数,该函数将调用CheckedCommand对象的Execute()函数。CheckedCommand验证请求中提供的client id是否与服务已发布的现有ClientId匹配。如果是,则它调用包装对象的Execute()函数,该对象在此实例中是SecureExecuteCommand对象。
SecureExecuteCommand.Execute()将检查所请求的可执行文件,以确保在生成运行可执行文件的子进程之前,该文件已经由McAfee进行了数字签名。
因此,为了让服务执行一个二进制文件,我们必须为它提供一个有效的client id,并且这个二进制文件必须由McAfee签名。client ids是通过RegisterClient方法发布的,该方法的唯一参数由一个可以包含任意数量的可选字段的YAPClient struct组成。在注册时,服务通过检查YAPClient结构中的端口字段来验证客户端是否是受信任的客户端。端口字段用于查找该端口上监听的相应PID,然后服务检查与该PID相关联的可执行文件是否已由McAfee数字签名。
为了利用此漏洞,我们需要向True Key服务发送SecureExecute请求,请求它在包含已修改的nlog.dll的文件夹中执行McAfee.TrueKey.Sync.exe。有很多应用程序可用,例如dnSpy,用于直接修改已编译的. net可执行文件或DLL。由于McAfee.TrueKey.Sync.exe调用GetCurrentClassLogger()函数,因此我们修改此函数来启动子进程,该进程在同一文件夹中执行包含payload的文件。
即使我们的修改不满足函数的类型签名,这个漏洞也会按照预期的方式运行。Process.Start()的返回值不是Logger对象,如果进一步使用这个方法返回的值,可能会引发错误,但如果执行了这段代码,我们就可以利用运行payload的子进程来获得升级后的特权。
最初,我们向True Key服务发送RegisterClient请求以获得有效的client id。因为我们知道服务本身监听30000端口,所以我们的RegisterClient请求为YAPClient 结构中的端口字段指定该值。实际上,服务将验证它相信自己是一个有效的客户端,并使用新的client id进行响应。
当有了一个有效的client id,我们就发送一个带有这个client id的SecureExecute请求,并在包含我们修改过的nlog.dll的文件夹中发送一个指向我们的McAfee.TrueKey.Sync.exe副本的executablePath(可执行路径)。. net运行时将加载我们修改的nlog.dll,当GetCurrentClassLogger()函数被调用时,将执行pop.exe 。
我们已经将该漏洞编写为metasploit模块,下面的视频地址是一个简单的演示
对于SecureExecute请求检查30000端口的环回流量,其中executablePath参数不以C:\ Program Files \ McAfee \ TrueKey前缀开头,可以检测到主动利用。
Microsoft提供了有关动态链接库安全主题的内容丰富的文章,并提供了有关开发人员如何保护其应用程序免受此类攻击的建议。在应用程序级别,SecureExecute方法应拒绝任何请求,其中executablePath不以已知的写保护文件夹(如C:\ Program Files \ McAfee \ TrueKey)的前缀开头。此外,RegisterClient方法应该将请求中指定的端口视为不受信任的用户输入,并以更安全的方式验证客户机。如果您的组织不依赖True Key,则卸载此软件将删除易受攻击的服务。
除了内部发现的0-day漏洞外,Exodus Intelligence还提供了一个由外部组织或供应商自己公开披露的威胁组成的feed。我们的n-day服务的订阅者可以访问一系列经过审查的、可靠的漏洞和相应的文档,从而确保他们的防御措施得到了妥善实施。这在供应商提供的补丁无法解决根本原因的情况下非常重要,因为补丁的存在可能会错误地向用户保证他们不再处于危险之中。
我们向McAfee披露了失败的补丁,他们发布了更新作为回应。然而,我们测试了最新版本(截至2018年9月7日的5.1.173.1),发现它仍然容易受到攻击,不需要做任何的更改。