背景
在2021年1月的补丁星期二,MSRC修复了splwow64服务中的一个漏洞,被分配为CVE-2021-1648(亦称为CVE-2020-17008)。该漏洞合并了我提交的两个绕过CVE-2020-0986补丁的有趣案例,其中一个也被Google Project Zero发现。
该漏洞原计划在2020年10月修复,但MSRC似乎在服务中发现了其他更严重的安全问题,因此将补丁推迟了四个月。
绕过FindDriverForCookie和FindPrinterHandle
CVE-2020-0986被修复后,我对splwow64和gdi32full进行了快速的bindiff分析,发现补丁后增加了两个检查。
第一个是微软增加了两个打印机句柄(或称cookie?)检查函数,名为FindDriverForCookie和FindPrinterHandle,它们将检查存储在一个全局变量中的打印机驱动句柄。
另一个是MSRC增加了两个指针检查函数UMPDStringPointerFromOffset和UMPDPointerFromOffset,以检查指针是否有效。
首先,我不知道微软增加FindDriverForCookie和FindPrinterHandle的目的,也许并不是为了缓解措施?快速审查后,我发现有一个命令0x6A可以设置打印机句柄,我们可以控制该句柄在服务的全局变量中的值,从而绕过这两个检查函数。
通过调用命令0x6A,函数bAddPrinterHandle会将打印句柄添加到存储在全局变量|qword_1800EABA0|中的驱动堆上。
这样,我们就可以在调用命令0x6D时轻松绕过打印机句柄检查,并命中漏洞代码。
CVE-2021-1648:任意地址读取
让我们谈谈信息泄露。CVE-2021-1648包含一个任意地址读取的信息泄露漏洞。
命令0x6D的代码太长,我不会在博客中全部贴出。简而言之,它会检查memcpy的目标地址是否在“有效”范围内(即|v6+0x58|的范围),但源地址|v57|未被检查,因此我们可以读取任意地址。
调用栈:
|
|
CVE-2021-1648的另外两个案例
我向MSRC报告的另外两个案例是关于绕过偏移检查函数UMPDStringPointerFromOffset和UMPDPointerFromOffset的。我认为MSRC在这两个函数的范围检查上犯了一个错误。
Splwow64是一个特殊的服务,在x86-64 Windows操作系统中兼容x86,因此它总是分配32位的堆。但在CVE-2020-0986的补丁中,UMPDStringPointerFromOffset和UMPDPointerFromOffset只检查偏移量和|portview+offset|是否小于0x7fffffff。
然而,在splwow64服务中,许多堆甚至栈都分配在低地址。因此,通过占用splwow64服务中的某些重要堆或栈来进行攻击是可能的。我在报告中建议MSRC检查指针范围是否在portview段内,而不是0x7fffffff。
两个案例的崩溃转储:
|
|
故事结尾
看起来微软重新设计了splwow64打印机服务,因此他们将补丁推迟了四个月。这对我来说,等待一个Windows补丁的时间真的很长。希望新的打印机服务能更安全。
时间线
- 2020-07-27 报告给MSRC。
- 2020-08-19 MSRC决定推迟补丁。
- 2020-08-22 获得赏金。
- 2021-01-13 补丁发布。