pointers and handles - alex ionescualex-ionescu.com/publications/blackhat/blackhat2008.pdf ·...

64
Pointers and Handles A Story of Unchecked Assumptions in the Windows Kernel Alex Ionescu [email protected] Black Hat USA ‘08 1

Upload: trantram

Post on 25-Apr-2018

229 views

Category:

Documents


3 download

TRANSCRIPT

Pointers and Handles

A Story of Unchecked Assumptions in the Windows Kernel

Alex [email protected]

Black Hat USA ‘08

1

About Me• Former lead kernel developer of ReactOS

• Open source implementation of the Windows OS

• Wrote most of the kernel (except Mm and PnP)

• Teaching Windows internals class with David Solomon

• Co-authoring Windows Internals, 5th Edition

• Studying Software Engineering in Canada

2

Greets, Shouts & Respect• Woodmann’s RCE forums, OpenRCE for

being awesome community sites

• Omega_red on the RCE forums for starting all this

• Neill Clift, Jason Geffner, Sarah Blankinship and others, for testing, awesomeness and other help

• Every organizer, speaker, volunteer, and attendee at Blackhat, for making this a success

• Everyone who promotes & contributes to RE

About this Talk

• Two pairs of bugs

• Two are NULL-pointer dereferences

• Two are “special” local DoS bugs

• Second set related to a new class of local DoS attacks

• Requires understanding of several internal NT behaviors

4

Outline

• NULL Pointer Dereferences

• Windows API Design

• Windows GUI Subsystem

• The Assumption

• Exploiting

• Promoting from DoS to Ring Privilege Violation

5

Outline

• Protected Handle Close

• Windows Object Manager

• System Call PreviousMode Mechanism

• The Assumption

• Exploiting

• Developer Guidance and Q&A

6

Windows Simplified Design

7

Windows API ArchitectureWindows

Applications

Core API

Graphics (GDI) & User

API

NTDLL

NTOS Kernel

Console API

Drivers Win32 GUI Subsystem

WindowsSubsystem

High Level API

User-Mode Components• Applications (Notepad.exe)

• High Level Libraries (Msi.dll, Comctl32.dll, .NET)

• Low Level Libraries

• “base” -> Kernel32 & Parts of Advapi32.dll (Registry)

• GDI/User -> User32.dll & Gdi32.dll

• Subsystem Process (Csrss.exe)

• Native Library (Ntdll.dll)

Kernel-Mode Components

• Kernel (Ntoskrnl.exe)

• HAL (Hal.dll)

• Drivers (*.sys)

• GUI Subsystem (Win32k.sys)

• DirectX Kernel Driver (Dxgkernel.sys)

• Video Drivers (atikmdag.sys, nvlddkm.sys)

Behaviors and Code Paths

• Functionality “native” (built-in) to the kernel:

• Translated by Ntdll.dll

• Sent to kernel

• Functionality specialized to Windows API:

• Performed by, or through, Csrss.exe (ie: consoles)

• Sent to Win32k.sys (ie: video card display access)

Windows API ArchitectureWindows

Applications

Core API

Graphics (GDI) & User

API

NTDLL

NTOS Kernel

Console API

Drivers Win32 GUI Subsystem

WindowsSubsystem

Windows API ArchitectureWindows

Applications

Core API

Graphics (GDI) & User

API

NTDLL

NTOS Kernel

Console API

Drivers Win32 GUI Subsystem

WindowsSubsystem

Windows API ArchitectureWindows

Applications

Core API

Graphics (GDI) & User

API

NTDLL

NTOS Kernel

Console API

Drivers Win32 GUI Subsystem

WindowsSubsystem

Ntoskrnl.exe• Interrupts, Traps,

Booting

• Memory Management

• Thread Scheduling

• Process Management

• Synchronization, Queues

• Security & Auditing

• I/O, PnP & Power Management

NTOS Kernel

Process Manager

Scheduler

Registry Manager

Memory Manager

Security Manager

I/O Manager

Win32k.sys - User

• Window Stations

• Desktops

• Input & Message Queues

• Windows & Classes

• Menus & Hooks

• GUI Process & Thread Data

Win32k.sys

Message Passing

User Handles

Window Manager

Mouse & Keyboard

IME & Kbd Layouts

Monitors

Win32k.sys - GDI• Brushes, Pens, Cursors,

Surfaces, Lines, DCs, Paths, Regions, etc...

• ICM Color Matching

• API for Video/Print Drivers

• Floating Point Math Library

• DirectX, OpenGL Support

Win32k.sys

GDI Objects

Graphics Engine

DirectX

Displays

Fonts

Printing

NULL Pointer Dereferences

18

GUI Thread Promotion• Every Windows thread starts as a non-GUI

thread (12 kb stack)

• As soon as the first graphics system call (ID is >= 0x1000) is made, promoted to GUI thread (PsConvertToGuiThread)

• Stack grows to 60kb (KeGrowKernelStack)

• Win32k.sys thread callout is called (W32ThreadCallout)

• Win32k maintains GUI-related thread state until exit

xxxCreateThreadInfo

• Most internal Win32k.sys functions start by “xxx”

• Perverted developers? No, “yyy” and “zzz” functions also exist!

• Very different mindset from strict, organized and clear kernel naming scheme

• xxxCreateThreadInfo initializes the Win32k state (stored in W32THREAD structure) for the new GUI thread

W32THREAD

W32THREAD

PQ (Input Queue)

PKL (Keyboard Layout)

PCTI (Shared Client Data)

PDESKTOP (Owner Desktop)

PSMS (SendMessage Queue)

PPI (Parent Process Info)

PMENUSTATE (Menu State)

PHOOK (Registered Hooks)

...and more!

Our Interest• xxxCreateThreadInfo can be called for threads

that CSRSS owns

• These threads are special

• CSRSS does not belong to a desktop like other threads -- it works across all desktops

• Can’t attach to their input queue

• CSRSS is a trusted, privileged process -- certain Win32k system calls can only be done from within CSRSS

CSRSS Privileged APIs• NtUserSetInformationThread (Process Thread

State)

• NtUserSetInformationProcess (Process GUI State)

• NtUserInitialize & NtUserProcessConnect (Win32k Init)

• NtUserConsoleControl (Console Support)

• NtGdiFullscreenControl (Full-Screen Support)

• xxxRemote* APIs (Remote Control)

• More...

CSRSS & Integrity Level• CSRSS overrides integrity level (can access

any window handle)

• Input queues owned by CSRSS are always Medium IL

• Console applications’ input queues are always accessible

• Allows low IL applications to send messages to high IL command prompt (Edgar Barbarosa, COSEINC, www.coseinc.com/Vista_UIPI.ppt)

CSRSS Security

• CSRSS is a system process

• Only administrators can access it

• Administrators could modify the thread/process state with other methods (such as loading a driver or using the debugger)

• Check is done by comparing the kernel process pointer (EPROCESS) of the current process, with the saved CSRSS pointer -- impossible to fake

Exhibit A

• NtUserGetThreadState:

• Code has ASSERT(CurrentW32Thread->Desktop != NULL);

• Then dereferences Desktop to get the IME Thread ID.

• The developer knew of a risk, and validated it on debug builds... but can this happen?

Exhibit B• NtUserGetDCEx(HWND Window, HRGN

ClipRegion, ULONG Flags):

• Backwards compatibility: if no window handle given, get the desktop’s window handle

• Code blindly dereferences Win32ThreadInfo->Desktop to get the Desktop->Window

• Uses Window PWND when calling _GetDCEx

• All threads are part of a desktop

• Except CSRSS-owned threads

Assumption

• “but Microsoft owns that code, and it never calls NtUserGetThreadState or NtUserGetDCEx”

DoS Exploit

• hCsrss = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwCsrssId);

• CreateRemoteThread(hCsrss, NULL, 0, NtUserGetThreadState, 15, 0, NULL);

• This creates a new thread in CSRSS which will immediately execute NtUserGetThreadState with the thread state class which causes the dereference

• Can we do better?

From DoS to Escalation

• In Windows, we can allocate memory at “NULL” with NtAllocateVirtualMemory(Handle, 0x00000001, PAGE_SIZE - 1, ...);

• This means we can control what the kernel reads and writes

• Exploitable if kernel de-references something from the poisoned NULL pointer, then reads/writes to that value or worse -- executes!

Controlling Win32k• NtUserGetThreadState only reads a value from

the Desktop pointer -- useless to us

• However, NtUserGetDCEx dereferences a “Window” from the Desktop pointer.

• We can pwn the PWND ;-)

• No obvious modification of the Window structure was found on Server 2003 and higher

• However, the PWND is cached into the DC object

Controlling the PWND• Cached PWND kept so that the owner of the

DC can be requested later

• GDI sometimes builds WNDOBJs based on the owner

• Scope and size of code that deals with this corrupted PWND needs analysis

• Possibility exists that code could be coerced into ring privilege escalation behavior

• But Admin->Kernel escalation is only an attack against DRM

System Calls

Previous Mode

• How does a kernel system call know if this is the kernel closing the handle, or an application?

• Every system call updates the previous mode

• If user-mode performed the call, it’s set to UserMode (1)

• If Kernel-mode performed the call, it’s set to KernelMode (0)

System Calls• User-mode applications cannot call kernel

functions -- must use system call functionality

• Previous mode always updated

• Kernel-mode code can choose to call kernel function directly if exported (or if Microsoft code within the kernel binary)

• Previous mode not updated

• If kernel-mode code performs system call, previous mode is updated

Previous Mode Bugs• Stale previous mode -- driver failures

• Here, driver gets called from a user application (PM = 1), then directly performs a call to a kernel function (PM = 1) with kernel-mode pointers.

• Call will fail because pointers will be refused -- kernel will believe this is an unprivileged app attacking the kernel.

• Trusted previous mode on untrusted data -- danger

Previous Mode is Kernel• Previous mode is 0, but the driver is still

passing along the raw user data

• Kernel implicitly trusts caller, does not probe parameters

• Leads to code execution and privilege escalation

• Or, kernel performs certain sanity checks on the premise this is a kernel mode operation

• Leads to DoS -- kernel panics for safety

Protected Handle Close

• The Windows kernel manages resources as objects

• Processes, Threads, Files, Keys, Tokens, Events, Mutexes, Semaphores, Timers, ALPC Ports. 30 total!

• Object manager provides private header on top of each object

• Owner unaware and should not free object on its own -- Object Manager does garbage collection (prevents freeing invalid pointer)

Object Manager

Windows Kernel Objects

OBJECT_HEADER

Namespace Information

Quota Information

Security Information

Debug Information

Flags

Reference Count

Object Type

Object Body

Handle Manager

• Can’t export object addresses to user mode applications

• Pointers are only valid to the kernel

• Can’t always export object addresses to kernel mode drivers

• Structure for the object may be opaque

• Kernel provides handles to the objects instead

Handle Features

• Handles can be inherited from the parent

• Must be inheritable

• In Vista, a subset of these can be specified

• Handles can be duplicated

• Must have duplicate rights

• Handles can be protected from close

Handle to Object Mapping

Object

Object

Object

Handle Table

Entry 1

Entry 2

Entry 3

Entry 4

Entry 5

Object

Object

Application

SetEvent(0x4)

Handle to Object Mapping

Object

Object

Object

Handle Table

Entry 1

Entry 2

Entry 3

Entry 4

Entry 5

Object

Object

Application

SetEvent(0x14)

Handle Security• Each object has a security descriptor with

ACLs

• Each time a handle is created, an access mask is given

• So a process can only open a resource if it has access to it

• Handles are per-process (one handle table per process)

• One process cannot typically touch the handles of another

Handle Isolation

• Handles are isolated, but can be duplicated if process grants PROCESS_DUP_HANDLE to you

• Handles created by drivers are part of the kernel’s handle table

• < Vista, only administrators can access

• >= Vista, kernel is protected process, no one can access

Protect From Close

• Set with SetHandleInformation or NtSetInformationObject

• Used for protecting against accidental close of critical handles

• No ACL check done -- anyone can deprotect the handle

• So mostly a debugging/reliability feature -- not security

What Happens at Close

• Logic handled by ObpCloseHandleEntry

• Normal cases: return STATUS_HANDLE_NOT_CLOSABLE

• Process being debugged or FLG_ENABLE_CLOSE_EXCEPTIONS global flag is set or handle has debug information: RaiseException(STATUS_HANDLE_NOT_CLOSABLE)

What if Kernel Closes It?

• You would expect the operation to succeed anyway -- kernel is “god”

• But... remember this is a debugging/reliability feature

• So we’d probably want to know if a critical handle in our driver was closed...

• So what happens? Crash!KeBugCheckEx(INVALID_KERNEL_HANDLE)

Assumption• The kernel will never normally close

protected handles

• Microsoft code makes sure not to do this

• Drivers don’t usually use this functionality

• 3rd-party code would crash on developer’s machines anyway, and they would fix the error

• Again, assumption of controlled environment

• Can it happen?

Closing a Handle• CloseHandle and NtClose when called from

user-mode will set PM = 1.

• Kernel will not crash if handle is protected

• ZwClose when called from kernel-mode will set PM = 0

• But this means it’s a driver bug

• Can’t set protected bit on driver handles

• Driver handles are part of system handle table

Assumption Checks Out?• Are all kernel handles in the system handle

table?

• No! Kernel-mode code must explicitly set OBJ_KERNEL_HANDLE

• Otherwise, handle becomes part of the current process

• Current process can protect the handle...

• ... and wait for the kernel-mode code to free it

Scenario

• Find a handle that we can control, and wait for the kernel to close it.

• Or better yet, have some sort of function that can coerce the kernel to close the handle immediately.

• But all handle closing is done with CloseHandle

• False! Window Stations and Desktops are actually managed by the Object Manager, even if they are Win32k objects

• Cannot normally use CloseHandle on a window station or desktop handle

• Win32k blocks CloseHandle calls with the OkayToClose mechanism

• Provides CloseWindowStation and CloseDesktop APIs (NtUserCloseWindowStation/Desktop)

• NtUserCloseWindowStation is a simple wrapper around...

CloseWindowStation

• ZwClose!

• So all we have to do is

• Create a window station with CreateWindowStation

• Protect the handle with SetHandleInformation

• Close it with CloseWindowStation

• Bug was caught in Vista SP1 / Server 2008 timeframe

• Probably due to SDL -- obvious bug

Exploit

Exploit, Take Two

• There exists a second method to expose it, however

• Protect the current window station handle

• Create a new window station

• Switch to it with SetProcessWindowStation

• Why does this crash?

• When a console application starts, the Console API initializes and calls CSRSS, which calls NtUserConsoleControl with the ConsoleWindowStationProcess (6) type

• This calls PsSetProcessWin32WindowStation to cache the handle (used for global atom table)

• When switching to a new window station, xxxSetProcessWindowStation will check if the cached copy is stale and...

Window Station Caching

• You guessed it -- ZwClose on the cached handle

Developer Guidance

NULL Pointer Dereferences• Never blindly dereference a pointer

• Make sure nobody can call a function to dereference it after it has been deleted and/or freed

• Make sure nobody can call a function to dereference it before it has been initialized

• ASSERT is your friend, but isn’t perfect

• Do not write your code by basing your entire security on the caller’s context -- remote thread injection exists

System Calls• Never call Nt* system calls directly from a

driver (most are not exported anyway)

• Stale previous mode can lead to weird failures later

• Can also lead to security issues:

• User calls with buffer 0xF00

• You perform some unrelated operation with Zw*

• You now process 0xF00 with Nt*

System Calls

• Always call Zw*

• This makes sure the previous mode is never stale

• But never call with user-accessible or user-owned data or parameters

• Always probe and capture

Handles• Always create kernel handles with

OBJ_KERNEL_HANDLE

• Unless you want to share the handle with a trusted application

• Make sure the application and driver are secured against non privileged access

• Do not perform operations based on the data referenced by the handle

• Do not close the handle with a kernel mode Previous Mode

Thank You!

• Slides and PoC will be at http://www.alex-ionescu.com

• Email me at [email protected] for

• Rants

• Raves

• Flames

• Questions and Comments

Q & A