Date post: | 13-Apr-2017 |
Category: |
Internet |
Upload: | defconrussia |
View: | 204 times |
Download: | 6 times |
Center of vulnerability research
Yurii Drozdov Liudmila Drozdova
DCG#7812
Saint-Petersburg
2016
WINDOWS 10 ANNIVERSARY UPDATE:
GDI HANDLE MANAGEMENT AND
VULNERABILITY EXPLOITATION
GDI HANDLE MANAGEMENT BEFORE WINDOWS
10 ANNIVERSARY UPDATE
• Win32k.sys contains gdi handle manager (win32kbase.sys for Windows 10),
functions with Hmg* prefix are responsible for handle management.
• HmgInsertObject inserts every gdi object (Bitmap, Brush, Font, Pen ….) into handle
table after allocation in kernel mode.
• Handle table is mapping to address space of every gui process. Pointer to mapped
table is located in the PEB.GdiSharedHandleTable field.
GDI HANDLE MANAGEMENT BEFORE WINDOWS
10 ANNIVERSARY UPDATE
Every object in handle table described by following structure
typedef struct {
PVOID64 pKernelAddress;
USHORT wProcessId;
USHORT wCount;
USHORT wUpper;
USHORT wType;
PVOID64 pUserAddress;
} GDICELL64;
So, we can get kernel address of gdi object from usermode.
OLD HMGINSERTOBJECT Every object must be added to handle table after creation. Handle table pointer saved in win32k variable gpentHmgr (its pointer is
located in PEB.GdiSharedHandleTable in usermode).
HmgInsertObject function inserts object into handle table and contains following code
HmgInsertObject(_BASEOBJECT *ObjectKernelAddress,
unsigned __int16 flags,
unsigned __int8 objtype) {
...
Handle = hGetFreeHandle(objtype);
ENTRYOBJ::vSetup(
(gpentHmgr + 24i64 * LOWORD(Handle)),
ObjectKernelAddress,
objtype,
flags,
LOWORD(Handle));
...
}
ENTRYOBJ::vSetup function is filling GDICELL64 structure with given parameters.
WHY DO WE NEED GDI KERNEL OBJECT
ADDRESS DURING EXPLOITATION?
• To make exploit more stable:
• 1) we can check if object was allocated on the right place after spray.
• 2) we can change memory layout as we want.
• Sometimes it is important part of exploitation.
• 1) We can change Bitmap (SURFOBJ) fields and gain arbitrary read and write when we
know its address.
• We can use gdi objects for exploitation even if we have vulnerability in different (not
win32k) system component.
• SURFOBJ is one of the popular ways to achieve privilege escalation, which is working
from Vista to 10.
WINDOWS 10 ANNIVERSARY UPDATE
• Gdi handle management was changed a lot after update of Windows 10.
• PEB.GdiSharedHandleTable doesn’t contain kernel addresses anymore.
• New handle management classes and functions were added in win32kbase.sys.
• This update was introduced for Windows 10 only, but other systems can be affected soon.
WIN32KBASE.SYS CHANGES
• New Hmg* functions were added. The most interesting – HmgPentryFromPobj, because it
references new class GdiHandleManager.
• New handle management classes were added – GdiHandleManager,
GdiHandleEntryDirectory, GdiHandleEntryTable, EntryDataLookupTable.
• HmgCreate creates and initializes handle table (like in old version).
• We can easily track all changes via HmgInserObject function.
OLD GDI.GDISHAREDHANDLETABLE CONTENT
NEW PEB.GDISHAREDHANDLETABLE CONTENT
GDI HANDLE MANAGEMENT IN WINDOWS 10
ANNIVERSARY UPDATE
STRUCTURES OF NEW GDI HANDLE MANAGER
struct GdiHandleManager {
DWORD64 unknown;
DWORD max_handle_count;
DWORD unknown;
GdiHandleEntryDirectory * Dir;
}
struct GdiHandleEntryDirectory {
BYTE busy_flag ;
BYTE unknown;
WORD TableCount ;
DWORD unknown1 ;
GdiHandleEntryTable * Tables[0x100] ;
DWORD MaxHandleCount ;
} ;
struct GdiHandleEntryTable {
GDICELL64 * SharedMem_or_CellData ;
DWORD MaxHandleCount ;
DWORD unknown1 ;
DWORD unknown2 ;
DWORD unknown3 ;
EntryDataLookupTable * GdiLookupTable ;
} ;
struct EntryDataLookupTable {
LookupEntryAddress *LookupTableData ;
DWORD MaxHandleCount ;
DWORD unknown1 ;
} ;
struct LookupEntryAddress {
LOOKUP_ENTRY *leaddress ;
} ;
struct LOOKUP_ENTRY {
DWORD64 unknown;
PVOID64 GdiObjectAddress;
}
WHAT PEB.GDISHAREDHANDLETABLE
CONTAINS?
• Handle entry size wasn’t changed, it is like old GDICELL64 size – 0x18
typedef struct {
PVOID64 pKernelAddress;
USHORT wProcessId;
USHORT wCount;
USHORT wUpper;
USHORT wType;
PVOID64 pUserAddress;
} GDICELL64;
• The main change – pKernelAddress contains value 0xffffffffff000000 | dword_index, where dword_index =
[zero_byte][unused_table_index][lookup_entry_address_index]|[lookup_entry_index]
• no kernel addresses anymore.
HOW TO GET GDI OBJECT ADDRESS BY HANDLE
(X64) ?
Before updates Windbg command looked like this (handle in this case - 0x3c05096a)
• dq poi(poi(win32kbase!gpentHmgr) + 0x18*(0x3c05096a & 0xffff))
After changes (handle in this case - 0x1f0509e)
• dq poi(poi(poi(poi(poi((poi(poi(win32kbase!gpHandleManager)+0x10) + 8 + 0*8)) +
0x18)) + ((0x1f0509ea & 0xffff) / 0x100) * 8) + (0x1f0509ea & 0xff)*0x10 + 8)
RESULT OF EXECUTION OF WINDBG COMMAND
ON UPDATED WINDOWS 10 SYSTEM
CHANGES SUMMARY
• Object metadata (pid, object type …) and object address were saved
together in GDICELL structure before update and both were mapped to
userspace.
• Now, only object metadata is mapping, kernel addresses are located in
kernel pool inaccessible from usermode.
LPE VULNERABILITIES EXPLOITATION AFTER
UPDATES
• All this changes made exploitation more difficult. But there are few possible solutions. Gdi
is good, but not only exploitation approach.
• We still have user objects (window, cursor, menu etc) and we can still get their addresses!
i.e. we can use user objects in some exploits instead of gdi objects.
• Theoretically we can still use gdi objects (SURFOBJ): we can try to predict location of
object via spray.
• We can find additional vulnerability which will allow us to get gdi object address (we have
few ideas, but need some time to check them).
LINKS
• https://www.blackhat.com/docs/us-16/materials/us-16-Weston-Windows-10-Mitigation-
Improvements.pdf
• http://cvr-data.blogspot.ru/