摘要
在2024年2月13日的补丁星期二,微软根据Jan Vojtěšek与Avast的安全报告披露了CVE-2024-21338。这是一种新的Windows从管理员到内核”权限提升漏洞,允许恶意攻击者,特别是与朝鲜合作的Lazarus组织,通过他们的FudModule.dll** rootkit 获得内核访问权限。我们都知道BYOVD(“自带漏洞驱动程序”)的理念被全球的威胁行为者和恶意软件开发者广泛使用,他们利用自带签名的漏洞驱动程序来获取内核访问权限,但这一点超出了BYOVD的范围。这种技术适用于系统中已安装的Windows驱动程序:即appid.sys,这是一个由Windows AppLocker使用的驱动程序,微软网站上提到,“AppLocker帮助您控制用户可以运行的应用程序和文件”。
CVE-2024-21338漏洞通过IOCTL(“输入输出控制”)通信中的特定函数调用,具体来说是通过appid.sys驱动中的AipSmartHashImageFile函数调用,利用易受攻击的IOCTL控制代码0x22A018。通过使用特别构造的输入缓冲区调用该控制代码,我们能够破坏_KTHREAD线程上下文中的PreviousMode字段。该字段PreviousMode决定了直接系统调用(Nt, Zw)是否由内核或用户调用。考虑到这一点,我们现在可以调用直接的系统调用,并使其影响操作系统的内核,从而为恶意威胁行为者提供对受害者内核的访问权限。
分析
Lazarus 制作的FudModule.dll rootkit 的主要目标是通过篡改或隐藏其自身功能来规避EDR/杀毒软件的检测,正如Avast在文章“Lazarus和FudModule Rootkit:超越BYOVD的从管理员到内核零日漏洞”中所述。然而,在这篇文章中,我们不会重点讨论rootkit的工作原理,而是探索appid.sys漏洞的工作方式、如何利用它,以及微软在最新版本的Windows中通过MSRC补丁采取了哪些措施来修复它。
在2024年2月13日的补丁星期二,微软安全响应中心(MSRC)披露了一项全新的漏洞,名为“CVE-2024-21338”。该漏洞允许攻击者通过暴露的函数发送特定构造的小工具,通过IOCTL(输入输出控制)通信,读取和写入内核内存。
首先,像任何通过IOCTL在Windows上的通信一样,需要打开与目标驱动程序通信的句柄。在这种情况下,通过分析IDA Pro中的appid.sys(AppLocker)驱动程序,我们可以在DriverEntry函数中看到,需要打开句柄的对象是“\Device\AppID”,如下图所示。
然而,当我们尝试通过NtCreateFile从管理员打开“\Device\AppID”的句柄时,会遇到NTSTATUS代码0xC0000022(STATUS_ACCESS_DENIED),这意味着管理员用户没有正确的权限来打开AppID设备的句柄。这让我们质疑需要哪些权限才能成功打开它的句柄。通过调查易受攻击的“AipSmartHashImageFile”函数,我们发现通过xrefs引用的“AipSmartHashImageFile”函数可以找到“AipDeviceIoControlDispatch”函数,它与通过设备句柄处理所有IOCTL调用的函数相关。
打开此调用后,我们可以看到“AipSmartHashImageFile”函数是通过IOCTL代码“0x22A018”调用的,如下图所示。
好的,现在我们有了IOCTL代码,接下来可以做什么?除了通过“NtDeviceIoControl”发送控制请求到这个特定函数外,IOCTL代码还拥有其结构。通过根据微软的IOCTL文档解析调用“AipSmartHashImageFile”函数的IOCTL代码,我们可以看到该IOCTL代码需要0x0002(FILE_WRITE_ACCESS)权限才能被调用,这意味着——很可能——打开我们驱动程序的句柄需要相同的权限,但哪个用户可以在AppID设备上赋予我们这个权限呢?通过使用SysInternals Suite中的“WinObj”工具,我们可以列出当前安装中存在的所有系统对象,包括所有驱动程序的设备。通过检查“AppID”设备在“WinObj”应用程序中的权限,我们可以看到“Administrators”组在AppID的**ACL(访问控制列表)**中没有所需的“写入”权限,如下图所示。
我们还可以看到“LOCAL SERVICE”用户名确实拥有成功访问和通过IOCTL代码调用我们所需函数的“写入”权限。
考虑到这一点,我们现在进入漏洞利用阶段,我们将通过“令牌模拟”来利用“Windows访问令牌”,并将精心构造的小工具发送到“AipSmartHashImageFile”函数。
利用阶段
利用阶段开始于获取“\Device\AppID”句柄,为此,我们需要在进程中获取“LOCAL SERVICE”的访问权限。为了获得这种权限,我们需要应用一些访问令牌模拟技术,以在我们的进程中获得“LOCAL SERVICE”权限。
什么是Windows访问令牌?根据微软文档,访问令牌是“一个描述进程或线程安全上下文的对象。令牌中的信息包括与进程或线程关联的用户帐户的身份和权限。当用户登录时,系统通过与存储在安全数据库中的信息进行比较来验证用户的密码。如果密码被验证,系统会生成一个访问令牌。每个代表用户执行的进程都有该访问令牌的副本。”
这些令牌可以以某种方式被操纵,我们可以通过检查进程是否具有特定的权限来从Windows的远程进程中窃取它们。在这种情况下,从提升的权限(管理员)到“NT AUTHORITYSYSTEM”(S-1-5-18),需要两个权限:“SeDebugPrivilege”和“SeAssignPrimaryTokenPrivilege”。
由于设计原因,“winlogon.exe”进程暴露了一个具有这两个权限的令牌,因为该进程以SYSTEM身份运行,旨在操作Windows的登录状态,并且用户可以轻松与之交互,因此允许用户从winlogon中复制“NT AUTHORITYSYSTEM”访问令牌。
在成功使用“DuplicateTokenEx”复制SYSTEM令牌之后,我们现在可以通过查找具有“SeDebugPrivilege”和“SeImpersonatePrivilege”权限的令牌来获得“NT AUTHORITYLOCAL SERVICE”(S-1-5-19)访问令牌。通常,大多数“svchost.exe”进程以“NT AUTHORITYLOCAL SERVICE”身份运行,因此找到一个这样的进程应该非常容易且快速。
现在我们拥有“NT AUTHORITYLOCAL SERVICE”访问权限,这意味着我们对“AppID”设备句柄(“\Device\AppID”)和0x22A018控制代码都拥有“写”访问权限,我们现在可以成功打开对所述设备句柄的句柄。通过正确打开的句柄并访问“AipSmartHashImageFile”函数,我们可以构造触发“PreviousMode”字节内存“损坏”的有效负载。
PreviousMode是每个_KTHREAD结构中的一个字段,指示是否要从KernelMode或UserMode调用系统调用。考虑到这一点,一些Nt或Zw(直接)系统调用通过检查当前线程的“PreviousMode”字段来检查“PreviousMode”的值,以下是从“ntoskrnl.exe”反汇编中提取的“NtWriteVirtualMemory”系统调用代码片段示例:
“PreviousMode”字段是一个简单的枚举,有两个成员:“UserMode”和“KernelMode”,即KernelMode为0,UserMode为1。知道这一点后,我们可以可能修改当前**_KTHREAD**结构中的此字段的值,接下来我们探讨对该字段的内存损坏是如何工作的。
允许“PreviousMode”漏洞得以实际利用的主要原因是“AppHashComputeImageHashInternal”,它被“AppHashComputeFileHashesInternal”函数调用,而该函数位于“AipSmartHashImageFile”函数中,如下图所示。
如我们在下图所见,通过这些函数链传递了两个参数,最后传递给“AppHashComputeImageHashInternal”,它执行一个由用户控制的函数指针,该指针基于由用户控制的缓冲区,而这个缓冲区是在我们对0x22A018控制代码的调用中控制的。
现在,我们能不能只编写一个用户模式的shellcode并发送给控制代码,告诉当前线程的“PreviousMode”值降低为0?不幸的是,我们不能。介绍一下kCFG(内核控制流保护)和SMEP(监督模式执行防护)。
-
SMEP(监督模式执行防护)不允许我们在更高的权限级别下执行用户模式的代码,这将阻止我们执行用户模式的shellcode来实现我们的目标。 -
kCFG(内核控制流保护)不允许我们调用任意或未经验证的函数指针,尤其是指向用户模式地址或不在已建立的CFG有效内核函数位图之外的位置的指针。此机制确保所有间接函数调用都经过控制流完整性策略的检查,防止将执行流转移到恶意或意外的代码段。
考虑到这两种保护机制,我们现在需要找到一个在CFG 位图中有效的内核函数,允许其作为间接函数调用的合法目标。这个函数应当提供我们可以利用的能力,在这种情况下是内存操作,同时遵守kCFG和SMEP的限制。
感谢之前对这个问题的研究,“Windows AppLocker驱动程序权限提升漏洞(CVE-2024-21338)”一文详细介绍了如何在CFG位图中找到有效的CFG函数。我们在PoC中选择的函数是“ExpProfileDelete”,它是一个有效的CFG函数,其功能几乎完美符合我们的需求。通过查看“ExpProfileDelete”函数的反汇编:
我们可以看到该函数接收一个参数,该参数将被传递给“ObfDereferenceObject”函数,然后会导致传递给“ExpProfileDelete”函数的地址递减,从而使“PreviousMode”地址的数据从1变为0,使“NtWriteVirtualMemory”和“NtReadVirtualMemory”系统调用将其调用解释为来自内核模式。允许恶意用户控制通过此漏洞攻击的系统的内核空间内存。
补丁
Microsoft安全响应中心(MSRC)在2月发布的补丁在“AipSmartHashImageFile”调用之前添加了“ExGetPreviousMode”检查,防止用户模式发起的调用触发所述回调函数。下图显示了新版Windows中相同控制代码的反汇编。
通过使用**BinDiff**工具,它显示了两个二进制文件之间的差异,我们还可以看到补丁中应用的更改,仅是“ExGetPreviousMode”检查。
概念验证
基于所有展示的概念,制作了一个概念验证(PoC)来展示该漏洞的严重性。下图展示了PoC执行时的调用栈,遵循了上文所展示的相同原则。
PoC 的链接可以在GitHub上找到:https://github.com/hakaioffsec/CVE-2024-21338。
结论
总之,CVE-2024-21338 漏洞在Windows系统中呈现出重大权限提升的威胁,尤其是被Lazarus组织利用来绕过传统的安全措施,如EDR和杀毒软件。该漏洞展示了一种超越BYOVD方法的复杂技术,操纵内核中的“PreviousMode”字段,结合广泛的令牌模拟技术,从管理员权限到内核执行都能实现未经授权的访问。微软在二月份的更新中加入了一个关键补丁,表明了网络安全专业人员和威胁行为者之间持续的“猫捉老鼠”的游戏。对 CVE-2024-21338 的研究帮助我们更加了解此类特定漏洞在实际环境中是如何发生的。
参考资料
-
https://decoded.avast.io/janvojtesek/lazarus-and-the-fudmodule-rootkit-beyond-byovd-with-an-admin-to-kernel-zero-day/ -
https://nero22k.github.io/posts/windows-applocker-driver-elevation-of-privilege-cve-2024-21338/ -
https://research.nccgroup.com/2020/05/25/cve-2018-8611-exploiting-windows-ktm-part-5-5-vulnerability-detection-and-a-better-read-write-primitive/ -
https://msrc.microsoft.com/update-guide/vulnerability/CVE-2024-21338 -
https://malpedia.caad.fkie.fraunhofer.de/details/win.fudmodule
原文始发于微信公众号(3072):CVE-2024-21338 Lazarus组织 admin2kernel LPE 漏洞分析与利用
- 左青龙
- 微信扫一扫
- 右白虎
- 微信扫一扫
评论