支持本站 — 捐款将帮助我们持续运营

目标: 1000 元,已筹: 1000

100.0%

POC详情: aed79fef3ac1dfc545d55a3eab8e1629dbfef610

来源
关联漏洞
标题:Microsoft Win32k 资源管理错误漏洞 (CVE-2021-40449)
Description:Microsoft Win32k是美国微软(Microsoft)公司的一个用于Windows多用户管理的系统文件。 Microsoft Windows Win32K存在资源管理错误漏洞。以下产品和版本受到影响:Windows 10 Version 1809 for 32-bit Systems,Windows 10 Version 1809 for x64-based Systems,Windows 10 Version 1809 for ARM64-based Systems,Windows Serve
Description
Exploit for CVE-2021-40449 - Win32k Elevation of Privilege Vulnerability (LPE)
介绍
# CallbackHell

Exploit for CVE-2021-40449 (Win32k - LPE)

- [CallbackHell](#callbackhell)
  - [Description](#description)
  - [Technical Writeup](#technical-writeup)
  - [PoC](#poc)
  - [References](#references)

## Description

CVE-2021-40449 is a use-after-free in Win32k that allows for local privilege escalation.

The vulnerability was found in the wild by [Kaspersky](https://www.kaspersky.com/blog/mysterysnail-cve-2021-40449/42448/).

The discovered exploit was written to support the following Windows products:
 - Microsoft Windows Vista
 - Microsoft Windows 7
 - Microsoft Windows 8
 - Microsoft Windows 8.1
 - Microsoft Windows Server 2008
 - Microsoft Windows Server 2008 R2
 - Microsoft Windows Server 2012
 - Microsoft Windows Server 2012 R2
 - Microsoft Windows 10 (build 14393)
 - Microsoft Windows Server 2016 (build 14393)
 - Microsoft Windows 10 (build 17763)
 - Microsoft Windows Server 2019 (build 17763)

However, this exploit is current only tested on the following versions:
 - Microsoft Windows 10 (build 14393)
 - Microsoft Windows 10 (build 17763)

## Technical Writeup

I highly recommend reading Kaspersky's [technical writeup](https://securelist.com/mysterysnail-attacks-with-windows-zero-day/104509/) before proceeding.

As mentioned in the technical writeup by Kasperky, the vulnerability exists in `GreResetDCInternal`. If an attacker hooks the user-mode callback `DrvEnablePDEV`, which is called during `hdcOpenDCW`, it is possible to destroy the original device context by calling `ResetDC`, which causes a use-after-free in the kernel when the user-mode callback returns.

The following pseudo-code is made partially from the leaked Windows XP source code and by reverse-engineering the latest (before the patch) `GreResetDCInternal` from `Win32kfull.sys`. The irrelevant parts have been removed with `[...]`. Look for the `VULN: ` comments.
```c
BOOL GreResetDCInternal(
    HDC hdc,
    DEVMODEW *pdmw,
    BOOL *pbBanding,
    DRIVER_INFO_2W *pDriverInfo2,
    PVOID ppUMdhpdev)
{
    // [...]
    HDC hdcNew;

    {
        // Create DCOBJ from HDC
        DCOBJ dco(hdc);

        if (!dco.bValid())
        {
            SAVE_ERROR_CODE(ERROR_INVALID_HANDLE);
        }
        else
        {
            // Create DEVOBJ from `dco`
            PDEVOBJ po(dco.hdev());

            // [...]

            // Create the new DC
            // VULN: Can result in a usermode callback that destroys old DC, which
            // invalidates `dco` and `po`
            hdcNew = hdcOpenDCW(L"",
                                pdmw,
                                DCTYPE_DIRECT,
                                po.hSpooler,
                                prton,
                                pDriverInfo2,
                                ppUMdhpdev);

            if (hdcNew)
            {
                po->hSpooler = NULL;

                DCOBJ dcoNew(hdcNew);

                if (!dcoNew.bValid())
                {
                    SAVE_ERROR_CODE(ERROR_INVALID_HANDLE);
                }
                else
                {
                    // Transfer any remote fonts

                    dcoNew->pPFFList = dco->pPFFList;
                    dco->pPFFList = NULL;

                    // Transfer any color transform

                    dcoNew->pCXFList = dco->pCXFList;
                    dco->pCXFList = NULL;

                    PDEVOBJ poNew((HDEV)dcoNew.pdc->ppdev());

                    // Let the driver know
                    // VULN: Method is taken from old (possibly destroyed) `po`
                    PFN_DrvResetPDEV rfn = po->ppfn[INDEX_DrvResetPDEV];

                    if (rfn != NULL)
                    {
                        (*rfn)(po->dhpdev, poNew->dhpdev);
                    }

                    // [...]
                }
            }
        }
    }

    // Destroy old DC
    // [...]
}
```

As can be seen from the pseudo-code, the old device context can be freed in a user-mode callback from the `hdcOpenDCW` call, and later on, the method `DrvResetPDEV` is retrieved from the old device context and called with `(po->dhpdev, poNew->dhpdev)`.

To create and hook a device context, one can do the following:

- Find an available printer with `EnumPrinters`
- Load the printer driver into memory with `OpenPrinter`, `GetPrinterDriver` and `LoadLibraryExA`
- Get the printer driver's user-mode callback table with `GetProcAddress` and `DrvEnableDriver`
- Unprotect the printer driver's user-mode callback table with `VirtualProtect`
- Overwrite the printer driver's desired user-mode callback table entries
- Create a device context for the printer with `CreateDC(NULL, printerName, NULL, NULL)`

We should now have a device context for a printer with hooked user-mode callbacks.

We're interested in only one hook, namely `DrvEnablePDEV`. This hook is interesting in two aspects: triggering the UAF and controlling the arguments, as described earlier. To trigger the UAF vulnerability, we will call `ResetDC` inside of the hook, which will destroy the old device context. When we return from the hook, we will still be inside the first `GreResetDCInternal`, which will shortly after get and call the function pointer for `DrvResetPDEV` from our old and destroyed device context with the two arguments that got returned from `DrvEnablePDEV`; the old and the new `DHPDEV`.

If your process is running with a medium integrity level, KASLR should not be an issue with the help of `EnumDeviceDrivers` and `NtQuerySystemInformation`. 

Kaspersky mentions that the original exploit used GDI palette objects and a single kernel function call to achieve arbitrary memory read/write. This exploit uses [a technique to allocate a BitMapHeader on the big pool](https://blahcat.github.io/2019/03/17/small-dumps-in-the-big-pool/) and `RtlSetAllBits` to enable all privileges on our current process token. The `BitMapHeader` will point to our current process token's `_SEP_TOKEN_PRIVILEGES`. By calling `RtlSetAllBits(BitMapHeader)`, it's possible to enable all privileges for our current process token with a single kernel function call. From here, one can abuse the new privileges to get SYSTEM. This exploit uses `SeDebugPrivilege` to inject shellcode into the `winlogon.exe` process.

## PoC

![./poc.png](https://raw.githubusercontent.com/ly4k/CallbackHell/main/poc.png)

## References

- [https://securelist.com/mysterysnail-attacks-with-windows-zero-day/104509/](https://securelist.com/mysterysnail-attacks-with-windows-zero-day/104509/)
- [https://github.com/siberas/CVE-2016-3309_Reloaded/](https://github.com/siberas/CVE-2016-3309_Reloaded/)
- [https://www.ired.team/miscellaneous-reversing-forensics/windows-kernel-internals/how-kernel-exploits-abuse-tokens-for-privilege-escalation](https://www.ired.team/miscellaneous-reversing-forensics/windows-kernel-internals/how-kernel-exploits-abuse-tokens-for-privilege-escalation)
- [https://github.com/KaLendsi/CVE-2021-40449-Exploit](https://github.com/KaLendsi/CVE-2021-40449-Exploit)
- [https://mp.weixin.qq.com/s/AcFS0Yn9SDuYxFnzbBqhkQ](https://mp.weixin.qq.com/s/AcFS0Yn9SDuYxFnzbBqhkQ)
文件快照

[4.0K] /data/pocs/aed79fef3ac1dfc545d55a3eab8e1629dbfef610 ├── [4.0K] CallbackHell │   ├── [ 20K] CallbackHell.cpp │   ├── [7.0K] CallbackHell.vcxproj │   └── [ 985] CallbackHell.vcxproj.filters ├── [1.4K] CallbackHell.sln ├── [1.0K] LICENSE ├── [149K] poc.png └── [7.0K] README.md 1 directory, 7 files
神龙机器人已为您缓存
备注
    1. 建议优先通过来源进行访问。
    2. 如果因为来源失效或无法访问,请发送邮件到 f.jinxu#gmail.com 索取本地快照(把 # 换成 @)。
    3. 神龙已为您对 POC 代码进行快照,为了长期维护,请考虑为本地 POC 付费/捐赠,感谢您的支持。