Windows Kernel APC Data-Free Local Privilege Escalation Vulnerability
Release Date:
December 13, 2005
Date Reported:
May 23, 2005
External Refferences:
eEye ID# EEYEB-20050523
OSVDB ID# 18823
CVE # CAN-2005-2827
Microsoft # MS05-055
Severity:
Medium (Local Privilege Escalation to Kernel)
Systems Affected:
Windows NT 4.0
Windows 2000
Overview:
eEye Digital Security has discovered a local privilege escalation
vulnerability in the Windows kernel that could allow any code executing
on a Windows NT 4.0 or Windows 2000 system to elevate itself to the
highest possible local privilege level (kernel). For example, a
malicious user, network worm, or e-mail virus could take advantage of
this vulnerability in order to completely compromise the vulnerable
system on which the exploit code is executing, regardless of that code's
original privilege level.
The vulnerability exists in the thread termination routine contained
within NTOSKRNL.EXE. Through a specific series of steps, a local
attacker can cause the code responsible for discarding queued
Asynchronous Procedure Call (APC) entries to erroneously attempt to free
a region of kernel data, producing a "data free" vulnerability that may
be exploited in order to alter arbitrary kernel memory, or even divert
the flow of execution directly.
Technical Details:
The basis of this vulnerability is in PspExitThread's APC freeing loop
and in the behavior of KiMoveApcState, invoked from KiAttachProcess and
KeUnstackDetachProcess. We'll give a description of the problem below,
followed by a "call flow" illustration to outline the specific sequence
of events.
When a thread is exiting, PspExitThread will detach the thread's APC
queues from ETHREAD.ApcState.ApcListHead[0] and ApcListHead[1], so that
each queue is now a circular, doubly-linked list in which the first and
last nodes do not point back to the list head (LIST_ENTRY structure).
However, since the list heads' pointers are not modified, the purpose is
presumably just to allow the APC freeing loop within PspExitThread to
walk each list and free its nodes, without navigating back to the list
head and erroneously attempting to free memory within the ETHREAD
structure. Of course, the vulnerability is that this can be made to
happen, and the result is a "data free" condition that eventually causes
ExFreePoolWithTag to operate on user memory.
APCs queued by an external process count against that process's pool
quota, and therefore the quota block of the pool block containing the
APC structure has a reference to the queuing process. If the exiting
thread contains an APC queued by a now-terminated external process in
its lists, and if that APC node represents the last reference to the
process's Process object, then freeing that node will cause the Process
object to be destroyed from within ExFreePoolWithTag. Part of this
sequence involves executing PspProcessDelete, which switches to the
ending process's address space using KeStackAttachProcess, calls
PspExitProcess, and then reverses the switch with
KeUnstackDetachProcess.
Both the "attach" and "detach" functions call KiMoveApcState, which is
intended to temporarily strip the thread of its APCs so that none are
dispatched in an address space for which they were not intended, then
re-link the list of APCs after the thread's native address space is
reinstated. During attach, the ETHREAD.ApcState structure is
duplicated, and the pointers of the lists' first and last nodes are
adjusted to refer to the copy. Upon detach, the first and last nodes'
pointers are adjusted to re-link the lists to the original
ETHREAD.ApcState -- even though they were supposed to remain
disconnected, since the APC free loop is still in progress. The end
result is that the free loop will continue and attempt to free a portion
of the ETHREAD structure as though it were a pool block header,
culminating in the kernel operating on attacker-supplied pointers from
user-land memory, because the accessed portion of ETHREAD contains
predictable and mostly zeroed values.
The following depicts the sequence of function calls and parameters
involved in producing the vulnerable condition:
. PspExitThread
. . KeFlushQueueApc
. . (detaches APC queues from ETHREAD.ApcState.ApcListHead)
. . (APC free loop begins)
. . ExFreePool(1st_APC -- queued by exited_process)
. . . ExFreePoolWithTag(1st_APC)
. . . . ObfDereferenceObject(exited_process)
. . . . . ObpRemoveObjectRoutine
. . . . . . PspProcessDelete
. . . . . . . KeStackAttachProcess(exited_process)
. . . . . . . . KiAttachProcess
. . . . . . . . . KiMoveApcState(ETHREAD.ApcState --> duplicate)
. . . . . . . . . KiSwapProcess
. . . . . . . PspExitProcess(0)
. . . . . . . KeUnstackDetachProcess
. . . . . . . . KiMoveApcState(duplicate --> ETHREAD.ApcState)
. . . . . . . . KiSwapProcess
. . ExFreePool(2nd_APC)
. . ExFreePool(ETHREAD + 30h)
. . (APC free loop ends)
The ETHREAD data upon which ExFreePool is called is mostly predictable,
KernelStack at offset +28h being the single true variable; however,
methods for leaking a thread's kernel ESP permit complete control over
the path execution will take through ExFreePoolWithTag. With enough
crafting, an arbitrary function pointer can be supplied as an object
type method, allowing execution to be hijacked directly.
Beginning with Windows XP, KeFlushQueueApc contains a code fix that
resolves this vulnerability.
Protection:
Retina Network Security Scanner has been updated to identify this
vulnerability.
Vendor Status:
Microsoft has released a patch for this vulnerability. The patch is
available at:
http://www.microsoft.com/technet/security/bulletin/MS05-055.mspx
Credit:
Derek Soeder
Greetings:
Dedicated to
R. W. S., Sr.
1928 - 2005
From my father to his:
"He was a good man; liked by all, loved by many. He was always upbeat,
outgoing and loved to kid around. He was always willing to help others
in their time of need and gave a lot of himself. He was very creative,
handy with tools, and could fix about anything. He was the one everyone
turned to for advice and direction. He was my father, and I miss him
dearly."
Copyright (c) 1998-2005 eEye Digital Security
Permission is hereby granted for the redistribution of this alert
electronically. It is not to be edited in any way without express
consent of eEye. If you wish to reprint the whole or any part of this
alert in any other medium excluding electronic medium, please email
alert (at) eEye (dot) com [email concealed] for permission.
Disclaimer
The information within this paper may change without notice. Use of
this information constitutes acceptance for use in an AS IS condition.
There are no warranties, implied or express, with regard to this
information. In no event shall the author be liable for any direct or
indirect damages whatsoever arising out of or in connection with the use
or spread of this information. Any use of this information is at the
user's own risk.