Loading...
Blogs & Stories

SpiderLabs Blog

Attracting more than a half-million annual readers, this is the security community's go-to destination for technical breakdowns of the latest threats, critical vulnerability disclosures and cutting-edge research.

Windows Debugging and Exploiting Part 4: NTQuerySystemInformation

Introduction

Hello again! We are back with more Windows internals and it's time to get real. We already covered how to set up an environment, WinDBG basics and discussed WinDBG Time Travel Debugging. In this part 4 of my blog series, I'll briefly describe an internal API that is widely used to leak kernel information for most of the Windows LPE (Local Privilege Escalation) exploits. We will talk about the function NTQuerySystemInformation.

NTQuerySystemInformation & System Information Classes

The function NTQuerySystemInformation is implemented on NTDLL. And as a kernel API, it is always being updated during the Windows versions with no short notice. As mentioned, this is a private function, so not officially documented by Microsoft. It has been used since early days from Windows NT-family systems with different syscall IDs as you can see on the table below [https://j00ru.vexillium.org/syscalls/nt/64/].

 

 Windows XP to Windows 7 

 Windows 8 & 2012  SP0 

 Windows 8.1 & 2012 R2 

 Windows 10 

 NTQuerySystemInformation 

0x0033

0x0034

0x0035

0x0036

The function basically retrieves specific information from the environment and its structure is very simple:

NtQuerySystemInformation(
      SYSTEM_INFORMATION_CLASS   SystemInformationClass,
      PVOID   SystemInformation,
      ULONG   SystemInformationLength,
      PULONG  ReturnLength);

In the first argument, SYSTEM_INFORMATION_CLASS (ULONG) we will set which information we want to retrieve. These classes are named Windows System Information Classes and are defined in winternl.h.

There are numerous data that can be retrieved using these classes along with the function. Information regarding the system, the processes, objects and others.

Below, the list of some classes that could be used:

Note:

  • late 5.0 starts with Windows 2000 SP4; 
  • late 5.1 starts with Windows XP SP2; 
  • very late 5.1 starts with Windows XP SP3; 
  • late 5.2 starts with Windows Server 2003 SP1; 
  • late 6.0 starts with Windows Vista SP1; 
  • late 6.1 starts with Windows 7 SP1.

 

 Numeric Value 

 Symbolic Name 

 Versions 

 Remarks 

 0x00 

 SystemBasicInformation

 3.10 and

 higher 

 

 0x01 

 SystemProcessorInformation

 3.10 and

 higher 

 

 0x02 

 SystemPerformanceInformation

 3.10 and

 higher 

 

 0x03 

 SystemTimeOfDayInformation

 3.10 and

 higher 

 

 0x04 

 SystemPathInformation

 3.10 and

 higher 

 

 0x05 

 SystemProcessInformation

 3.10 and

 higher 

 

 0x06 

 SystemCallCountInformation

 3.10 and

 higher 

 

 0x07 

 SystemDeviceInformation

 3.10 and

 higher 

 

 ...

 ...

 ...

...

 0x40 

 SystemExtendedHandleInformation

 5.1 and

 higher 

 

 0x41 

 SystemLostDelayedWriteInformation

 5.1 and

 higher 

 

 0x42 

 unknown 

 late 5.1

 only 

 

 SystemBigPoolInformation

 5.2 and

 higher 

 

 0x43 

 SystemSessionPoolTagInformation

 5.2 and

 higher 

 

 0x44 

 SystemSessionMappedViewInformation

 5.2 and

 higher 

 

 ...

 ...

 ...

 ...

 0x58 

 SystemProcessIdInformation

 6.0 and

 higher 

 

 0x59 

 SystemErrorPortInformation

 6.0 and

 higher 

 

 0x5A 

 SystemBootEnvironmentInformation

 6.0 and

 higher 

 

 0x5B 

 SystemHypervisorInformation

 6.0 and

 higher 

 

 0x5C 

 SystemVerifierInformationEx

 6.0 and

 higher 

 

 0x5D 

 SystemTimeZoneInformation

 6.0 and

 higher 

 

 0x5E 

 SystemImageFileExecutionOptionsInformation

 6.0 and

 higher 

 

 0x5F 

 SystemCoverageInformation

 6.0 and

 higher 

 

 0x60 

 SystemPrefetchPatchInformation

 6.0 and

 higher 

 

 ...

 ...

 ...

..

 0xA8 

 SystemAllowedCpuSetsInformation

 10.0 and

 higher 

 

 0xA9 

 SystemDmaProtectionInformation

 10.0 and

 higher 

 

 0xAA 

 SystemInterruptCpuSetsInformation

 10.0 and

 higher 

 

 0xAB 

 SystemSecureBootPolicyFullInformation

 10.0 and

 higher 

 

 0xAC 

 SystemCodeIntegrityPolicyFullInformation

 10.0 and

 higher 

 

 0xAD 

 SystemAffinitizedInterruptProcessorInformation

 10.0 and

 higher 

 

 0xAE 

 SystemRootSiloInformation

 10.0 and

 higher 

 

 ...

 ...

 ...

 ...

 0xC7 

 SystemCodeIntegrityVerificationInformation

 1803 and

 higher 

 

 0xC8 

 SystemFirmwarePartitionInformation

 1803 and

 higher 

 

 0xC9 

 SystemSpeculationControlInformation

 1803 and

 higher 

 

 0xCA 

 SystemDmaGuardPolicyInformation

 1803 and

 higher 

 

 0xCB 

 SystemEnclaveLaunchControlInformation

 1803 and

 higher

 

Source: https://www.geoffchappell.com/studies/windows/km/ntoskrnl/api/ex/sysinfo/class.htm?tx=65,67&ts=0,268

Usage

There are multiple information classes that we could use and part of the process, it is to discover which one will be useful in our exploitation method. If we need to discover an EPROCESS or a driver base address, for each one there is a specific class that we could implement. For every class, we will need to define its structures. Some samples:

SystemModuleInformation (0x0b)
typedef struct SYSTEM_MODULE {
        PVOID  Reserved1;
        PVOID  Reserved2;
        PVOID  ImageBase;
        ULONG  ImageSize;
        ULONG  Flags;
        USHORT Index;
        USHORT NameLength;
        USHORT LoadCount;
        USHORT PathLength;
        CHAR   ImageName[256];
}

typedef struct SYSTEM_MODULE_INFORMATION {
       ULONG                ModulesCount;
       SYSTEM_MODULE        Modules[0];

 

At SYSTEM_MODULE_INFORMATION->ModulesCount[i].ImageBase, you will find the base address of any kernel module. That could be used to calculate the HalDispatchTable for example, using the kernel base address. This table contains function pointers that could be overwritten during exploitation.

SystemHandleInformation (0x10)
typedef struct SYSTEM_HANDLE {
        ULONG ProcessId;
        UCHAR ObjectTypeNumber;
        UCHAR Flags;
        USHORT Handle;
        PVOID Object;
        ACCESS_MASK GrantedAccess;
}

typedef struct SYSTEM_HANDLE_INFORMATION
{
        ULONG HandleCount;
        SYSTEM_HANDLE Handles[1];
}

 

In this case, at SYSTEM_HANDLE_INFORMATION->Handles[i].Object you may find the address of the object in kernel space from a specific handle that could be filtered by the process ID for example (See Proof-Of-Concept).

These are only two examples of information classes that can be utilized on an exploitation, however there are much more useful classes like SystemExtendedHandledInformation, SystemLockInformation, SystemExtendedProcessInformation, etc.

It is valid to note, that all these structures are undocumented and thanks to the great work from researchers like Mateusz Jurcyzk, Alex Ionescu and others we now have this accurately described.

More information about information classes: https://j00ru.vexillium.org/papers/2011/address_protection.pdf

Proof-Of-Concept

I've developed a simple code to retrieve the open handle addresses from the running process using SystemHandleInformation. I tried to be as simple as possible for your education. So you may want to explore this and others information classes for discovering their functionality and identify what else can be done.

C:\>NTQuerySystemInformation-PoC1.exe
NTQuerySystemInformation() PoC -- Bruno Oliveira @mphx2
Address: 0xFFFFC90441603180, Object Type: 37, Handle: 4
Address: 0xFFFFC9043F8B7E60, Object Type: 16, Handle: 8
Address: 0xFFFFC9043F8B7F60, Object Type: 16, Handle: c
Address: 0xFFFFC90444662D50, Object Type: 36, Handle: 10
Address: 0xFFFFC90440581C40, Object Type: 35, Handle: 14
Address: 0xFFFFC90440096D70, Object Type: 30, Handle: 18
Address: 0xFFFFC90446352290, Object Type: 21, Handle: 1c
Address: 0xFFFFC904446633D0, Object Type: 36, Handle: 20
Address: 0xFFFFC90446353060, Object Type: 21, Handle: 24
Address: 0xFFFFC90444662EF0, Object Type: 36, Handle: 28
Address: 0xFFFFC9043FD7A0F0, Object Type: 50, Handle: 2c
Address: 0xFFFFC9043FDA1450, Object Type: 50, Handle: 30
Address: 0xFFFFC9043FDA0730, Object Type: 50, Handle: 34
Address: 0xFFFFA204CB57A840, Object Type: 3, Handle: 38
Address: 0xFFFFC9043F8B9EE0, Object Type: 16, Handle: 3c
Address: 0xFFFFC9043F8C0B60, Object Type: 16, Handle: 40
Address: 0xFFFFC90446A4EBD0, Object Type: 37, Handle: 44
Address: 0xFFFFC90446A4D140, Object Type: 37, Handle: 48
Address: 0xFFFFC9043FDA0E30, Object Type: 50, Handle: 4c
Address: 0xFFFFC90440074710, Object Type: 37, Handle: 50
Address: 0xFFFFC90440073C20, Object Type: 37, Handle: 54
Address: 0xFFFFC90440073C20, Object Type: 37, Handle: 58
Address: 0xFFFFC9043ED774F0, Object Type: 46, Handle: 5c
Address: 0xFFFFC9043FDA18B0, Object Type: 50, Handle: 60
Address: 0xFFFFC9043FDA1A70, Object Type: 50, Handle: 64
Address: 0xFFFFC9043FDA0810, Object Type: 50, Handle: 68
Address: 0xFFFFC9043FDA2B00, Object Type: 35, Handle: 6c
Address: 0xFFFFC90445354740, Object Type: 30, Handle: 70
Address: 0xFFFFC904463602C0, Object Type: 21, Handle: 74
Address: 0xFFFFC90444663090, Object Type: 36, Handle: 78
Address: 0xFFFFC904463603D0, Object Type: 21, Handle: 7c
Address: 0xFFFFC90444662460, Object Type: 36, Handle: 80
Address: 0xFFFFA204E5D57670, Object Type: 44, Handle: 84
Address: 0xFFFFA204E5D83E70, Object Type: 44, Handle: 8c

C:\>

PoC source-code available on: https://github.com/bmphx2/PoC-codes/blob/master/NTQuerySystemInformation-PoC.cpp

Checking the address on WinDBG:

lkd> !object 0xFFFFC90441603180
Object: ffffc90441603180 Type: (ffffc904384f8380) File
    ObjectHeader: ffffc90441603150 (new version)
    HandleCount: 2 PointerCount: 65536
    Directory Object: 00000000 Name: \Reference {ConDrv}

 

Exploitation

This information leak is extremely useful for bypassing the kernel randomization KASLR (Kernel Address Space Layout Randomization). Supposing we already have control in kernel with some write-what-where exploitation primitive, we need to know where exactly we should modify in order to elevate our privileges. By utilizing this API, we are now able to locate multiple objects on the kernel space and calculate offsets for any possible other that we might need. What makes this function very special, is the fact that it can be called by an unprivileged user. In other words, you don't need to be SYSTEM to request internal information from the OS. There are multiple exploits that take advantage of this fact for running. Browsing LPE exploits for Windows is easy to identify. Feel free to do some analysis on your own.

 

Curiosity

In 2017 and 2018, Google Project Zero found vulnerabilities on NTQuerySystemInformation function itself.

https://bugs.chromium.org/p/project-zero/issues/detail?id=1395

https://bugs.chromium.org/p/project-zero/issues/detail?id=1513

The vulnerabilities occur in some specific information classes and disclose more than they are supposed to do. The irony, a function that is well-known used as a resource for exploit developers, being vulnerable ¯\_(ツ)_/¯.

 

Conclusion

Once more I tried to bring some information to set a basic knowledge while discussing exploitation on Windows systems. At this time, I explained a little bit about this important function for leaking kernel space information using any unprivileged user, such data is fundamental for most of the LPE exploits, being inevitable to discuss while explaining the topic. 

Hopefully, we will start to get things more excited in each post! Again, if there is any doubt or anything that you want me to know, ping me and happy hacking!