Skip to content

Windows Kernel Local Denial-of-Service #5: win32k!NtGdiGetDIBitsInternal (Windows 7-10)

Today I’ll discuss yet another way to bring the Windows operating system down from the context of an unprivileged user, in a 5th and final post in the series. It hardly means that this is the last way to crash the kernel or even the last way that I’m aware of, but covering these bugs indefinitely could soon become boring and quite repetitive, so I’ll stop here and return with other interesting material in the near future. Links to the previous posts about Windows DoS issues are listed below:

The bug explained today can be found in the win32k!NtGdiGetDIBitsInternal system call, which has been around since the very early days of Windows existence (at least Windows NT). The syscall is used by the GetDIBits, BitBlt and StretchBlt documented API functions, and has been recently subject to patching in Microsoft’s April Patch Tuesday, in order to fix an unrelated double-fetch vulnerability reported by Project Zero (CVE-2017-0058, issue #1078 in the tracker). The DoS problem was also reported to the vendor at that time, but due to its low severity, it didn’t meet the bar for a security bulletin.

The purpose of the function is to acquire bitmap data based on a Device Context, HBITMAP object, starting scan line, number of scan lines, a BITMAPINFO header and an output buffer. This is illustrated by the following function declaration present in the ReactOS sources:

INT
APIENTRY
NtGdiGetDIBitsInternal(
    _In_ HDC hdc,
    _In_ HBITMAP hbm,
    _In_ UINT iStartScan,
    _In_ UINT cScans,
    _Out_writes_bytes_opt_(cjMaxBits) LPBYTE pjBits,
    _Inout_ LPBITMAPINFO pbmi,
    _In_ UINT iUsage,
    _In_ UINT cjMaxBits,
    _In_ UINT cjMaxInfo)

This declaration suggests that a maximum of cjMaxBits bytes can be written to the pjBits output memory area. The conclusion seems to be correct after taking a look at the actual implementation of the function in win32k.sys, where we can find the following code snippet:

Continue reading ›

Windows Kernel Local Denial-of-Service #4: nt!NtAccessCheck and family (Windows 8-10)

After a short break, we’re back with another local Windows kernel DoS. As a quick reminder, this is the fourth post in the series, and links to the previous ones can be found below:

The bug we’re discussing today resides in an internal nt!SeAccessCheckByType function, reachable via three system calls: NtAccessCheck, NtAccessCheckByType and NtAccessCheckByTypeResultList. All Windows versions starting with Windows 8 are affected, which is caused by the fact that the relevant code area is specific to so-called lowbox tokens (used by AppContainers), a mechanism that was only introduced in Windows 8. Similarly to the past issues, this one was also discovered by a Bochspwn-like instrumentation, and is caused by an unsafe access to user-mode memory (not guarded by adequate exception handling).

The declaration of the NtAccessCheck syscall, which we will use in our exploit, is shown below:

NTSTATUS WINAPI NtAccessCheck(
  _In_ PSECURITY_DESCRIPTOR SecurityDescriptor,
  _In_ HANDLE ClientToken,
  _In_ ACCESS_MASK DesiredAccess,
  _In_ PGENERIC_MAPPING GenericMapping,
  _Out_writes_bytes_(*PrivilegeSetLength) PPRIVILEGE_SET PrivilegeSet,
  _Inout_ PULONG PrivilegeSetLength,
  _Out_ PACCESS_MASK GrantedAccess,
  _Out_ PNTSTATUS AccessStatus
  );

Interestingly, the nt!SeAccessCheckByType routine is very well aware of the fact that it operates on pointers provided by client applications, as evidenced by the number of try/except constructs which are present inside of the function. Their exact number can be determined by looking at the identifiers written to the TryLevel field of the local SEH frame (EH3_EXCEPTION_REGISTRATION structure):

Continue reading ›

Windows Kernel Local Denial-of-Service #3: nt!NtDuplicateToken (Windows 7-8)

This is the third post in a series about unpatched local Windows Kernel Denial-of-Service bugs. The list of previous posts published so far is as follows:

As opposed to the two issues discussed before, today’s bug is not in the graphical subsystem (win32k.sys), but in the core kernel module: ntoskrnl.exe, and more specifically in the handler of the nt!NtDuplicateToken system call (under the same name). Update: an equivalent bug can also be found in the nt!NtCreateToken system call, but since it requires the SeCreateTokenPrivilege privilege, it cannot be triggered by a regular user, and hence is not of much interest to us.

According to MSDN, the definition of the syscall is as follows:


The vulnerability in question is caused by an unprotected access to the user-controlled pointer passed through the ObjectAttributes parameter. In fact, the argument is referenced several times in the system call handler; first, it is passed down to the nt!SeCaptureSecurityQos routine, and later to nt!SepDuplicateToken. In both those cases, reading from the memory area is guarded by the necessary try/except blocks. However, there is also a third read performed directly in the top-level syscall handler:

Continue reading ›

Windows Kernel Local Denial-of-Service #2: win32k!NtDCompositionBeginFrame (Windows 8-10)

Another week, another way to locally crash the Windows kernel with an unhandled exception in ring-0 code (if you haven’t yet, see last week’s DoS in win32k!NtUserThunkedMenuItemInfo). Today, the bug is in the win32k!NtDCompositionBeginFrame system call handler, whose beginning can be translated into the following C-like pseudo-code:

NTSTATUS STDCALL NtDCompositionBeginFrame(HANDLE hDirComp, PINPUT_STRUCTURE lpInput, POUTPUT_STRUCTURE lpOutput) {
  NTSTATUS st;
  INPUT_STRUCTURE Input;
  DirectComposition::CConnection *Connection;

  if (lpInput != NULL) {
    try {
      ProbeForRead(lpInput, sizeof(INPUT_STRUCTURE), 1);
      RtlCopyMemory(&Input, lpInput, sizeof(INPUT_STRUCTURE));
      st = STATUS_SUCCCESS;
    } __except(EXCEPTION_EXECUTE_HANDLER) {
      st = GetExceptionCode();
    }
  } else {
    st = STATUS_INVALID_PARAMETER;
  }

  KeEnterCriticalRegion();
  if (NT_SUCCESS(st)) {
    st = DirectComposition::CConnection::ReferenceHandle(hDirComp, &Connection);
    if (NT_SUCCESS(st)) {
      if (Microsoft_Windows_Win32kEnableBits & 1) {
        Template_xq(&DCompBeginFrameEvent, hDirComp, lpInput->SomeField);
      }
      [...]
    }
  }

  [...]
}

Since the i/o structure names and definitions are not known to me, I just generically called them INPUT_STRUCTURE and OUTPUT_STRUCTURE; their details are non-essential to understand the bug. Here, we can see that the 2nd argument (lpInput) is accessed twice: once in line 9, with a proper sanitization with an inlined ProbeForRead call and a try/except block, but then also in line 23, where a field at offset 0x10 (SomeField in the above listing) is read from the user pointer while exception handling is disabled. The Template_xq function is just a thin wrapper around EtwWrite, which is used for logging kernel-mode events. This is the bug we want to exploit.

In order to reach the vulnerable code, we have to meet a few conditions:

  1. Make sure that the initial copy from the pointer in line 9 succeeds, i.e. the address is valid and points to readable memory. This can be satisfied by running a race condition attack, where one thread continuously flips access rights for the memory page, while another one keeps invoking the affected system call in a loop.
  2. Have the DirectComposition::CConnection::ReferenceHandle function succeed by passing in a valid handle, which can be obtained by invoking the win32k!NtDCompositionCreateConnection system call in advance.
  3. Have the 0x1 flag set in the global Microsoft_Windows_Win32kEnableBits variable.

Continue reading ›

Windows Kernel Local Denial-of-Service #1: win32k!NtUserThunkedMenuItemInfo (Windows 7-10)

Back in 2013, Gynvael and I published the results of our research into discovering so-called double fetch vulnerabilities in operating system kernels, by running them in full software emulation mode inside of an IA-32 emulator called Bochs. The purpose of the emulation (and our custom embedded instrumentation) was to capture detailed information about accesses to user-mode memory originating from the kernel, so that we could later run analysis tools to discover multiple references to single memory addresses within the scope of one system call, and produce meaningful reports. The project was called Bochspwn [1][2][3] (or kfetch-toolkit on Github) and was largely successful, leading to the discovery of several dozen serious vulnerabilities in the Windows kernel. We believe it also played a significant role in popularizing the double-fetch vulnerability class and the concept of using system-wide instrumentation for security, as several other fruitful projects ensued as a result, probably most notable of which is Xenpwn.

After all this time, I decided to get back on the subject of full system instrumentation and analyzing various execution traces in search of indicators of potential vulnerabilities. Specifically, one of my goals was to develop more patterns (based on memory accesses or other events) which could signal problems in kernel-mode code other than just double fetches. One intuitive example of such pattern is the lack of exception handling being set up at the time of accessing ring-3 memory area. As the documentation of the Windows ProbeForRead function states:

Drivers must call ProbeForRead inside a try/except block. If the routine raises an exception, the driver should complete the IRP with the appropriate error. Note that subsequent accesses by the driver to the user-mode buffer must also be encapsulated within a try/except block: a malicious application could have another thread deleting, substituting, or changing the protection of user address ranges at any time (even after or during a call to ProbeForRead or ProbeForWrite).

There’s also an example on the Handling Exceptions MSDN page:

try {
    ...
    ProbeForWrite(Buffer, BufferSize, BufferAlignment);
 
    /* Note that any access (not just the probe, which must come first,
     * by the way) to Buffer must also be within a try-except.
     */
    ...
} except (EXCEPTION_EXECUTE_HANDLER) {
    /* Error handling code */
    ...
}

What happens if a ProbeFor* call or user memory access takes place outside of a try/except block? Typically nothing, but an authenticated, local attacker could exploit such a bug to cause an unhandled kernel exception (by passing in an invalid pointer or invalidating it during syscall runtime), and consequently crash the entire operating system with a Blue Screen of Death.

From a technical standpoint, it is not difficult to detect user-mode accesses with no exception handlers set up on 32-bit platforms. In Windows x86, the handler records are chained together in a SEH chain (starting at the well known fs:[0] address), where each handler is described by the following structure:

struct _EH3_EXCEPTION_REGISTRATION
{
 struct _EH3_EXCEPTION_REGISTRATION *Next;
 PVOID ExceptionHandler;
 PSCOPETABLE_ENTRY ScopeTable;
 DWORD TryLevel;
};

Continue reading ›

Slides about my Windows Metafile research (Ruxcon, PacSec) and fuzzing (Black Hat EU) now public

During the past few weeks, I travelled around the world to give talks at several great security conferences, such as Ruxcon (Melbourne, Australia), PacSec (Tokyo, Japan), Black Hat Europe (London, UK) and finally Security PWNing Conference (Warsaw, Poland). At a majority of the events, I presented the results of my Windows Metafile security research, which took place earlier this year and yielded vulnerabilities in GDI (exploitable e.g. in Internet Explorer), GDI+ (e.g. Microsoft Office), ATMFD.DLL (Windows local privilege escalation) and the Virtual Printers mechanism in VMware Workstation. As part of the talks, I explained what GDI and metafiles really are, the process I followed while hunting for and identifying the vulnerabilities, and the exploitation paths for some of them. Finally, I discussed my approach to fuzzing a user-mode Windows DLL module on Linux machines (cross-platform), on the example of a 3rd party JPEG2000 decoder used in VMware products. Since my allocated time slots at both Ruxcon and PacSec were too short to cover the entirety of the material, I talked about the ATMFD.DLL vulnerabilities exclusively at Ruxcon, and about GDI+ only at PacSec. A complete list of the EMF bugs that were mentioned in the presentations can be found in the Google Project Zero tracker.

The second talk (presented at BH) focused purely on fuzzing and the various thoughts, techniques and results I arrived at after actively using this approach to uncover software security flaws for more than 5 years, both as part of and outside of work. The topics included gathering initial corpora of input files, extracting code coverage information from running programs, using this information to “distill” and manage live corpora (using a parallelized algorithm), interacting with our target application on various levels, and effectively mutating the input data to accomplish the best results. The presentation was then concluded with a brief analysis of my recent Windows kernel font fuzzing initiative, which has resulted in the discovery of 18 issues so far.

In this post, I would like to publicly announce both slide decks used in the above talks. While some of the conferences have already made them available on their corresponding websites, the slides linked here include some further fixes and improvements, and specifically the EMF ones are all combined into a single PDF file, forming a self-contained source of information about all the discovered bugs. Enjoy, and as always, feel free to send questions, comments and suggestions.

Windows Metafiles: An Analysis of the EMF Attack Surface & Recent Vulnerabilities

Download

Effective File Format Fuzzing – Thoughts, Techniques and Results

Download

Windows system call tables updated, refreshed and reworked

Those of you interested in the Windows kernel-mode internals are probably familiar with the syscall tables I maintain on my blog: the 32-bit and 64-bit listings of Windows system calls with their respective IDs in all major versions of the OS, available here (and are also linked to in the left menu):

After a few years of inactivity in this area, I’ve found some time to update and thoroughly refresh the tables. The changelog is as follows:

  1. Added information from Windows Server 2003 (R2, R2 SP2), Windows Server 2008 (R2, R2 SP1), Windows Server 2012 (R2) and Windows 10 (1507, 1511, 1607).
  2. Clarified some versions of Windows, resulting in removing non-existent Windows Server 2008 SP1 (32-bit), Windows XP SP0 (64-bit), Windows Server 2003 SP1 (64-bit), Windows Server 2008 SP1 (64-bit).
  3. Removed empty columns with missing information from the win32k 32-bit table.
  4. Performed a major clean up of the lists, resolving all syscall handler collisions and renaming invalid symbols (e.g. “FsRtlSyncVolumes”) stemming from compiler optimizations to their correct form. From now on, all system calls are represented by their real names starting with “Nt”.
  5. Unified the layout of NT and win32k tables.
  6. Added more granular information to the win32k 64-bit table (accounting for all service packs and major releases).
  7. Fixed HTML syntax errors and improved JavaScript code formatting.

I hope the tables keep proving useful for Windows researchers interested in those interfaces. :-) And of course, all comments, suggestions and bug reports are highly appreciated!

Disclosing stack data (stack frames, GS cookies etc.) from the default heap on Windows

In the previous blog post, I discussed a modest technique to “fix” the default process heap in order to prevent various Windows API functions from crashing, by replacing the corresponding field in PEB (Process Environment Block) with a freshly created heap. This of course assumes that the attacker has already achieved arbitrary code execution, or is at least able to use ROP and knows the base addresses of some vital system DLLs. It is likely the last exploitation technique one would use before gaining full control over the vulnerable application or system, and was indeed used by Gynvael and me while wrapping up the exploitation of the easier challenge during this year’s DEF CON CTF qualifiers which took place in May.

However, before we could even reach that stage, I had to overcome a few other significant obstacles, the hardest of which was converting the available primitives into a hijacked control flow. Following hours of trying to reproduce the same heap layout on the organizers’ and my own platform (exploiting the bugs was in fact the easiest part), I finally managed to achieve close to arbitrary memory read and write capabilities. By that point, I knew the location of the heap, the challenge image base and NTDLL.DLL image base, where I could freely read from and write to. On the other hand, the task itself did not make it easy to get controlled EIP even with such powerful primitives, as it didn’t store plain-text function pointers, virtual objects or any data directly controlling the execution flow on either the heap or in static memory. This meant that a generic technique had to be used instead.

All of the ideas I tested throughout Day 2 of the competition fell through. The CRT-related function pointers in static memory I could potentially overwrite were encoded with the EncodePointer API. There were some vtable pointers on the heap used during program termination, but I was unable to get them positioned in a similar fashion both locally and remotely, and I strived to write an exploit that I could test in both environments (a fellow CTF player – Dougall – didn’t care and just blindly exploited the bug on the task server). I had a pretty decent idea centered around a list of destructor pointers saved in NTDLL, but in a last attempt to find a simpler and more elegant solution, I decided to check if the stack address couldn’t be somehow leaked from heap, which I could read without any limits.

In theory, storing stack addresses on the heap doesn’t make any sense. The heap is designed for long-lasting allocations that can be passed between various execution contexts within a  single process (functions, threads etc.), while stack objects are only valid for the duration of a function execution (or even shorter). Thus, we should not typically observe any stack addresses placed on the heap, or else they would indicate some very poor programming practices. However, Windows is a complex system full of unexpected quirks, so there might still be many non-obvious reasons for such behavior, and all I really needed was a single stack address at a roughly consistent position on the heap. With this assumption, I wrote the following simple program to scan through the entire default process heap in search of the desired addresses:

Continue reading ›

Windows user-mode exploitation trick – refreshing the main process heap

During the weekend of May 21-23 (directly after the CONFidence CTF that we organized with Dragon Sector), qualifications to the famous DEF CON CTF 2016 took place. We obviously participated in what is probably the most binary heavy, challenging and competitive CTF of the year, eventually ending up 9th on the final scoreboard, which was sufficient to get us qualified to the main event. :-)

While the competition featured a great number of tasks to solve, including multiple pwnables in the CGC (Cyber Grand Challenge) formula, I must admit that I spent nearly the entire CTF working on a single challenge: a vulnerable Windows x86 executable called easier, authored by Thing2. After two full days of hacking by myself, and developing a ROP chain together with Gynvael for the last few hours, we managed to get the flag just in time – roughly 25 minutes before the end of the CTF. Overall, the problem was the second with fewest successful solves (completed by a total of 5 teams – PPP, DEFKOR, 9447, Samurai and Dragon Sector), and considering that it was available since the start of the contest (contrary to secrfrevenge), it was probably the most difficult challenge of all.

The source code of the task is available on LegitBS’ github: here. If you are interested in reading a complete (but quite different than ours) solution of the 9447 team, check out the following article: Def Con Quals 2016 – Easier [Pwnable].

The CTF challenge

For some basic context, the task was a very small executable, with DEP and ASLR enabled, running on Windows Server 2012 (Amazon EC2) under AppJailLauncher. It used symmetric encryption with a static key for communication, and allowed the network client to perform 8 operations, all centered around a list of allocations on the heap. There were plenty of vulnerabilities, or at least code constructs which appeared as such, but turned out to be unusable in practice. This made me wonder if I was missing something, the author was trolling hard, or if they just didn’t sufficiently test the task. Now I know it wasn’t #1 (since other players had the same thoughts), but I still don’t know which of options #2 and #3 it is. :)

Continue reading ›

Details on a (not so recent now) stack-based buffer overflow in the Adobe CFF rasterizer in FreeType2 (CVE-2014-2240, CVE-2014-9659)

This blog has experienced a long time of inactivity, as I’ve recently used it only to publish slides from conferences I presented at, with many months-long breaks in between. I am planning to change things up and start posting again in the upcoming weeks, starting with this blog post, which I originally wrote in early 2014. I haven’t posted it back then, as the bug in the FreeType project discussed here motivated me to look at other implementations of PostScript fonts and CharStrings specifically, which eventually resulted in an extensive research, dozens of bugs fixed by Microsoft, Adobe and Oracle, five long blog posts on the Google Project Zero blog (see the “One font vulnerability to rule them all” series), two nominations, and one Pwnie award. I didn’t want to spoil too much of what I was working on, and then just forgot about the post, but now that things have settled down on the font security front and I’m reactivating the blog, it is finally ready to go. Enjoy, and keep in mind the tenses in the article are used as if it was still 2014. :-) Some new parts I’ve added while dusting off the text are written in orange.

The bug was also briefly discussed during my last year’s 44CON presentation, see here.


At Google, we perform fuzz testing of a number of software targets: web browers, plugins, document viewers, open-source programs, libraries and more. A number of instances of our fuzzing efforts and their results have been documented in the past, see e.g. the “PDF fuzzing and Adobe Reader 9.5.1 and 10.1.3 multiple critical vulnerabilities”, “PDF Fuzzing Fun Continued: Status Update” or recent “FFmpeg and a thousand fixes” blog posts. One of the targets we have spent a lot of time on is FreeType2, a popular open-source library written in C, designed for high quality font rendering. The library is used in many commonly used operating systems and applications, such as GNU/Linux (and other Unix derivatives like FreeBSD and NetBSD), iOS, Android or ChromeOS, and hence is a valuable target for attackers seeking to exploit any of the aforementioned platforms.

The Google Security Team has always recognized the necessity for secure and robust font rendering libraries, which otherwise have been subject to frequent vulnerability hunting performed by various entities. Over the last decade, many dozens of vulnerabilities have been identified, fixed and publicly disclosed in the Windows subsystems (both kernel and user-mode) responsible for handling font files, for example:

  • Font Rasterizer Local Elevation of Privilege Vulnerability (CVE-2007-1213)
  • Embedded OpenType Font Integer Overflow Vulnerability (CVE-2010-1883)
  • TrueType Font Parsing Vulnerability (CVE-2012-0159)
  • Win32k Font Parsing Vulnerability (CVE-2013-1291)
  • Uniscribe Font Parsing Engine Memory Corruption Vulnerability (CVE-2013-3181)
  • ~25 vulnerabilities reported in the Windows Kernel, DirectWrite and .NET by yours truly in 2014 and 2015 (list).

Continue reading ›