Illumant最近在Check Point ZoneAlarm反病毒软件中发现了一个严重漏洞,攻击者可以利用该漏洞,在反病毒软件启用的情况下,将低权限用户提升至SYSTEM
权限。该漏洞之所以存在,是因为ZoneAlarm在进程间通信上采用了并不安全的具体实现,使得低权限用户可以使用存在漏洞的.NET服务,劫持不安全的通信,从而注入并执行代码。受影响的.NET服务以SYSTEM
权限运行,因此被注入的代码会以SYSTEM
权限运行,绕过权限限制,使攻击者可以获取系统的完全访问权限。
本文从技术角度介绍了该漏洞的发现过程,也介绍了如何在本地环境中利用漏洞以SYSTEM
权限执行未经授权的代码。
漏洞利用过程可参考此处视频。
大家可以访问我们的GitHub页面获取漏洞利用代码。
Fabius Watson(@FabiusArtrel)最近在Ekoparty 2018上发表过一次开创性演讲,主要介绍了如何滥用WCF端点。同样在2018年,Watson也提交并公布了一些CVE。这些权限提升和远程代码执行漏洞都与基于.NET WCF服务的商业产品有关,部分漏洞列表如下:
Watson对基于.NET的WCF漏洞的研究也给我们提供了研究思路。
此外,我们在漏洞开发过程中也使用了关于代码签名漏洞方面的技术(特别是关于代码签名证书克隆及防御方面的技术),这些技术由来自SpecterOps的Matt Graeber (@mattifestation)公布。
Fabius Watson提供的一个python脚本可以帮助我们识别可能存在漏洞的目标服务。该工具可以枚举满足如下条件的所有服务:
SYSTEM
(NT AUTHORITY\SYSTEM
)权限运行该脚本中使用了WMIC查询语句来识别以SYSTEM
运行的所有服务,然后使用pefile
模块来检查服务程序的导入表中是否存在mscoree.dll
(所有.NET应用都会用到这个库)。该工具的运行结果如下所示:
枚举完成后,接下来就是使用.NET反编译工具来检查这些服务。这里我们使用的是dnSpy。虽然系统上运行着许多.NET服务,但不一定都用到了WCF。所有的WCF服务都依赖于System.ServiceModel
,因此我们可以在dnSpy中检测是否存在相关引用。我们发现ZoneAlarm服务中只有一个引用了这个库:SBACipollaSrvHost.exe
。
找到了以SYSTEM
权限运行的WCF服务后,我们需要检查该服务是否对外暴露了我们可以利用的方法。有时候某些方法会以待运行的命令作为输入,这些方法利用起来非常方便。在其他情况下,利用方式可能没那么直接。当然,目标服务也可能不会公开任何方法,无法用于代码执行。
在源代码审核过程中,我研究了OnCommandReceived
方法。跟踪该方法触发的一系列调用后,我发现整条调用链中存在一个名为ExecuteInstaller
的方法,可以用来执行安装程序:
根据这个方法的名称以及实际用途,我们判断该方法很可能是我们寻找的目标,因此继续下一步研究。
阅读SBACipolla
类代码后,我们可以看到代码创建了两个命名管道服务端点:Cipolla
以及CipollaRoot
。WCF服务可以使用各种传输协议,如果使用的是HTTP或者TCP协议,则我们有可能远程利用该服务。在本文中,该服务使用的是命名管道,因此我们的目标是实现本地权限提升:
还有名为AddSecureWcfBehavior
的一个自定义方法会调用这些服务端点,这表明开发者可能会尝试锁定这些服务。实际上,当某个客户端尝试连接到命名管道服务器时,代码首先会检查该连接是否来自于Check Point签名的进程,如下图所示:
首先服务器会确定客户端的PID,然后使用该信息获取程序的完整路径,最后,服务端会检查:A)应用是否使用有效证书进行签名,以及B)证书的CN字段是否以“Check Point Software Technologies.”开头。如果不满足这些条件,服务端就会断开该连接。
我们最初的目标就是将DLL注入到经过Check Point签名的合法进程来满足这些检查条件,以便与目标服务通信。这种方法只有当特定的反病毒功能被禁用后才行之有效。在默认状态下,我们很难将DLL注入大部分进程中,因此这不是一个首选方案。
来自SpecterOps的Matt Graeber发表过一篇文章,其中介绍了一个PowerShell cmdlet,能帮助低权限用户使用自签名证书来签名代码,也能让操作系统信任该证书。这样一来,我们就有可能签名利用代码,使其能与WCF服务通信,无需注入其他进程。我们可以通过如下步骤,使用伪造的证书来签名利用代码,绕过检查机制:
$cert = New-SelfSignedCertificate -certstorelocation cert:\CurrentUser\my -dnsname checkpoint.com -Subject “CN=Check Point Software Technologies Ltd.” -Type CodeSigningCert
Export-Certificate -Type CERT -FilePath c:\tmp\MSKernel32Root_Cloned.cer -Cert $cert
Import-Certificate -FilePath c:\tmp\MSKernel32Root_Cloned.cer -CertStoreLocation Cert:\CurrentUser\Root\
Set-AuthenticodeSignature -Certificate $cert -FilePath c:\tmp\exploit.exe
SBAStub.dll
(具体路径为C:\Program Files (x86)\CheckPoint\Endpoint Security\TPCommon\Cipolla
)中定义了一个SBAStub
对象,该对象负责处理连接到WCF服务所需的所有管道,还包含名为SendCommand
的一个方法,我们很自然就能猜测到该方法与目标服务中的OnCommandReceived
方法有关。OnCommandReceived
方法接受名为CommandXML
的一个字符串作为参数,该字符串会原封不动传递给ExecuteInstaller
。接下来我们看一下ExecuteInstaller
中的代码,分析该方法对参数的处理过程:
代码204-211行会反序列化处理CommandXML
,将其转换成一个RunInstallerPackageCommand
对象,这是服务程序中自定义的一个类,该类包含3个字段:string类型的InstallerPackagePath
、string类型的InstallerPackageArguments
以及另一个自定义类(SBAMessageInfo
)MessageInfo
。该类中最有趣的字段为InstallerPackagePath
,因为该字段可以用来在目标服务的上下文中启动进程。
在224行,我们可以看到代码会验证InstallerPackagePath
所指向的程序是否由Check Point签名。
代码213-232行会将参数载入一个Process
对象中,然后在235行启动该对象。
因此我们有可能以SYSTEM
权限启动由Check Point签名的任何应用。
利用代码如下所示:
首先我们初始化SBAMessageInfo
及RunInstallerPackageCommand
对象,最重要的是要在InstallerPackagePath
字段中设置需要目标服务运行的程序。接下来,我们使用XmlSerializer
来序列化RunInstallerPackageCommand
。最后,我们创建一个SBAStub
,使用SendCommand
方法将新序列化的对象发送给目标服务。只要InstallerPackagePath
所指定的文件经过签名,并且包含的CN为Check Point Software Technologies,
,目标服务就会帮我们启动该程序。
为了演示利用过程,我们创建了一个简单的示例程序,可以在系统中添加一个新的本地管理员账户,我们使用内置的Windows PowerShell cmdlets对该程序进行签名。随后,目标服务会按照我们的要求运行该程序,实现权限提升。
在开发出利用代码后,我们第一时间将漏洞反馈至Check Point。与其他厂商相比,他们的披露机制要方便得多。Check Point在官网上专门为反馈安全问题开放了一个表单,在提交漏洞后厂商很快就与我们取得联系,并且也在问题处理更新过程中与我们协同合作。
厂商修复问题代码后,邀请我们验证修复补丁是否有效。他们的修复方法非常简单,直接让攻击者无法通过WCF来利用ExecuteInstaller
方法,然后也提高了未授权客户端与目标服务交互的难度,这样处理比简单地避免WCF对外暴露敏感功能来说要更为安全。