Windows中错误报告机制导致的提权漏洞(CVE-2019-0863)

iso60001  1968天前

22.png

在2018年12月,一个名为“SandboxEscaper”的黑客公开了一个Windows Error Reporting(WER)组件中的0day漏洞。而根据他所提供的信息,我又发现了另一个0day漏洞,可被用于非法提升系统权限。根据微软方面的说法,已有攻击者利用这个漏洞进行攻击,但直到2019年5月该漏洞补丁才发布。

那么,这个漏洞的原理是啥呢?

微软的又一次失误

Windows Error Reporting工具是一个灵活的基于事件的反馈架构,旨在收集有关Windows的软硬件错误的信息,并将这些信息报告给Microsoft,好为用户提供可用的解决方案。

例如,当Windows系统崩溃或发生故障,则会生成一个错误报告并存储在WER报告队列目录下(C:\ProgramData\Microsoft\Windows\WER\ReportQueue),其中每个报告都有自己的子目录和一个存储相关元数据的名为report.wer的INI文件。为了使所有进程都能上报系统错误信息,所有用户都可以对reportQueue目录进行写入,具体如下所示:

33.png

生成报告后,接下来就是将其发送给Microsoft以进行进一步分析。此交互流程可以通过多种方式触发,其中一种就是使用名为Windows Error Reporting\QueueReporting的计划任务。而从安全角度来看,此计划任务很有趣,因为:

  • 它以system权限运行,这就非常敏感了。

  • 它可以根据需求触发。

  • 它涉及了一个exe文件wermgr.exe,以及一个参数-upload

44.png

在计划任务触发后,wermgr.exe与等待处理的报告文件和目录进行交互。它会读取、解析这些文件,将它们复制到其他目录,或是直接删除。但最重要的是,现在一个高权限的exe会处理任何用户都可以写入的文件。如果这中间流程存在问题,可能会导致一些严重的安全漏洞。

滥用文件链接

Windows支持不同类型的文件链接,它们可将某处的文件或目录指向其他的文件和目录,简单来说,就是会将用户重定向到目标路径。从安全的角度来看,文件链接很容易造成权限漏洞,因为用户可以将某些文件链接到他们没有写权限的文件或目录。

下面的示例描述了不具有kernel32.dll写入权限的用户是如何创建c:\temp\Dir\x.dllC:\Windows\System32\kernel32.dll之间的链接的。这样有可能使黑客可以读、写甚至删除敏感的系统文件。

55.png

漏洞信息

简而言之,黑客可以利用WER的system权限去更改任意文件。通过上述文件的链接,将WER目录中的文件链接到计算机上其他目录的文件,从而借助计划任务的system权限帮助自己提升权限。

以下是完整的漏洞利用场景:

  • Step 1:wermger.exe逐个解析报告目录中的所有文件,并将其提交给Microsoft。

  • Step 2:当wermger.exe检测到名为Report.wer的被损坏的INI文件时,会进行一系列处理,最终会将其删除。但在删除前,它会改变文件的访问控制权限,以方便将其删除。

  • 漏洞利用点:黑客主要是利用wermger.exe读取文件的访问控制权限和改变其权限之间的短暂机会。如果攻击者创建一个错误报告与系统上其他文件之间的链接,则在修改访问控制的权限后,wermgr.exe就会错误地修改其他文件的权限。

Step 1:

命令wermgr.exe -upload所做的第一件事就是调用wermgr!DoCoreUpload函数,它会列出reportQueue下的所有子目录,并读取错误报告将其提交给Microsoft:

int64 DoCoreUpload(/* ... */) {
    /* ... */
    Ret = WerpSubmitReportFromStore(ReportPath, /* ... */);
    if (Ret >= 0) {
        /* Report successfully uploaded */
    } else {
        if (Ret == ERROR_FILE_CORRUPT) {
            DeleteCorruptedReportFromStore(ReportPath);
        }
    }
}

Step 2:

当wermgr.exe遇到已损坏的名为report.wer的INI文件时,它会更改其访问控制权限以便稍后删除它。更具体地说:

1.首先,wermgr!DeleteCorruptedReportFromStore会列出子目录下的所有文件;

2.接着,wermgr!PreparePathForDeletion会修改每个文件的权限。这就是漏洞原理所在!因为此函数会使用kernel32!GetFileSecurity读取文件的安全描述符,并利用kernel32!SetFileSecurity将其设置为可删除。

int64 PreparePathForDeletion(wchar_t* FileName) {
    PSECURITY_DEsc riptOR SecurityDesc riptor = NULL;
    DWORD BytesRead = 0;
    PDACL Dacl = NULL;
    /* ... */

    if ( !GetFileSecurity(FileName, 
                DACL_SECURITY_INFORMATION, 
                NULL, 0, &BytesRead) ) {
        /* ... */
        return;
    }

    SecurityDesc riptor = new BYTE[BytesRead];

    if ( !GetFileSecurity(FileName, 
                DACL_SECURITY_INFORMATION, 
                SecurityDesc riptor, 
                BytesRead, &BytesRead) ) { 
        /* ... */
        return;
    }

    if ( GetSecurityDesc riptorDacl(SecurityDesc riptor, 
                         &DaclPresent, 
                         &Dacl, &DaclDefaulted) )
    {
        /* ... */
        HANDLE TokenHandle = NULL;
        PACL NewAcl = NULL;
        EXPLICIT_ACCESS ExplicitAccess = {0};

        /* ... */
        LPVOID UserName = new BYTE[/* ... */];
        GetTokenInformation(TokenHandle, TokenUser, 
                      UserName, &BytesRead);

        ExplicitAccess.Trustee.ptstrName = UserName;
        ExplicitAccess.Trustee.TrusteeType = TRUSTEE_IS_NAME;
        ExplicitAccess.grfAccessMode = GRANT_ACCESS;
        ExplicitAccess.grfAccessPermissions = DELETE | /* ... */;
        /* ... */

        SetEntriesInAcl(1, &ExplicitAccess, Dacl, &NewAcl);
        InitializeSecurityDesc riptor(&SecurityDesc riptor, 1);
        SetSecurityDesc riptorDacl(&SecurityDesc riptor, 1, NewAcl, 0);
        SetFileSecurity(FilePath, DACL_SECURITY_INFORMATION, 
                &SecurityDesc riptor);    
    }
}

不过,在特定的时间创建文件链接较为困难,这可能需要一次又一次的尝试。攻击者在实际操作中很可能以可执行文件(dll、exe或脚本)为目标,尝试使用恶意文件覆盖它们,最后等待系统自动执行。

本文由白帽汇整理并翻译,不代表白帽汇任何观点和立场
来源:https://unit42.paloaltonetworks.com/tale-of-a-windows-error-reporting-zero-day-cve-2019-0863/

最新评论

昵称
邮箱
提交评论