CVE-2020-0787 BITS任意文件移动漏洞
漏洞组件:后台智能传输服务模块(BITS)
组件特点:
- 从HTTP Web服务器和SMB文件共享下载文件或将文件上传到HTTP Web服务器和SMB文件共享。
- BITS将考虑传输成本以及网络使用情况,以便用户的前台工作影响尽可能小
- 即使重新启动后,BITS也可以处理网络中断,暂停并自动恢复传输。
RPC服务模式#
发现过程#
BITS服务接口#
BITS服务存在多个不同版本的类,是“控件类”的不同迭代,且存在一个旧版“控件类”
可以看到存在一个1.0版本的COM类和一个旧版本的类,暂且用新类和旧类指代
新类中存在一个IBackgroundCopyManager接口,旧类存在一个IBackgroundCopyQMgr接口
可以看到BITS服务是以System权限执行的
新类分析#
新类调用流程
- 创建BIT控制类(CLSID:
4991D34B-80A1-4291-83B6-3328366B9097
)的实例,通过CoCreateInstance()
接口获得一个指向IBackgroundCopyManager
的指针 IBackgroundCopyManager
,调用IBackgroundCopyManager::CreateJob()
获取指向该IBackgroundCopyJob
接口的指针。IBackgroundCopyJob
调用IBackgroundCopyJob::AddFile(URL, LOCAL_FILE)
将文件添加到下载任务中,这需要两个参数:URL和本地文件路径。- 调用
IBackgroundCopyJob::Resume()
设置为SUSPENDED
状态,并在工作的状态为TRANSFERRED
时调用IBackgroundCopyJob::Complete()
。
1 | CoCreateInstance(CLSID_4991D34B-80A1-4291-83B6-3328366B9097) -> IBackgroundCopyManager* |
旧类分析#
旧类调用流程
- 创建传统BIT控制类(CLSID:
69AD4AEE-51BE-439B-A92C-86AE490E8B30
)的实例,调用CoCreateInstance()
获得一个指向IBackgroundCopyQMgr
的指针。 IBackgroundCopyQMgr
调用IBackgroundCopyQMgr::CreateGroup()
获取指向IBackgroundCopyGroup
的指针IBackgroundCopyGroup
调用IBackgroundCopyGroup::CreateJob()
获取指向IBackgroundCopyJob1
指针。IBackgroundCopyJob1
调用IBackgroundCopyJob1::AddFiles()
将文件添加到任务中。- 调用
IBackgroundCopyJob1::Resume()
设置为SUSPENDED
状态,,并在工作的状态TRANSFERRED
时调用IBackgroundCopyJob1::Complete()
。
1 | CoCreateInstance(CLSID_69AD4AEE-51BE-439B-A92C-86AE490E8B30) -> IBackgroundCopyQMgr* |
发现问题 QueryNewJobInterface#
IBackgroundCopyGroup接口的文档中,该接口有13种方法
但是OleView显示有15个接口
从头文件中qmgr.中找到proc16定义如下:
1 | virtual HRESULT STDMETHODCALLTYPE QueryNewJobInterface( |
先与GUID 37668d37-507e-4160-9316-26306d150b12
比较,成功后调用CJob::GetJobExternal
函数
而GUID 37668d37-507e-4160-9316-26306d150b12
是IBackgroundCopyJob
的GUID,也就是说旧版本的代码可以通过未在文档中列出的QueryNewJobInterface
接口,获取新版本中的IBackgroundCopyJob
方法指针,也就是说可能会出现跨版本的代码调用
猜测可以完成的流程#
- 创建指向旧类的实例,获取指向IBackgroundCopyQMgr接口的指针
- 创建一个新组调用IBackgroundCopyQMgr::CreateGroup(),获取一个指向IBackgroundCopyGroup接口的指针
- 创建一个job,调用IBackgroundCopyGroup::CreateJob(),获取一个指向IBackgroundCopyJob1接口的指针
- 通过IBackgroundCopyJob1::AddFiles()添加文件
- 调用IBackgroundCopyGroup::QueryNewJobInterface()方法并获得指向未知接口的指针,假定它是一个IBackgroundCopyJob接口
- 通过调用IBackgroundCopyJob接口的Resume() 和 Complete()来恢复和完成job而不是IBackgroundCopyJob1接口
1 | CoCreateInstance(CLSID_69AD4AEE-51BE-439B-A92C-86AE490E8B30) -> IBackgroundCopyQMgr* |
poc演示#
将\\127.0.0.1\C$\Windows\System32\drivers\etc\hosts
下载到本地C:\Temp\test.txt
调用AddFiles创建tmp文件,当前用户
调用Resume写入文件,当前用户
最后重命名文件
此时为System权限
漏洞分析#
客户端调用Resume过程
1 | (CLIENT) IBackgroundCopyJob::Resume() |
客户端调用Complete过程
1 | (CLIENT) IBackgroundCopyJob::Complete() |
由于都会读取客户端token权限并进行检查,因此不能提权
正常情况#
1 | (CLIENT) IBackgroundCopyGroup::CreateJob() |
返回的是代表客户端的token权限的接口
提权情况#
1 | (CLIENT) IBackgroundCopyGroup::QueryNewJobInterface() |
由于在这里未检查token,因此返回了代表服务端System权限的接口给客户端,后续客户端都是以System权限进行Resume和Complete等操作。
漏洞利用#
通过符号链接的方式写入dll进行提权。
- 本地创建job进行下载,在tmp文件上设置Oplock
- 恢复执行后该服务会写入TMP文件触发Oplock
- 此时切换挂载点到对象目录,创建符号链接,tmp文件指向fake.dll,本地文件指向system32文件夹中的dll
- 释放Oplock,由于是以System权限进行文件移动,因此会将fake.dll移动到system32文件夹下,实现提权
修补方式#
修改Windows BITS 处理符号链接的方式来修复此漏洞
参考资料#
- https://docs.microsoft.com/en-us/windows/win32/bits/background-intelligent-transfer-service-portal
- https://xz.aliyun.com/t/7935
- https://itm4n.github.io/cve-2020-0787-windows-bits-eop/
- https://github.com/itm4n/BitsArbitraryFileMove
- https://github.com/cbwang505/CVE-2020-0787-EXP-ALL-WINDOWS-VERSION
- https://packetstormsecurity.com/files/158056/Background-Intelligent-Transfer-Service-Privilege-Escalation.html