CVE-2020-0787 Windows本地提权漏洞深入分析与利用指南
漏洞概述
CVE-2020-0787是Windows后台智能传输服务(BITS)中存在的一个本地提权漏洞,允许低权限用户在系统上下文中执行任意文件移动操作,最终可能导致权限提升至SYSTEM级别。该漏洞由itm4n发现,影响多个Windows版本。
BITS服务简介
后台智能传输服务(BITS, Background Intelligent Transfer Service)是Windows提供的一项服务,用于:
- 从HTTP Web服务器和SMB文件共享下载文件
- 将文件上传到HTTP Web服务器和SMB文件共享
- 考虑传输成本和网络使用情况,最小化对用户前台工作的影响
- 处理网络中断,支持暂停和自动恢复传输
- 在系统重启后仍能保持传输状态
漏洞组件分析
BITS COM类工作机制
BITS服务公开了多个COM对象,重点关注两类:
-
"New" BIT Control Class (CLSID: 4991D34B-80A1-4291-83B6-3328366B9097)
CoCreateInstance(CLSID_4991D34B-80A1-4291-83B6-3328366B9097) -> IBackgroundCopyManager* |__ IBackgroundCopyManager::CreateJob() -> IBackgroundCopyJob* |__ IBackgroundCopyJob::AddFile(URL, LOCAL_FILE) |__ IBackgroundCopyJob::Resume() |__ IBackgroundCopyJob::Complete() -
Legacy Control Class (CLSID: 69AD4AEE-51BE-439B-A92C-86AE490E8B30)
CoCreateInstance(CLSID_69AD4AEE-51BE-439B-A92C-86AE490E8B30) -> IBackgroundCopyQMgr* |__ IBackgroundCopyQMgr::CreateGroup() -> IBackgroundCopyGroup* |__ IBackgroundCopyGroup::CreateJob() -> IBackgroundCopyJob1* |__ IBackgroundCopyJob1::AddFiles(FILESETINFO) |__ IBackgroundCopyJob1::Resume() |__ IBackgroundCopyJob1::Complete()
未公开方法分析
在IBackgroundCopyGroup接口中发现了两个未文档化的方法:
-
QueryNewJobInterface()
virtual HRESULT STDMETHODCALLTYPE QueryNewJobInterface( /* [in] */ __RPC__in REFIID iid, /* [iid_is][out] */ __RPC__deref_out_opt IUnknown **pUnk) = 0; -
SetNotificationPointer()
通过逆向分析qmgr.dll发现,当输入GUID匹配硬编码值37668d37-507e-4160-9316-26306d150b12(IID_IBackgroundCopyJob)时,会调用CJob::GetJobExternal()。
漏洞原理
关键差异点
-
CreateJob()方法流程:
(CLIENT) IBackgroundCopyGroup::CreateJob() | V (SERVER) COldGroupInterface::CreateJob() |__ COldGroupInterface::CreateJobInternal() |__ CLockedJobWritePointer::ValidateAccess() | |__ CJob::CheckClientAccess() // 客户端模拟 |__ CJob::GetOldJobExternal() // 返回IBackgroundCopyJob1*指针 -
QueryNewJobInterface()方法流程:
(CLIENT) IBackgroundCopyGroup::QueryNewJobInterface() | V (SERVER) COldGroupInterface::QueryNewJobInterface() |__ CJob::GetJobExternal() // 返回IBackgroundCopyJob*指针
核心问题:当调用QueryNewJobInterface()获取新接口指针时,服务端没有正确模拟客户端身份,导致返回的指针具有SYSTEM权限上下文。
文件移动机制
- 服务创建临时文件(BIT*.tmp)并写入内容
- 写入完成后,通过
MoveFileEx()重命名文件 - 在
QueryNewJobInterface()获取的指针上下文中,文件移动操作以SYSTEM权限执行
漏洞利用步骤
准备工作
-
创建目录结构:
%temp%\workspace |__ <DIR> bait |__ <DIR> mountpoint |__ FakeDll.dll -
准备恶意DLL(
FakeDll.dll)用于后续提权
详细利用流程
-
创建挂载点
- 建立从
%temp%\workspace\mountpoint到%temp%\workspace\bait的挂载点
- 建立从
-
创建新Job
- 使用Legacy Control Class接口创建新Job
- 参数:
- Target URL:
\\127.0.0.1\C$\Windows\System32\drivers\etc\hosts - Local file:
%temp%\workspace\mountpoint\test.txt
- Target URL:
- 实际路径解析为:
%temp%\workspace\bait\test.txt
-
设置Oplock
- 监控
bait文件夹,查找类似BITAA6.tmp的临时文件 - 在临时文件上设置Oplock
- 监控
-
恢复Job并等待Oplock触发
- 调用
Resume()使服务开始写入临时文件 - 写入操作触发Oplock
- 调用
-
切换挂载点
- 原始状态:
TMP file = %temp%\workspace\mountpoint\BIT1337.tmp -> %temp%\workspace\bait\BITAA6.tmp Local file = %temp%\workspace\mountpoint\test.txt -> %temp%\workspace\bait\test.txt - 切换操作:
%temp%\workspace\mountpoint -> \RPC Control Symlink #1: \RPC Control\BITAA6.tmp -> %temp%\workspace\FakeDll.dll Symlink #2: \RPC Control\test.txt -> C:\Windows\System32\FakeDll.dll - 切换后状态:
TMP file = %temp%\workspace\mountpoint\BITAA6.tmp -> %temp%\workspace\FakeDll.dll Local file = %temp%\workspace\mountpoint\test.txt -> C:\Windows\System32\FakeDll.dll
- 原始状态:
-
释放Oplock
- 允许服务继续写入操作
- 服务将
FakeDll.dll写入临时位置 MoveFileEx()操作因符号链接被重定向,将DLL移动到System32目录
-
提权
- 利用Update Session Orchestrator服务加载移动到system32的恶意DLL
- 通常替换
WindowsCoreDeviceInfo.dll等常用库实现权限提升
防御与缓解措施
- 及时安装微软提供的安全更新
- 限制低权限用户对BITS服务的访问
- 监控系统目录下的异常文件操作
- 启用CFG(Control Flow Guard)等缓解措施
- 限制符号链接和挂载点的创建权限