当我最初面试 CF 的 Windows 研究员职位候选人时,我给出的挑战之一与CVE-2024-21338有关。这是一个 Windows 内核特权提升漏洞,具体来说是驱动程序中的不受信任的指针取消引用appid.sys漏洞。该驱动程序负责 AppLocker 技术。
当时,该漏洞因 Avast 在Lazarus FudModule Rootkit上的出色工作而闻名。
总结
根据 Avast 的详细帖子,该漏洞的主要漏洞点可以总结如下:
-
该错误存在于AppHashComputeImageHashInternal()函数中,可以通过0x22A018向名为的设备对象发送带有值的 IOCTL 来调用该函数\DeviceAppid。
-
驱动程序需要两个从 IOCTL 的输入缓冲区引用的指针。
-
由于我们可以通过回调完全控制指令指针和第一个参数中的数据,因此这个错误会产生强大的原语。
-
根据设备对象名称上的 ACL,只有LOCAL SERVICE和AppIDSvc用户才有足够的权限发送目标IoControlCode。
-
目标驱动程序appid.sys不会自动加载,需要向特定的 AppLocker 相关 ETW 提供程序发送事件。
挑战
SMEP 和 kCFG
-
虽然我们可以完全控制指令指针,但由于存在管理模式执行保护 (SMEP) 缓解措施,我们不能仅提供用户模式指针来直接执行我们的 shellcode。
-
回调函数是间接调用,所以我们必须在内核空间中找到一个有效的指针来绕过内核控制流保护(kCFG)的保障。
安全远程监视系统
因为这个漏洞利用是在用户上下文中运行的LocalService,所以 KASLR 在这里不是一个大问题。借助 evergreenNtQuerySystemInformation()系统调用,我们可以轻松泄露构建漏洞利用所需的几乎所有内核地址。
加载目标驱动程序
由于默认情况下不加载该驱动程序,因此我们可以通过使用服务管理器或向 AppLocker 相关的 ETW 提供程序发送事件来启动 AppID 服务来手动加载它。
出于测试目的,此驱动程序已加载到内核空间中。
Exploitation
根本原因分析
0x22A018当收到具有值的 IOCTL 时,AipSmartHashImageFile()将调用该函数来处理此控制代码。在 Windows 11 中,第一个参数应为以下结构的指针:
typedef struct _HASH_IMAGE_FILE {
PVOID ImageContext; // pointer to the context of hashing file image
FILE_OBJECT *FileObject; // kernel object pointer of file
PVOID CallbackTable; // pointer to callback functions
ULONGLONG Action; // not so sure
} HASH_IMAGE_FILE, *PHASH_IMAGE_FILE;
然后AppHashComputeFileHashesInternal()调用该函数来计算目标文件的哈希值。传递给此函数的前两个参数是用户可控制的:
稍后,经过一些初始化之后,函数AppHashComputeFileHashesInternal()调用AppHashComputeImageHashInternal()以获取哈希值,并将前两个参数直接传递给目标函数。
函数内部AppHashComputeImageHashInternal(),在计算目标镜像的哈希值之前,会从第二个参数指针开始调用2个回调函数,而这些指针是完全由用户控制的,从而形成完整的RIP接管条件。
总体而言,对易受攻击的函数的图形调用如下所示:
SMEP 和 kCFG 绕过
由于 SMEP 和 kCFG 的存在,如果我们直接从用户模式调用随机 ROP 小工具或 shellcode,内核将通过错误检查来解决问题。相反,我们必须找到一些有用的函数来帮助我们执行仅数据攻击。
在阅读了一些文章(1,2)后,我发现该函数nt!SeSetAccessStateGenericMapping()被广泛用于绕过 kCFG。但是,它要求第一个参数指向一个大小至少为 的结构体0x50:
同时,目标 IOCTL 要求输入指针的大小0x20(结构大小_HASH_IMAGE_FILE):
所以我决定自己找一个小工具。
花了一些时间寻找执行有趣操作的小函数,基于给定的约束,我找到了一个可行的候选函数:。此小工具允许使用输入结构偏移量(在本例中为字段)处的值覆盖第一个指针(此结构是指针)偏移量的nt!DbgkpTriageDumpRestoreState8 个字节:0x2078ImageContext0x10CallbackTable
构建漏洞利用
有两种可能的方法可以利用上述小工具来利用此漏洞:
-
设置PreviousMode目标的字段KTHREAD,然后滥用NtReadProcessMemory/NtWriteProcessMemory系统调用来存档内核空间的任意读/写。在 Avast 的报告中,Lazarus 使用了这种技术。
-
覆盖_SEP_TOKEN_PRIVILEGES当前进程令牌的结构以启用SeDebugPrivilege并滥用此权限在特权进程中注入 shellcode。这种方式需要触发漏洞两次才能覆盖和Present字段Enabled。
虽然写入值也是指向CallbackTable结构字段的指针_HASH_IMAGE_FILE,但它必须是有效的指针值。但是,通过利用 API VirtualAlloc,仍然可以生成合适的写入值,因为上面介绍的两种方法都不需要(太)具体的值。在我的漏洞利用中,我演示了两种获取 SYSTEM shell 的方法。
漏洞代码
你可以在GitHub上找到漏洞代码
https://github.com/Crowdfense/CVE-2024-21338/blob/main/CVE-2024-21338.cpp
演示
POC 1 – 滥用 PreviousMode
参考
-
https://decoded.avast.io/janvojtesek/lazarus-and-the-fudmodule-rootkit-beyond-byovd-with-an-admin-to-kernel-zero-day/
-
https://decoded.avast.io/luiginocamastra/from-byovd-to-a-0-day-unveiling-advanced-exploits-in-cyber-recruiting-scams/
-
https://github.com/sam-b/windows_kernel_address_leaks
-
https://research.nccgroup.com/2020/05/25/cve-2018-8611-exploiting-windows-ktm-part-5-5-vulnerability-detection-and-a-better-read-write-primitive/ #previousmode-abuse:~:text=into%20PreviousMode%20further.-,PreviousMode%20%E2%80%93%20a%20%22god%20mode%22%20primitive%3F,-PreviousMode%20on%2064
-
https://learn.microsoft.com/en-us/windows-hardware/drivers/kernel/previousmode
-
https://nero22k.github.io/posts/windows-applocker-driver-elevation-of-privilege-cve-2024-21338/
-
https://labs.bluefrostsecurity.de/blog/2020/01/07/cve-2019-1215-analysis-of-a-use-after-free-in-ws2ifsl/
-
https://ti.qianxin.com/blog/articles/CVE-2023-28252-Analysis-of-In-the-Wild-Exploit-Sample-of-CLFS-Privilege-Escalation-Vulnerability/
原文始发于微信公众号(Ots安全):Windows AppLocker 驱动程序 LPE 漏洞 – CVE-2024-21338
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论