HomeVulnerabilityMaking Weak Drivers Exploitable With out {Hardware}

Making Weak Drivers Exploitable With out {Hardware}

1 Introduction

This text supplies a technical evaluation of what number of Home windows kernel mode drivers might be interacted with from person mode with out the {hardware} they had been developed for. This work was motivated by driver-oriented vulnerability analysis and the necessity to consider the exploitability of particular person findings, which steadily have an effect on code whose reachability is hardware-gated. The methodology offered right here ought to assist anybody decide whether or not a selected Home windows kernel mode driver vulnerability stays reachable – and thus doubtlessly exploitable – even within the absence of the {hardware} the driving force was developed for.

The reader is predicted to have fundamental Home windows driver data, particularly relating to system objects. The remainder of this text is written with the idea that the reader is already conversant in the ideas described within the introduction article: Anatomy of Entry: Home windows Gadget Objects from a Safety Perspective.

Identical to the introduction article, this useful resource will not be targeted on any particular bug class, however somewhat the assault floor and, to an extent, the Home windows Plug and Play structure.

All of the assessments demonstrated right here had been carried out on Home windows 11 23H2 (winver 10.0.22631.3007).

For extra such newest risk analysis and vulnerability advisory, please subscribe to Atos Cyber Defend blogs.

2 The offensive worth of kernel mode drivers

Along with the plain Native Privilege Escalation potential, susceptible drivers are sometimes abused in BYOVD assaults – a post-exploitation method leveraged by attackers to disrupt system defenses similar to EDR elements.

Two primary standards decide whether or not a driver vulnerability is a robust candidate for BYOVD assaults: 1. Exploitation permits significant disruption of an in any other case tamper-resistant security part. Examples embrace kernel-level vulnerabilities granting arbitrary reminiscence learn/write entry, arbitrary code execution, or arbitrary useful resource abuse (e.g., overwriting recordsdata, closing handles, or terminating processes). 2. Its exploitability is unbiased of uncommon system situations, such because the presence of particular {hardware}.

Though BYOVD-style assaults have been effectively documented for years, with quite a few public reviews and analysis papers on the subject (e.g. https://www.ndss-symposium.org/wp-content/uploads/2026-s1491-paper.pdf, https://blackpointcyber.com/weblog/qilin-ransomware-and-the-hidden-dangers-of-byovd/, https://www.sophos.com/en-us/weblog/itll-be-back-attackers-still-abusing-terminator-tool-and-variants), none of them particularly examines the function of hardware-gating in driver vulnerability reachability.

3 Gadget object creation and upkeep – widespread patterns

The evaluation supplied on this useful resource is structured round system objects, as a result of they’re essentially the most viable assault vector. Nevertheless, the strategies demonstrated right here virtually affect driver code reachability from userland normally, not simply by way of IRP.

The most typical obstacles in attacking a driver by way of its system object are: 1. The system object will not be created. 2. The driving force’s inside state doesn’t enable the train of the susceptible conduct regardless of the system object being accessible.

Each eventualities are quite common when coping with a tool driver deployed on a system with out the corresponding bodily {hardware}.

In the remainder of the article I’m usually referring to system stacks and system nodes. I’ve lined system stacks fairly broadly in my introduction article. Whereas a tool node and a tool stack will not be the identical factor, the phrases are sometimes used interchangeably, as a result of each system node has precisely one system stack.

3.1 Unconditional creation upon driver load

Many drivers, particularly non-PnP drivers, create their system objects both immediately from inside their DriverEntry operate, or from another operate that will get invoked within the direct name chain originating from DriverEntry.

Multidev_WDM demo driver exemplifies this sample. We are able to see the system creation invoked straight away in DriverEntry:

CDO creation invoked immediately from DriverEntry

The driving force additionally removes the system object by calling IoDeleteDevice, however that occurs solely when DriverUnload known as (when the driving force is being unloaded):

CDO cleanup from DriverUnload

Drivers constructed this manner might be interacted with after easy deployment consisting of simply two steps:

  1. Create the driving force’s service entry: sc.exe create SampleDrv kind= kernel begin= demand binPath= System32driversSampleDrv.sys

sc.exe create SampleDrv kind= kernel begin= demand binPath= System32driversSampleDrv.sys

  • Begin the service (driver will load): sc.exe begin SampleDrv

If we have a look at a randomly picked driver from https://loldrivers.io/, we’ll see that its deployment command matches this sample:

LOL drivers – zam64.sys deployment

However most system drivers don’t fall into this class, as we’ll see within the following sections of this text.

3.2 Conditional system creation and upkeep

Oftentimes driver initialization routines carry out extra checks. For instance, kernel mode elements of security software program (EDR, anti-virus, monitoring, enhanced authentication and so forth.) are inclined to examine for product-specific registry keys and entries, that are created and initialized throughout regular product deployment.

Precise system drivers (created to drive bodily {hardware}) are inclined to solely create their system objects within the presence of that {hardware}. With out it they both: – don’t try and create any system objects in any respect, – they take away any system objects shortly after their creation, by calling IoDeleteDevice.

Let’s give attention to how that logic is applied and consider whether or not and the way it may be labored round, particularly from the BYOVD perspective – by solely working from userland (with no bodily/hypervisor entry).

By the best way, the second situation, by which a tool object is first created after which deleted shortly after, creates a state of affairs that could possibly be thought-about a race situation, as a result of there’s a quick time window by which the system object exists.

3.3 PnP-specific callbacks as the principle location of PnP driver initialization logic

In PnP-compatible drivers (which make up most of system drivers), initialization logic extends past DriverEntry into the next PnP-specific routines: AddDevice and the IRP_MJ_PNP handler.

This part explores each of them and explains why most PnP-compatible drivers must be arrange in a approach that ensures these capabilities are known as if we wish to work together with the driving force.

3.3.1 AddDevice

All PnP-compatible drivers should outline this routine. It’s liable for creating useful system objects (FDO) and filter system objects (filter DO) for gadgets enumerated by the PnP supervisor. This explains why AddDevice is the place many of the initialization logic resides. That features: – creation of system objects (IoCreateDevice), – initialization of varied inside variables which might be later required to succeed in the susceptible code, – I/O queue administration in WDF (KMDF) drivers.

The MSDN web page about managing I/O queues in WDF drivers says: > Drivers sometimes name WdfIoQueueCreate from inside an EvtDriverDeviceAdd callback operate. The framework can start delivering I/O requests to the driving force after the driving force’s EvtDriverDeviceAdd callback operate returns.

Within the context of WDF (KMDF) drivers, AddDevice is known as EvtDriverDeviceAdd (totally different title, similar software).

AddDevice will not be known as from throughout the DriverEntry routine, which suggests it doesn’t mechanically execute upon driver load. As a substitute, the PnP supervisor invokes it solely after it discovers a brand new system node and determines that this driver ought to both management the system immediately or function a filter within the system stack.

Let us take a look at some code. Be aware: all structure-specific offsets are for the 64-bit structure.

Each in DriverEntry and in AddDevice, the primary parameter the operate receives is a pointer to the DRIVER_OBJECT construction. As we will learn on the MSDN web page, the construction is allotted by the I/O supervisor:

The I/O supervisor allocates the DRIVER_OBJECT construction and passes it as an enter parameter to a driver’s DriverEntry, AddDevice, and elective Reinitialize routines and to its Unload routine, if any.

DRIVER_OBJECT comprises tips to the driving force’s dispatch routines, every at a particular offset (e.g. 0xe0 for IRP_MJ_DEVICE_CONTROL).

The pointer to AddDevice, nonetheless, will not be saved immediately within the DRIVER_OBJECT construction, however within the DRIVER_EXTENSION construction, accessed by way of DriverObject->DriverExtension->AddDevice. This reality is talked about on the identical MSDN web page:

Pointer to the driving force extension. The one accessible member of the driving force extension is DriverExtension->AddDevice, into which a driver’s DriverEntry routine shops the driving force’s AddDevice routine.

So within the decompiler, the AddDevice task sometimes seems to be like:


// DriverObject->DriverExtension->AddDevice = SomeFunction;
*(*(param_1 + 0x30) + 8) = FUN_XXXXX;

So, a typical initialization sequence for driver dispatch routines and different commonplace callbacks we will normally discover in a tool driver’s DriverEntry operate seems to be like this (decompiled in Ghidra, feedback added manually):


*(code **)(param_1 + 0x70) = FUN_00011a08;  // IRP_MJ_CREATE dispatch routine
*(code **)(param_1 + 0x80) = FUN_00011a08;  // IRP_MJ_CLOSE dispatch routine
*(code **)(param_1 + 0xe0) = FUN_00010614; // IRP_MJ_DEVICE_CONTROL dispatch routine
*(code **)(param_1 + 0xe8) = FUN_000104ac; // IRP_MJ_INTERNAL_DEVICE_CONTROL
*(code **)(param_1 + 0x148) = FUN_00011c70; // IRP_MJ_PNP dispatch routine
*(code **)(param_1 + 0x120) = FUN_00011bc8; // IRP_MJ_POWER dispatch routine
*(code **)(*(longlong *)(param_1 + 0x30) + 8) = FUN_00011ad4; // AddDevice
*(code **)(param_1 + 0x68) = FUN_00011b8c; // DriverUnload

So, AddDevice is outlined in FUN_00011ad4 and upon driver load (DriverEntry execution) its pointer is written into DriverObject->DriverExtension->AddDevice, simply as all dispatch routine pointers are written into their related offsets. However none of these capabilities have been invoked but. For instance, FUN_00010614 (IRP_MJ_DEVICE_CONTROL) will solely execute as soon as the driving force receives an IRP with MajorFunction code = IRP_MJ_DEVICE_CONTROL (e.g. , in response to DeviceIoControl name from userland). Likewise, AddDevice will not be known as by the driving force itself, however somewhat by the PnP supervisor underneath particular circumstances.

Now, let’s look into FUN_00011ad4 and see how a typical AddDevice implementation seems to be like:


undefined8 FUN_00011ad4(undefined8 param_1,undefined8 param_2)
{
  longlong lVar1;
  longlong lVar2;
  undefined8 uVar3;
  undefined8 uVar4;
  undefined8 uVar5;
  undefined8 uVar6;
  longlong local_res18 [2];
 
  local_res18[0] = 0;
  lVar1 = *(longlong *)(DAT_00011880 + 0x40);
  uVar3 = IoCreateDevice(param_1,0x100,0,0x22,0,0,local_res18);
  if (-1 < (int)uVar3) {
    lVar2 = *(longlong *)(local_res18[0] + 0x40);
    *(undefined1 *)(lVar2 + 5) = 0;
    *(undefined1 *)(lVar2 + 4) = 0;
    *(undefined8 *)(lVar2 + 0x18) = 0;
    *(undefined8 *)(lVar2 + 0x10) = param_2;
    *(longlong *)(lVar2 + 8) = local_res18[0];
    *(undefined4 *)(lVar2 + 0x20) = 0x10000004;
    ExInterlockedInsertHeadList(lVar1,lVar2 + 0x28,lVar1 + 0x18);
    LOCK();
    *(int *)(lVar1 + 0x10) = *(int *)(lVar1 + 0x10) + 1;
    UNLOCK();
    KeInitializeEvent(lVar2 + 0x50,1);
    *(undefined4 *)(lVar2 + 0x68) = 1;
    *(uint *)(local_res18[0] + 0x30) = *(uint *)(local_res18[0] + 0x30) & 0xffffff7f;
    uVar3 = IoAttachDeviceToDeviceStack(local_res18[0],param_2);
    *(undefined8 *)(lVar2 + 0x18) = uVar3;
    uVar3 = 0;
    local_res18[0] = 0;
    RtlInitUnicodeString(&DAT_00011870,u_DeviceSampleDrv_00012270);
    uVar4 = IoCreateDevice(param_1,0x40,&DAT_00011870,0x22,0,0,local_res18);
    if (-1 < (int)uVar2) {
        RtlInitUnicodeString(&DAT_00011860,u_DosDevicesSampleDrv_000122a0);
        uVar5 = IoCreateSymbolicLink(&DAT_00011860,&DAT_00011870);
        uVar6 = (ulonglong)uVar5;
        if ((int)uVar5 < 0) {
            IoDeleteDevice(*(undefined8 *)(param_1 + 8));
        }
    }
  }
  return uVar3;
}

As we will see, two separate system objects are created. First, we now have the next name to IoCreateDevice, whose returned worth is saved in uVar3:


uVar3 = IoCreateDevice(param_1,0x100,0,0x22,0,0,local_res18);

The primary param – param_1 – is a pointer to the driving force object.

The second parameter is the requested system extension dimension (0x100) for the newly created system. Because the MSDN web page says: > The system extension is an important information construction related to a tool object. Its inside construction is driver-defined, and it is sometimes used to: > > Preserve system state info. > Present storage for any kernel-defined objects or different system sources, similar to spin locks, utilized by the driving force. > Maintain any information the driving force should have resident and in system house to hold out its I/O operations.

Gadget extension (particular person for each system object) will not be the identical factor as driver extension (offset 0x30 within the DRIVER_OBJECT) talked about earlier (the place AddDevice pointer, if current, is saved at offset 0x8). I’m emphasizing the distinction, as a result of each phrases sound comparable, which can create confusion. We’ll get again to the commonest software of the system extension construction later on this part.

The third parameter is the system title – on this case, empty (unnamed system object), which is typical for FDOs.

Trying additional, after FDO creation, we now have a complete block of code, which solely executes if system object creation was profitable:


if (-1 < (int)uVar3)) {

A number of directions additional in that block, we now have a name to IoAttachDeviceToStack:


uVar3 = IoAttachDeviceToDeviceStack(local_res18[0],param_2);

In AddDevice callback param_2 holds a pointer to the PDO created by the related bus driver.

Since AddDevice is invoked by the PnP supervisor, each parameters – param_1 pointing on the DRIVER_OBJECT and param_2 pointing on the PDO (DEVICE_OBJECT) – are supplied by the PnP supervisor.

So, at this level, we will clearly see that provided that AddDevice is invoked will the driving force create its FDO (and fix it to a tool stack, making it accessible for IRP processing by way of handles opened on the PDO).

Most PnP drivers solely create one system object (FDO) of their AddDevice, and fix that object to a tool stack, on high of the PDO pointed by param_2.

This explicit driver, nonetheless, additionally creates a CDO:


Var4 = IoCreateDevice(param_1,0x40,&DAT_00011870,0x22,0,0,local_res18);

Be aware that the third parameter will not be 0 (which suggests a tool title is supplied). And there’s no IoAttachDeviceToStack name on that system object. So the system object is called and standalone – typical CDO.

Each system objects are IRP entry factors, and this driver will solely create them when AddDevice known as.

This construction applies to all FDOs and filter DOs. On this explicit driver we even have a CDO created within the AddDevice callback.

Moreover, AddDevice is the place drivers initialize their customized inside constructions, together with those situated in system extension constructions. If we glance again into the AddDevice operate above, we now have such an instance proper to start with of the conditional code block, beginning with this line:


lVar2 = *(longlong *)(local_res18[0] + 0x40);

local_res18[0] holds a pointer to the system object created by the previous IoCreateDevice name. In a DEVICE_OBJECT, 0x40 is the offset of the system extension construction. So lVar2 factors on the system extension. Then, the following 7 directions carry out numerous initializations at arbitrary offsets of the system extension construction:


*(undefined1 *)(lVar2 + 5) = 0;
*(undefined1 *)(lVar2 + 4) = 0;
*(undefined8 *)(lVar2 + 0x18) = 0;
*(undefined8 *)(lVar2 + 0x10) = param_2;
*(longlong *)(lVar2 + 8) = local_res18[0];
*(undefined4 *)(lVar2 + 0x20) = 0x10000004;
ExInterlockedInsertHeadList(lVar1, lVar2 + 0x28, lVar1 + 0x18);

The contents of the system extension construction is how WDM drivers normally acknowledge (make distinction) between system objects used to ship the present IRP. It is sensible – in any case, the system extension is a construction contained in the system object, not the driving force object. So upon system object creation the driving force could put totally different values into particular person system extension fields, so later when a pointer to that system is acquired in param_1 by a dispatch routine, the routine can learn these values and use them in if situations. Oftentimes, susceptible code in dispatch routines sits behind such conditional blocks, making susceptible execution paths depend upon the precise system object used to ship the IRP.

Now it turns into clear why having AddDevice known as is essential:

  1. It’s required for the driving force to initialize correctly, which is oftentimes required for susceptible code to turn into reachable from userland. This contains each:

    1. In any other case-inaccessible conditional code branches.
    2. CDO creation (system object serving as entry level to the driving force).
  2. Extra importantly, the aim of AddDevice is to create a brand new PnP-compatible (unnamed FDO/FiDO) system object and fix it to the system stack on high of the PDO supplied by the PnPManager within the second argument ([in] _DEVICE_OBJECT *PhysicalDeviceObject). Which implies that AddDevice is the operate that connects the driving force (by way of its FDO/FiDO) to a newly created system stack, permitting IRP journey.
See also  Notepad++ Fixes Hijacked Replace Mechanism Used to Ship Focused Malware

For every driver, a number of unbiased interplay (assault) vectors could exist. Their activation is dependent upon correct driver initialization and sometimes materializes in one of many following varieties:

  1. CDOs created from throughout the AddDevice routine. Most PnP-compatible drivers don’t create CDOs, however some do.
  2. FDOs and FiDOs created inside AddDevice and hooked up on high of a newly created system stack. These gadgets can solely be accessed by way of the stack.

3.3.2 IRP_MJ_PNP

IRP_MJ_PNP is a MajorFunction IRP code devoted for PnP-related interactions. Every PnP-compatible driver should deal with this code with a devoted dispatch routine, sometimes called DispatchPnP.

Because the above MSDN web page reads: > Related to the IRP_MJ_PNP operate code are a number of minor I/O operate codes (see Plug and Play Minor IRPs), a few of which all drivers should deal with and a few of which might be optionally dealt with. The PnP supervisor makes use of these minor operate codes to direct drivers to begin, cease, and take away gadgets and to question drivers about their gadgets.

Whereas these routines will not be as crucial as AddDevice, as a result of they don’t seem to be liable for the creation of the PnP-type system object, they normally implement different common steps of driver initialization logic, similar to: – initialization of world driver-internal variables, – configuration file checks, – system interface registration, – {hardware} probing and validation.

It’s price maintaining in thoughts that there’s a distinction in how WDM and WDF drivers construction these callbacks of their code. WDM drivers set a conventional IRP_MJ_PNP dispatch routine on the DriverObject->MajorFunction desk. Any processing of PnP minor IRPs is dealt with in that routine. WDF (KMDF) drivers register PnP/energy state-change callbacks by way of WdfDeviceInitSetPnpPowerEventCallbacks, which supplies clear separation of capabilities devoted for dealing with particular person minor IRPs. These variations turn into related throughout static evaluation and debugging, however they don’t have an effect on they approach drivers are arrange from userland to get these routines correctly invoked.

3.4 Lively {hardware} interplay and probing

Solely a small fraction of driver code really interacts with bodily {hardware}.

The related direct and oblique interplay mechanisms embrace: – legacy x86 port I/O (https://study.microsoft.com/en-us/windows-hardware/drivers/ddi/wdm/nf-wdm-read_port_uchar, https://study.microsoft.com/en-us/windows-hardware/drivers/ddi/wdm/nf-wdm-write_port_uchar and associated IN/OUT instruction wrappers), – Reminiscence-Mapped I/O (https://study.microsoft.com/en-us/windows-hardware/drivers/ddi/wdm/nf-wdm-mmmapiospace, https://study.microsoft.com/en-us/windows-hardware/drivers/ddi/wdm/nf-wdm-read_register_ulong and variants), – PCI configuration house (https://study.microsoft.com/en-us/windows-hardware/drivers/ddi/ntddk/nf-ntddk-halgetbusdatabyoffset), – ACPI management strategies (https://study.microsoft.com/en-us/windows-hardware/drivers/ddi/acpiioct/ni-acpiioct-ioctl_acpi_eval_method), – Serial Peripheral Bus (https://study.microsoft.com/en-us/windows-hardware/drivers/spb/spb-ioctls and associated SPB I/O requests), – GPIO (https://study.microsoft.com/en-us/windows-hardware/drivers/ddi/gpio/ni-gpio-ioctl_gpio_read_pins), – DMA (https://study.microsoft.com/en-us/windows-hardware/drivers/ddi/wdm/nf-wdm-iogetdmaadapter), – interrupts (https://study.microsoft.com/en-us/windows-hardware/drivers/ddi/wdm/nf-wdm-ioconnectinterruptex), – calls to different drivers by way of https://study.microsoft.com/en-us/windows-hardware/drivers/ddi/wdm/nf-wdm-iofcalldriver.

When contemplating hardware-gated code and by extension hardware-gated vulnerabilities, it’s essential to grasp the context. As an example this, let’s take into account three totally different examples, all involving the identical mechanism – MMIO.

3.4.1 Impartial {hardware} use

Mounted handle 0xFEE00000, universally current:


// Native APIC — mounted at 0xFEE00000 on all x86 techniques
base = MmMapIoSpace(0xFEE00000, PAGE_SIZE, MmNonCached);
model = READ_REGISTER_ULONG(base + 0x30);
MmUnmapIoSpace(base, PAGE_SIZE);

No hardware-gating, no security affect.

3.4.2 Weak {hardware} use

On this situation, we now have an arbitrary bodily reminiscence write (susceptible use of MmMapIoSpace, adopted by WRITE_REGISTER_ULONG). It’s unconditionally reachable – any system working the driving force is uncovered:


// Bodily handle and offset equipped by usermode by way of IOCTL
base = MmMapIoSpace(input->PhysicalAddress, input->Measurement, MmNonCached);
WRITE_REGISTER_ULONG(base + input->Offset, input->Worth);
MmUnmapIoSpace(base, input->Measurement);

3.4.3 {Hardware} gating

And right here we even have an arbitrary bodily reminiscence write, however an attacker can solely attain it on machines the place the {hardware} chip ID examine passes. That is the {hardware} gate: the MmMapIoSpace on a non-existent BAR returns NULL or maps to nothing significant, and chipId will not match:


// BAR handle obtained from PCI config house of a particular system
base = MmMapIoSpace(barAddress, BAR_SIZE, MmNonCached);
chipId = READ_REGISTER_ULONG(base + CHIP_ID_REGISTER);

if (chipId == 0x1234ABCD) {
    WRITE_REGISTER_ULONG(base + input->Offset, input->Worth);
}
MmUnmapIoSpace(base, BAR_SIZE);

For extra such newest risk analysis and vulnerability advisory, please subscribe to Atos Cyber Defend blogs.

4 How driver deployment might be approached from the BYOVD perspective

On this part we’re going to attempt to consider how a lot affect over correct driver initialization is feasible by solely working from userland (with administrative privileges), to replicate a typical BYOVD situation.

So on this part we aren’t contemplating strategies involving: – bodily entry, – hypervisor degree entry permitting creation of virtualized {hardware}, – non-standard/insecure system configurations, similar to disabled driver signature enforcement, – synthetic alterations of execution movement utilizing kernel mode debugger, or another use of kernel mode debugger.

Whereas the above strategies are all fascinating and precious for security analysis and testing, they’re out of scope of this text.

4.1 Easy sc.exe deployment

That is the best, minimal step required to set off driver load. We create a related service entry, then we set off driver load by beginning that service:


sc create SampleDrv kind= kernel begin= demand binPath= System32driversSampleDrv.sys && sc.exe begin

Be aware, this deployment alone makes the driving force execute its DriverEntry, however doesn’t cowl any PnP setup. By way of named system creation, this setup strategy is ample for drivers matching the sample described in 3.1 Unconditional creation upon driver load.

Now, if we wish to check if the driving force created any named system objects, the best approach not involving WinDBG utilization is to:

  1. Use NtObjectManager to listing the Gadgets listing and save that listing.
  2. Deploy and begin the driving force (sc create + sc begin).
  3. Use NtObjectManager once more to listing the Gadgets listing and evaluate the outcome with the listing obtained in step 1.
  4. If a brand new system object was detected, attempt acquiring its SDDL.
  5. Profitable studying of SDDL proves it’s doable to open a deal with from userland, and solely these gadgets are reported.

A Powershell implementation might be discovered right here.

Let’s have a look at this script in motion.

First, that is what we will anticipate to see for a driver that masses, however doesn’t create any new gadgets:


PS C:check> .sc_deploy_detect.ps1 C:runtime_serviceIFM63X64.sys
Returning system listing (193 components).
[SC] CreateService SUCCESS

SERVICE_NAME: IFM63X64
        TYPE               : 1  KERNEL_DRIVER
        STATE              : 4  RUNNING
                                (STOPPABLE, NOT_PAUSABLE, IGNORES_SHUTDOWN)
        WIN32_EXIT_CODE    : 0  (0x0)
        SERVICE_EXIT_CODE  : 0  (0x0)
        CHECKPOINT         : 0x0
        WAIT_HINT          : 0x0
        PID                : 0
        FLAGS              :
Returning system listing (193 components).

We are able to see that the driving force was efficiently loaded, however the system listing didn’t change after that.

Now, right here is an instance of a driver that does create a brand new system straight away upon load:


PS C:check> .sc_deploy_detect.ps1 C:runtime_serviceKfeCo11x64.sys
Returning system listing (193 components).
[SC] CreateService SUCCESS

SERVICE_NAME: KfeCo11x64
        TYPE               : 1  KERNEL_DRIVER
        STATE              : 4  RUNNING
                                (STOPPABLE, NOT_PAUSABLE, IGNORES_SHUTDOWN)
        WIN32_EXIT_CODE    : 0  (0x0)
        SERVICE_EXIT_CODE  : 0  (0x0)
        CHECKPOINT         : 0x0
        WAIT_HINT          : 0x0
        PID                : 0
        FLAGS              :
Returning system listing (194 components).
New system discovered for
 DeviceKfeCoDriver (symlink: ) O:BAG:SYD:P(A;;FA;;;SY)(A;;FA;;;BA)

This deployment and system detection strategy is quick and sensible for runtime discovery of drivers that create userland-accessible CDOs out of the field.

Nevertheless, it isn’t ample for PnP system objects, that are way more widespread and thus represent a a lot bigger assault floor.

Additionally, remember the fact that many drivers deployed this manner will fail to load on account of lacking dependencies. These are normally glad when the deployment is carried out utilizing the unique installer and INF file.

4.2 Creating software-emulated gadgets with spoofed {hardware} ID

4.2.1 The thought

After digging a bit and studying extra in regards to the driver deployment course of, I stumbled upon the check system performance supplied by devcon.exe, which supplies the flexibility to create system nodes with arbitrary (spoofed) {hardware} IDs.

So it turned clear to me that these gadgets could possibly be used to compensate for the lacking {hardware} and get the AddDevice callback invoked.

Most system drivers include INF recordsdata, which tie drivers to bodily {hardware} by {hardware} IDs.

The simplest method to determine {hardware} ID (or IDs) matching a driver is by viewing its INF file. {Hardware} IDs are situated within the Fashions sections, for instance:

Here’s a Python implementation extracting {hardware} IDs from INF recordsdata.


[SampleDrv.NTamd64]

%SampleDrv.DeviceDesc% = SampleDrv,ACPISAMPLEDRV7853

As soon as we now have an identical {hardware} ID, as a substitute of explicitly calling sc.exe, we deploy the driving force as follows:


pnputil.exe /add-driver SampleDrv.inf /set up
devcon.exe set up SampleDrv.inf "ACPISAMPLEDRV7853"

First, we use pnputil to deploy the driving force package deal into the Home windows Driver Retailer.

Subsequent, we use devcon to create a brand new software-emulated system node with an arbitrary {hardware} ID that matches one outlined within the driver’s INF file. This motion triggers the PnP supervisor to detect the newly staged driver as the very best match for the system.

In consequence, the driving force’s AddDevice routine will get executed.

Whereas pnputil.exe is current on each Home windows system, devcon.exe will not be, however it may be present in WDK.

The algorithm of detecting new named system objects on account of this deployment strategy is identical, apart from the deployment instructions.

The devcon model of the deploy and detect PowerShell script might be discovered right here.

The output generated by this script seems to be the identical as for the sc.exe model.

4.2.2 Preliminary check outcomes

My preliminary experiments with this deployment strategy resulted in virtually twice as many new system objects created as in comparison with the easy sc.exe create, non-PnP deployment. This clearly demonstrates that software-emulated system nodes with spoofed {hardware} IDs are a viable userland-only technique of creating (some) drivers reachable with out their related {hardware}. I used to be capable of finding and make sure quite a few driver vulnerabilities this manner, together with excellent BYOVD candidates.

It is very important observe that the algorithm used to detect new named system objects contains each CDOs in addition to FDOs hooked up on high of the software-emulated PDO with an auto-generated title.

Within the screenshot under, demonstrating a fraction of the aggregated outcome log, we will see one CDO and one PDO (with auto-generated title) created by the identical driver, each with readable security descriptors:

New named gadgets created throughout devcon set up

For visibility, the log file additionally contains newly found system objects whose SDDLs couldn’t be obtained. These make up the bulk.

And right here we will see 3 PDOs with auto-generated names, whose security descriptors are readable (the extra column is the GLOBAL?? symlink title, on this case mechanically created with system interface registration):

New named gadgets created throughout devcon set up

So, an apparent query arises: Why had been the security descriptors of so many system objects created throughout this check not readable?

And secondly, what are we actually doing when working “devcon.exe set up path_to.inf HWID”?

To reply these questions, let’s have a more in-depth have a look at the method of software-emulated system creation.

4.2.3 Creating software-emulated gadgets with SoftwareDevice and PnpManager

Understand that making a software-emulated system and telling Home windows to make use of a particular driver to drive that system are two separate steps: 1. First, we create a software-emulated system with a spoofed {hardware} ID. 2. Then we invoke the driving force set up/replace course of for that system utilizing the unique INF file (UpdateDriverForPlugAndPlayDevicesW), to ultimately run the driving force on the emulated system.

With regards to step one, the Home windows kernel itself supplies two comparable mechanisms permitting creation of software-emulated gadgets with arbitrary {hardware} IDs:

  1. The primary technique is supplied by the PnPManager driver itself, and it may be carried out through the use of Config Supervisor API/SetupAPI. That is how devcon.exe implements its software-emulated system creation.
  2. The second is supplied by the SoftwareDevice driver, utilizing Software program Gadget API.

Each drivers are embedded in ntoskrnl.exe. In each circumstances we’re creating PnP system nodes with arbitrary {hardware} IDs.

Let’s have a more in-depth look into this course of.

4.2.3.1 SetupAPI and PnpManager – course of overview

Organising a software-emulated system utilizing SetupAPI requires the next sequence of API calls:

  1. SetupDiCreateDeviceInfoList – create an empty system data set for our class.
  2. SetupDiCreateDeviceInfoW – create system node.
  3. SetupDiSetDeviceRegistryPropertyW – set the {hardware} ID on the devnode.
  4. SetupDiCallClasInstaller – register the system with PnP.
  5. UpdateDriverForPlugAndPlayDevicesW – pressure driver replace for supplied HWID, utilizing supplied INF file.

Calling SetupDiCallClassInstaller (step 4) triggers a sequence of operations on the kernel degree, together with a name to IoCreateDevice (PnpManager creating the brand new system object).

UpdateDriverForPlugAndPlayDevicesW requests the PnP supervisor to put in a driver for that system. Earlier than that occurs, the system will present DOE_START_PENDING in its extension flags, when inspected with !devobj in WinDBG:


0: kd> !devobj Gadget000003b
...
ExtensionFlags (0x00000810)  DOE_START_PENDING, DOE_DEFAULT_SD_PRESENT
...

As soon as the driving force is sure to the system, the goal driver’s AddDevice will likely be invoked by PnpManager, passing a pointer to the PDO (owned by PnpManager) because the second argument. AddDevice is predicted to create its FDO and fix it on high of the PDO utilizing IoAttachDeviceToDeviceStack.

4.2.3.2 SetupAPI and PnpManager – system node creation solely

Let’s use the next C implementation of steps 1-4, to solely create a brand new system node with an arbitrary {hardware} ID, then examine the system node in Gadget Supervisor and examine its named system object in WinDBG.

This fashion we will skip utilizing an INF file totally (for now) and study the newly created named system object in its default state, with out the PnP supervisor making any makes an attempt to construct a tool stack on high of it.


create_swdev_cm.exe FAKEHW_ID
Gadget node created efficiently for {hardware} ID: FAKEHW_ID

We should always be capable to see the brand new system node (as “Unknown”) in Software program Gadgets within the Gadget Supervisor view.

We are able to manually choose and examine totally different system node properties, similar to system occasion path, {hardware} ID and even PDO title:

Gadget supervisor view – occasion path
Gadget supervisor view – {hardware} ID
Gadget supervisor view – Bodily Gadget Object title

Let’s examine the PDO title in WinDBG:


0: kd> !devobj Gadget0000036
Gadget object (ffff8207ddc03300) is for:
 00000036 DriverPnpManager DriverObject ffff8207d8aa3290
Present Irp 00000000 RefCount 0 Kind 00000004 Flags 00001040
SecurityDescriptor ffffd408ceb1d260 DevExt ffff8207ddc03450 DevObjExt ffff8207ddc03458 DevNode ffff8207deca0660
ExtensionFlags (0x00000800)  DOE_DEFAULT_SD_PRESENT
Traits (0x00000080)  FILE_AUTOGENERATED_DEVICE_NAME
Gadget queue will not be busy.

We are able to see that the driving force proudly owning the system object is DriverPnpManager, the system object has an auto-generated title and a default (permissive) security descriptor. Additionally observe that the system object is NOT hooked up to any system stack right here (there is no such thing as a AttachedDevice and so forth.), so we will rule out a filter blocking entry to it from above.

See also  Google Patches 120 Flaws, Together with Two Zero-Days Beneath Attack

Inspecting the security descriptor in WinDBG confirms the default, permissive security descriptor:


0: kd> !sd ffffd408ceb1d260
->Revision: 0x1
->Sbz1    : 0x0
->Management : 0x8814
            SE_DACL_PRESENT
            SE_SACL_PRESENT
            SE_SACL_AUTO_INHERITED
            SE_SELF_RELATIVE
->Proprietor   : S-1-5-32-544
->Group   : S-1-5-21-557163823-2925933541-2346282345-513
->Dacl    :
->Dacl    : ->AclRevision: 0x2
->Dacl    : ->Sbz1       : 0x0
->Dacl    : ->AclSize    : 0x5c
->Dacl    : ->AceCount   : 0x4
->Dacl    : ->Sbz2       : 0x0
->Dacl    : ->Ace[0]: ->AceType: ACCESS_ALLOWED_ACE_TYPE
->Dacl    : ->Ace[0]: ->AceFlags: 0x0
->Dacl    : ->Ace[0]: ->AceSize: 0x14
->Dacl    : ->Ace[0]: ->Masks : 0x001201bf
->Dacl    : ->Ace[0]: ->SID: S-1-1-0

->Dacl    : ->Ace[1]: ->AceType: ACCESS_ALLOWED_ACE_TYPE
->Dacl    : ->Ace[1]: ->AceFlags: 0x0
->Dacl    : ->Ace[1]: ->AceSize: 0x14
->Dacl    : ->Ace[1]: ->Masks : 0x001f01ff
->Dacl    : ->Ace[1]: ->SID: S-1-5-18

->Dacl    : ->Ace[2]: ->AceType: ACCESS_ALLOWED_ACE_TYPE
->Dacl    : ->Ace[2]: ->AceFlags: 0x0
->Dacl    : ->Ace[2]: ->AceSize: 0x18
->Dacl    : ->Ace[2]: ->Masks : 0x001f01ff
->Dacl    : ->Ace[2]: ->SID: S-1-5-32-544

->Dacl    : ->Ace[3]: ->AceType: ACCESS_ALLOWED_ACE_TYPE
->Dacl    : ->Ace[3]: ->AceFlags: 0x0
->Dacl    : ->Ace[3]: ->AceSize: 0x14
->Dacl    : ->Ace[3]: ->Masks : 0x001200a9
->Dacl    : ->Ace[3]: ->SID: S-1-5-12

->Sacl    :
->Sacl    : ->AclRevision: 0x2
->Sacl    : ->Sbz1       : 0x0
->Sacl    : ->AclSize    : 0x1c
->Sacl    : ->AceCount   : 0x1
->Sacl    : ->Sbz2       : 0x0
->Sacl    : ->Ace[0]: ->AceType: SYSTEM_MANDATORY_LABEL_ACE_TYPE
->Sacl    : ->Ace[0]: ->AceFlags: 0x0
->Sacl    : ->Ace[0]: ->AceSize: 0x14
->Sacl    : ->Ace[0]: ->Masks : 0x00000001
->Sacl    : ->Ace[0]: ->SID: S-1-16-4096

However after we attempt to show the security descriptor with NtObjectManager, we’ll encounter the next error message:

Failure making an attempt to learn SDDL of unattached PDO

The requested operation will not be legitimate for the goal system?

Within the introduction article, in part 3.6.7 Filters as entry management, I demonstrated the same state of affairs, solely with Entry denied. In that case the higher driver within the stack was blocking IRP_MJ_CREATE, so the IRP by no means even reached the named PDO down the stack (the one used to open the deal with).

Since right here we solely have one system object as a substitute of a tool stack, it should be PnpManager itself blocking these requests.

Let’s take a look at its dispatch routine desk:


0: kd> !drvobj PnpManager 2
Driver object (ffff8207d8aa3290) is for:
 DriverPnpManager
...
Dispatch routines:
[00] IRP_MJ_CREATE                      fffff8053ff516b0        nt!IopInvalidDeviceRequest
[01] IRP_MJ_CREATE_NAMED_PIPE           fffff8053ff516b0        nt!IopInvalidDeviceRequest
[02] IRP_MJ_CLOSE                       fffff8053ff516b0        nt!IopInvalidDeviceRequest
[03] IRP_MJ_READ                        fffff8053ff516b0        nt!IopInvalidDeviceRequest
[04] IRP_MJ_WRITE                       fffff8053ff516b0        nt!IopInvalidDeviceRequest
[05] IRP_MJ_QUERY_INFORMATION           fffff8053ff516b0        nt!IopInvalidDeviceRequest
[06] IRP_MJ_SET_INFORMATION             fffff8053ff516b0        nt!IopInvalidDeviceRequest
[07] IRP_MJ_QUERY_EA                    fffff8053ff516b0        nt!IopInvalidDeviceRequest
[08] IRP_MJ_SET_EA                      fffff8053ff516b0        nt!IopInvalidDeviceRequest
[09] IRP_MJ_FLUSH_BUFFERS               fffff8053ff516b0        nt!IopInvalidDeviceRequest
[0a] IRP_MJ_QUERY_VOLUME_INFORMATION    fffff8053ff516b0        nt!IopInvalidDeviceRequest
[0b] IRP_MJ_SET_VOLUME_INFORMATION      fffff8053ff516b0        nt!IopInvalidDeviceRequest
[0c] IRP_MJ_DIRECTORY_CONTROL           fffff8053ff516b0        nt!IopInvalidDeviceRequest
[0d] IRP_MJ_FILE_SYSTEM_CONTROL         fffff8053ff516b0        nt!IopInvalidDeviceRequest
[0e] IRP_MJ_DEVICE_CONTROL              fffff8053ff516b0        nt!IopInvalidDeviceRequest
[0f] IRP_MJ_INTERNAL_DEVICE_CONTROL     fffff8053ff516b0        nt!IopInvalidDeviceRequest
[10] IRP_MJ_SHUTDOWN                    fffff8053ff516b0        nt!IopInvalidDeviceRequest
[11] IRP_MJ_LOCK_CONTROL                fffff8053ff516b0        nt!IopInvalidDeviceRequest
[12] IRP_MJ_CLEANUP                     fffff8053ff516b0        nt!IopInvalidDeviceRequest
[13] IRP_MJ_CREATE_MAILSLOT             fffff8053ff516b0        nt!IopInvalidDeviceRequest
[14] IRP_MJ_QUERY_SECURITY              fffff8053ff516b0        nt!IopInvalidDeviceRequest
[15] IRP_MJ_SET_SECURITY                fffff8053ff516b0        nt!IopInvalidDeviceRequest
[16] IRP_MJ_POWER                       fffff8054015fa10        nt!IopPowerDispatch
[17] IRP_MJ_SYSTEM_CONTROL              fffff80540561f30        nt!IopSystemControlDispatch
[18] IRP_MJ_DEVICE_CHANGE               fffff8053ff516b0        nt!IopInvalidDeviceRequest
[19] IRP_MJ_QUERY_QUOTA                 fffff8053ff516b0        nt!IopInvalidDeviceRequest
[1a] IRP_MJ_SET_QUOTA                   fffff8053ff516b0        nt!IopInvalidDeviceRequest
[1b] IRP_MJ_PNP                         fffff805402c6940        nt!IopPnPDispatch

Aha! The dispatch routine values for many MajorFunction codes are set to nt!IopInvalidDeviceRequest.

Which implies that the driving force merely doesn’t assist them.

With out IRP_MJ_CREATE we can not open a deal with, even to learn the security descriptor. Within the case described within the introduction article (part 3.6.7 Filters as entry management), the higher driver known as IofCompleteRequest, with Irp->IoStatus.Standing = STATUS_ACCESS_DENIED.

On this case, IRP_MJ_CREATE returns Irp->IoStatus.Standing = STATUS_INVALID_DEVICE_REQUEST.

The rationale that is occurring is as a result of the driving force proudly owning the PDO is solely not supposed to be liable for dealing with IRP_MJ_CREATE requests. In typical system stacks, the dealing with of IRP_MJ_CREATE ought to happen within the FDO and finish there (with IofCompleteRequest), with IRP_MJ_CREATE by no means being handed down the stack.

Which leads us to an necessary conclusion – if we are attempting to open a deal with to a tool stack, not less than one system in that stack should efficiently deal with our IRP_MJ_CREATE.

We can not open a deal with to a tool stack if neither of the next accepts IRP_MJ_CREATE:

  1. Higher FiDO (if current).
  2. FDO.
  3. Decrease FiDO (if current).
  4. The PDO (if IRP ever reaches right here). PDO is at all times the bottom of a tool stack, so it is at all times current.

For this reason we can not open a deal with to a naked (non-stack-attached) named PDO created by PnpManager.

A big portion of the failed deployment makes an attempt noticed within the aggegated log – the place no security descriptors could possibly be obtained for the newly created gadgets – was attributable to the shortage of IRP_MJ_CREATE assist within the PnP Supervisor, mixed with the absence of an upper-level driver within the system stack to deal with that IRP.

Which is what occurred when: – UpdateDriverForPlugAndPlayDevicesW succeeded, however the goal driver didn’t assist IRP_MJ_CREATE both, – UpdateDriverForPlugAndPlayDevicesW failed for any motive (.cat file lacking, different dependancy referred within the INF file lacking, and even the driving force not loading).

4.2.3.3 SetupAPI and PnpManager – full and profitable deployment

Now, for distinction, let’s have a look at how a full (steps 1-5) and profitable deployment seems to be like, utilizing the Powershell script.

We’ll use AwinicSmartKAmps.sys (I2C good amplifier controller) driver for example.

First, let’s take a look at its INF file.

On line 32 we will discover the {hardware} ID – ACPIAWDZ8399.

Additionally it is price noting that on line 50 the “AddService” directive defines the driving force’s service title as AwinicChip.

That is how the driving force object will likely be named, although the .sys file itself is called AwinicSmartKAmps.sys (as seen on line 58):

{Hardware} ID from INF file

We run the deployment script:

{Hardware} ID from INF file

Fascinating – two new named system objects had been detected, and they’re each userland-accessible (SDDLs could possibly be retrieved)!

Let’s examine the driving force object in WinDBG:


!drvobj AwinicChip 7
Driver object (ffffe18f33ff3e10) is for:
 DriverAwinicChip

Driver Extension Listing: (id , addr)
(fffff805394622e0 ffffe18f2ec1a950)
Gadget Object listing:
ffffe18f32ce6de0

DriverEntry:   fffff80562ba0630 AwinicSmartKAmps
DriverStartIo: 00000000
DriverUnload:  fffff80562ba07c0 AwinicSmartKAmps
AddDevice:     fffff80539462090

Dispatch routines:
[00] IRP_MJ_CREATE                      fffff80539427ac0        +0xfffff80539427ac0
...
Gadget Object stacks:

!devstack ffffe18f32ce6de0 :
  !DevObj           !DrvObj            !DevExt           ObjectName
  ffffe18f34e51e00  Driverksthunk    ffffe18f34e51f50  0000002e
> ffffe18f32ce6de0  DriverAwinicChip ffffe18f35cde310
  ffffe18f35b0db90  DriverPnpManager ffffe18f35b0dce0  0000002d
!DevNode ffffe18f32f32b20 :
  DeviceInst is "ROOTMEDIA000"
  ServiceName is "AwinicChip"

We are able to see that our driver created one system object (ffffe18f32ce6de0), which was then hooked up into a tool stack on high of Gadget000002d (software-emulated PDO created by PnpManager), and moreover to that, the PnP supervisor additionally hooked up one other (additionally named) system object on high of it – Gadget000002e (owned by Driverksthunk).

If we glance firstly of the INF file, we’ll discover this:

{Hardware} ID from INF file

The driving force class is outlined as Multimedia, utilizing the well-known {4d36e96c-e325-11ce-bfc1-08002be10318} GUID.

ksthunk (Kernel Streaming) is registered as a category higher filter for the MEDIA system setup class.

This may be confirmed by inspecting the UpperFilters REG_MULTI_SZ registry entry at HKLMSYSTEMCurrentControlSetControlClass{4d36e96c-e325-11ce-bfc1-08002be10318}:

{Hardware} ID from INF file

The PnP supervisor mechanically attaches class higher filter system objects to each system within the class it’s arrange for. That is why Gadget000002e owned by Driverksthunk is current within the system stack on high of our driver’s unnamed FDO.

We’ll revisit the UpperFilters mechanism later on this article.

One other consequence of the driving force being put in as a Media system is how its system node is seen within the Gadget Supervisor GUI device. It seems within the “Sound, video and sport controllers” subtree:

{Hardware} ID from INF file
{Hardware} ID from INF file

Earlier than we transfer on, whereas we have already got the driving force loaded, let’s arrange a few breakpoints:


0: kd> bp fffff80539462090 ".echo AddDevice known as;g"
0: kd> bp fffff80539427ac0 ".echo IRP_MJ_CREATE known as;g"
0: kd> g

We already know these addresses from the output of !drvobj AwinicChip 7.

Now, IRP_MJ_CREATE ought to hit at any time when we try and open a deal with to any system within the stack:

Invoking IRP_MJ_CREATE

Within the debugger output we must always see:


IRP_MJ_CREATE known as
IRP_MJ_CREATE known as

And if we manually invoke the creation of one other system node utilizing the identical {hardware} ID (by merely working devcon.exe set up AwinicSmartKAmps.inf “ACPIAWDZ8399” once more), we must always see the AddDevice breakpoint hitting as effectively:


AddDevice known as

Understand that AddDevice being invoked solely implies that we now have managed to trick the PnP supervisor to name it. It doesn’t neccessarily imply that AddDevice will efficiently create a brand new system object and fix it to the the system stack – it might nonetheless fail internally on account of extra unmet situations.

From the sensible perspective, the best method to verify the success of the sort of deployment, is studying the security descriptor of the software-emulated system. If that works, it implies that: – driver set up (UpdateDriverForPlugAndPlayDevicesW name) was profitable, – within the newly created system stack there’s a driver that accepts IRP_MJ_CREATE.

Right here is the complete model the setup program (steps 1-5). Requires INF file.

4.2.3.4 Software program Gadget API

A substitute for the SetupAPI system creation strategy is Software program Gadget API.

Creation of a software-emulated system with arbitrary {hardware} ID is easier than with SetupAPI, because it boils down to simply calling SwDeviceCreate.

A pattern C implementation might be discovered right here. It may be simply prolonged with UpdateDriverForPlugAndPlayDevicesW (requires INF file).

By default the system object will get eliminated after we shut the HSWDEVICE hSwDevice deal with (the deal with populated by SwDeviceCreate). To forestall that, earlier than closing the deal with, this system calls hr = SwDeviceSetLifetime(hSwDevice, SWDeviceLifetimeParentPresent);.

Gadget objects created this manner are owned by DriverSoftwareDevice (as a reminder, those created with SetupAPI are owned by DriverPnpManager).

{Hardware} ID spoofed with SoftwareDevice API
{Hardware} ID spoofed with SoftwareDevice API

A fast inspection of the system object is WinDBG:


0: kd> !devobj Gadget0000036
0: kd> Gadget object (ffffaa0a87a6de00) is for:
 00000036 DriverSoftwareDevice DriverObject ffffaa0a8273ce00
Present Irp 00000000 RefCount 0 Kind 00000022 Flags 00001040
SecurityDescriptor ffffce8086380820 DevExt ffffaa0a87a6df50 DevObjExt ffffaa0a87a6df60 DevNode ffffaa0a86a1a8e0
ExtensionFlags (0x00000800)  DOE_DEFAULT_SD_PRESENT
Traits (0x00000180)  FILE_AUTOGENERATED_DEVICE_NAME, FILE_DEVICE_SECURE_OPEN
AttachedDevice (Higher) ffffaa0a88033de0 DriverAwinicChip
Gadget queue will not be busy.

And identical to DriverPnpManager, the DriverSoftwareDevice driver doesn’t assist IRP_MJ_CREATE:


0: kd> !drvobj SoftwareDevice 2

Driver object (ffffaa0a8273ce00) is for:
 DriverSoftwareDevice

DriverEntry:   fffff8074ad32f40 nt!PiSwPdoDriverEntry
DriverStartIo: 00000000
DriverUnload:  00000000
AddDevice:     fffff8074a9e4400 nt!ArbPreprocessEntry

Dispatch routines:
[00] IRP_MJ_CREATE                      fffff8074a5516b0        nt!IopInvalidDeviceRequest

4.3 Leaping system stacks

Making a PnP-compatible driver reachable with a software-emulated system is an instance of constructing and accessing a customized system stack.

That opens the best way to even work together by way of IRP with drivers that had been by no means supposed for userland interplay (e.g. not checking IRP’s RequestorMode previous to additional processing), as a result of when deployed the unique approach they reside in system stacks the place an higher driver prevents userland entry (by denying or not supporting IRP_MJ_CREATE), identical to within the instance demonstrated in part 3.6.7 Filters as entry management within the introduction article.

So, if we discover a vulnerability in a driver that can not be interacted with from userland in its unique configuration, that driver will not be helpful for Native Privilege Escalation. However for breaking the admin to kernel boundary it’d. We simply have to deploy it in a approach that enables exploitability, by inserting it in a tool stack the place the unique higher filter will not be current. We might name this malicious driver misconfiguration/deployment.

This strategy will not be solely helpful for testing, but in addition for making vulnerabilities reachable, and thus doubtlessly exploitable throughout BYOVD assaults.

Let’s have a look at one other variant of this.

4.3.1 Filter restacking

As soon as we perceive that with the intention to entry a tool stack, one in every of its drivers should settle for our IRP_MJ_CREATE, it turns into clear why the deployment situation lined in part 4.3 couldn’t succeed for filter drivers.

A typical filter driver is a pass-through IRP forwarder, which suggests it doesn’t reject IRP_MJ_CREATE, but it surely doesn’t settle for it both. It does have the related dispatch routine, and that routine normally simply forwards IRPs down the stack.

So, if we attempt to entry a filter driver by placing it on high of a software-emulated PDO, we cannot be capable to open a deal with.

That’s as a result of neither of the 2 drivers helps IRP_MJ_CREATE.

The filter driver forwards it right down to the PDO, and the PDO rejects it by way of nt!IopInvalidDeviceRequest.

For this reason for filter drivers we’d like a tool stack with a typical FDO under (or simply any driver that can settle for IRP_MJ_CREATE from userland).

One method to construct such a tool stack is by abusing the Disk Drive class (GUID {4d36e967-e325-11ce-bfc1-08002be10318}).

The algorithm is as follows:

  1. Deploy the filter driver with sc.exe create (no INF recordsdata concerned)
  2. Append the filer’s service title to the UpperFilters registry key for the system Disk Drive system class in HKLM:SYSTEMCurrentControlSetControlClass{4d36e967-e325-11ce-bfc1-08002be10318}.
  3. Mount a brand new arduous drive from VHD, creating a brand new system node and PnP constructing a brand new system stack for it.
  4. Filter turns into accessible as soon as we open a deal with on .PhysicalDrive0.

A PowerShell implementation might be discovered right here.

This deployment situation works for many filter drivers, whatever the system class the filter is meant for. This fashion I efficiently ran (and in some circumstances exploited) filter drivers for numerous system clasess, similar to disk, bluetooth, mouse, keyboard and audio.

As an example, right here we’re loading a gaming mouse filter driver on high of a disk stack:

Operating a gaming mouse filter on high of disk stack

If we examine the driving force object in WinDBG, we’ll see your complete system stack, together with GMLXDFltr with its unnamed FiDO on high of it:


0: kd> !drvobj GMLXDFltr
Driver object (ffffd20a9c4cde20) is for:
 DriverGMLXDFltr

Driver Extension Listing: (id , addr)

Gadget Object listing:
ffffd20a9b8a3690  ffffd20a9753b910
0: kd> !devobj ffffd20a9b8a3690
Gadget object (ffffd20a9b8a3690) is for:
  DriverGMLXDFltr DriverObject ffffd20a9c4cde20
Present Irp 00000000 RefCount 0 Kind 00000022 Flags 00000000
SecurityDescriptor ffffe48d055db5a0 DevExt ffffd20a9b8a37e0 DevObjExt ffffd20a9b8a3868
ExtensionFlags (0000000000)
Traits (0x00000100)  FILE_DEVICE_SECURE_OPEN
AttachedTo (Decrease) ffffd20a9ba1f690 Driverpartmgr
Gadget queue will not be busy.
0: kd> !devstack ffffd20a9b8a3690
  !DevObj           !DrvObj            !DevExt           ObjectName
> ffffd20a9b8a3690  DriverGMLXDFltr  ffffd20a9b8a37e0
  ffffd20a9ba1f690  Driverpartmgr    ffffd20a9ba1f7e0
  ffffd20a9f187060  Driverdisk       ffffd20a9f1871b0  DR1
  ffffd20aa30e8050  Drivervhdmp      ffffd20aa30e81a0  00000038
!DevNode ffffd20a9b8998c0 :
  DeviceInst is "SCSIDisk&Ven_Msft&Prod_Virtual_Disk2&1f4adffe&0&000001"
  ServiceName is "disk"

Let’s set a breakpoint on its IRP_MJ_CREATE dispatch routine. First, get hold of the handle:


0: kd> !drvobj GMLXDFltr 2
Driver object (ffffd20a9c4cde20) is for:
 DriverGMLXDFltr

DriverEntry:   fffff80085a52244 GMLXDFltr
DriverStartIo: 00000000
DriverUnload:  fffff80085a51b8c GMLXDFltr
AddDevice:     fffff80085a51ab4 GMLXDFltr

Dispatch routines:


[00] IRP_MJ_CREATE                      fffff80085a51a08        GMLXDFltr+0x1a08

Then arrange a breakpoint, resume execution:


0: kd> bp GMLXDFltr+0x1a08 ".echo GMLXDFltr IRP_MJ_CREATE known as;g"
0: kd> g

On the VM, resolve the system path and set off IRP_MJ_CREATE by making an attempt to learn the SDDL:


PS C:> Get-NtSymbolicLinkTarget 'GLOBAL??PhysicalDrive1'
DeviceHarddisk1DR1
PS C:> Get-NtSecurityDescriptor 'DeviceHarddisk1DR1'

Proprietor                  DACL ACE Depend SACL ACE Depend Integrity Stage
-----                  -------------- -------------- ---------------
BUILTINAdministrators 5              NONE           NONE

Debugger output:


0: kd> g
GMLXDFltr IRP_MJ_CREATE known as
GMLXDFltr IRP_MJ_CREATE known as

So, it’s working! We’re accessing a gaming mouse filter driver by way of a deal with opened on DeviceHarddisk1DR1!

On a facet observe, surprisingly, the breakpoint is activated twice, not as soon as. Why?

To search out out, let’s begin with confirming the id of the userland course of. For that we will connect the next script to run when the breakpoint hits, so it prints the picture title of the present userland caller:


bp GMLXDFltr+0x1a08 ".echo GMLXDFltr IRP_MJ_CREATE ran;.scriptrun C:Customersewildedcurr_image_name.js;g"
breakpoint 0 redefined
0: kd> g

And now, when Get-NtSecurityDescriptor ‘DeviceHarddisk1DR1’ is invoked once more, we get:


GMLXDFltr IRP_MJ_CREATE ran
JavaScript script efficiently loaded from 'C:UsersewildedWinDBG_scriptscurr_image_name.js'
Present Course of Picture Identify: powershell.exe
GMLXDFltr IRP_MJ_CREATE ran
JavaScript script efficiently loaded from 'C:UsersewildedWinDBG_scriptscurr_image_name.js'
Present Course of Picture Identify: powershell.exe

So in each circumstances the caller is powershell.

See also  A Technical Hole Evaluation of Final-Mile Safety

Let’s additionally print the DesiredAccess by way of IRP IO_STACK_LOCATION, to get extra particulars:


1: kd> g
GMLXDFltr IRP_MJ_CREATE ran
Present Course of Picture Identify: powershell.exe
GMLXDFltr+0x1a08:
fffff800`85a51a08 48895c2408      mov     qword ptr [rsp+8],rbx
2: kd> dt nt!_IRP @rdx Tail.Overlay.CurrentStackLocation
   +0x078 Tail                              :
      +0x000 Overlay                           :
         +0x040 CurrentStackLocation              : 0xffffd20a`9d4806f8 _IO_STACK_LOCATION
2: kd> dt nt!_IO_STACK_LOCATION 0xffffd20a`9d4806f8 Parameters.Create.SecurityContext
   +0x008 Parameters                        :
      +0x000 Create                            :
         +0x000 SecurityContext                   : 0xfffff504`0ab565d0 _IO_SECURITY_CONTEXT
2: kd> dt nt!_IO_SECURITY_CONTEXT 0xfffff504`0ab565d0 DesiredAccess
   +0x010 DesiredAccess : 0x20000

So through the first name of GMLXDFltr+0x1a08, the DesiredAccess is 0x20000. Let’s resume execution and examine the identical property on the second breakpoint hit:


2: kd> g
GMLXDFltr IRP_MJ_CREATE ran
Present Course of Picture Identify: powershell.exe
GMLXDFltr+0x1a08:
fffff800`85a51a08 48895c2408      mov     qword ptr [rsp+8],rbx
0: kd> dt nt!_IRP @rdx Tail.Overlay.CurrentStackLocation
   +0x078 Tail                              :
      +0x000 Overlay                           :
         +0x040 CurrentStackLocation              : 0xffffd20a`9dc4a808 _IO_STACK_LOCATION
0: kd> dt nt!_IO_STACK_LOCATION 0xffffd20a`9dc4a808 Parameters.Create.SecurityContext
   +0x008 Parameters                        :
      +0x000 Create                            :
         +0x000 SecurityContext                   : (null)

So, within the first name, DesiredAccess is 0x20000. However in the second, the SecurityContext is NULL. This strongly means that on this second name, we aren’t coping with IRP_MJ_CREATE in any respect.

Let’s study the decision stacks when the breakpoint hits.

First:


GMLXDFltr+0x1a08:
fffff800`85a51a08 48895c2408      mov     qword ptr [rsp+8],rbx
3: kd> okay
 # Baby-SP          RetAddr               Name Website
00 fffff504`0ab56448 fffff800`68eebef5     GMLXDFltr+0x1a08
01 fffff504`0ab56450 fffff800`692f753e     nt!IofCallDriver+0x55
02 fffff504`0ab56490 fffff800`692f2874     nt!IopParseDevice+0x8be
03 fffff504`0ab56660 fffff800`692f1222     nt!ObpLookupObjectName+0x1104
04 fffff504`0ab567f0 fffff800`692eecb1     nt!ObOpenObjectByNameEx+0x1f2
05 fffff504`0ab56920 fffff800`6934f438     nt!IopCreateFile+0x431
06 fffff504`0ab569e0 fffff800`6902bbe5     nt!NtOpenFile+0x58
07 fffff504`0ab56a70 00007ffe`e51af9d4     nt!KiSystemServiceCopyEnd+0x25
08 00000010`96acd9d8 00007ffe`7209aa32     0x00007ffe`e51af9d4
09 00000010`96acd9e0 00000000`00020000     0x00007ffe`7209aa32
0a 00000010`96acd9e8 00000010`96acda10     0x20000
0b 00000010`96acd9f0 00000010`96acdae0     0x00000010`96acda10
0c 00000010`96acd9f8 00000142`0a263498     0x00000010`96acdae0
0d 00000010`96acda00 00000000`00000005     0x00000142`0a263498
0e 00000010`96acda08 00000000`00000000     0x5

We are able to see nt!NtOpenFile within the Name Website column, which is predicted, and confirms that is the handle-opening name.

Let’s resume the execution and study the second hit:


3: kd> g
GMLXDFltr IRP_MJ_CREATE ran
Present Course of Picture Identify: powershell.exe
GMLXDFltr+0x1a08:
fffff800`85a51a08 48895c2408      mov     qword ptr [rsp+8],rbx
3: kd> okay
 # Baby-SP          RetAddr               Name Website
00 fffff504`0ab56828 fffff800`68eebef5     GMLXDFltr+0x1a08
01 fffff504`0ab56830 fffff800`692f9bdc     nt!IofCallDriver+0x55
02 fffff504`0ab56870 fffff800`692f352e     nt!IopDeleteFile+0x13c
03 fffff504`0ab568f0 fffff800`68eec627     nt!ObpRemoveObjectRoutine+0x7e
04 fffff504`0ab56950 fffff800`693437d4     nt!ObfDereferenceObjectWithTag+0xc7
05 fffff504`0ab56990 fffff800`693403a9     nt!ObpCloseHandle+0x2a4
06 fffff504`0ab56ab0 fffff800`6902bbe5     nt!NtClose+0x39
07 fffff504`0ab56ae0 00007ffe`e51af554     nt!KiSystemServiceCopyEnd+0x25
08 00000010`96acd958 00007ffe`71e3db77     0x00007ffe`e51af554
09 00000010`96acd960 00007ffe`71e06bf0     0x00007ffe`71e3db77
0a 00000010`96acd968 00000000`00000d28     0x00007ffe`71e06bf0
0b 00000010`96acd970 00000142`1f783590     0xd28
0c 00000010`96acd978 00007ffe`d10a4bce     0x00000142`1f783590
0d 00000010`96acd980 00004f02`50afaf79     0x00007ffe`d10a4bce
0e 00000010`96acd988 00007ffe`d17b6370     0x00004f02`50afaf79
0f 00000010`96acd990 00000010`96acdb80     0x00007ffe`d17b6370
10 00000010`96acd998 00007ffe`71e06bf0     0x00000010`96acdb80
11 00000010`96acd9a0 00007ffe`71e06bf0     0x00007ffe`71e06bf0
12 00000010`96acd9a8 00000010`96acd960     0x00007ffe`71e06bf0
13 00000010`96acd9b0 00007ffe`71e3db77     0x00000010`96acd960
14 00000010`96acd9b8 00000010`96acda00     0x00007ffe`71e3db77
15 00000010`96acd9c0 00007ffe`71e06bf0     0x00000010`96acda00
16 00000010`96acd9c8 00000010`96acdae0     0x00007ffe`71e06bf0
17 00000010`96acd9d0 00000142`0a263798     0x00000010`96acdae0
18 00000010`96acd9d8 00000142`1f783590     0x00000142`0a263798
19 00000010`96acd9e0 00000142`0a2590f0     0x00000142`1f783590
1a 00000010`96acd9e8 00000000`00000000     0x00000142`0a2590f0

So, the second name is not IRP_MJ_CREATE. It’s IRP_MJ_CLOSE (powershell closing the deal with), and it comes from NtClose (seen within the Name Website colum).

The breakpoint hits twice, as a result of GMLXDFltr makes use of the identical dispatch routine for each MajorCodes.

A look on the dispatch desk confirms this. Each IRP_MJ_CREATE and IRP_MJ_CLOSE are set to GMLXDFltr+0x1a08:


0: kd> !drvobj GMLXDFltr 2
Driver object (ffffd20a9c4cde20) is for:
 DriverGMLXDFltr

DriverEntry:   fffff80085a52244 GMLXDFltr
DriverStartIo: 00000000
DriverUnload:  fffff80085a51b8c GMLXDFltr
AddDevice:     fffff80085a51ab4 GMLXDFltr

Dispatch routines:
[00] IRP_MJ_CREATE                      fffff80085a51a08        GMLXDFltr+0x1a08
[01] IRP_MJ_CREATE_NAMED_PIPE           fffff80085a50388        GMLXDFltr+0x388
[02] IRP_MJ_CLOSE                       fffff80085a51a08        GMLXDFltr+0x1a08

4.3.2 Per-device and per-class filters

International per-class system filters might be arrange within the LowerFilters and UpperFilters entries within the related system class registry areas:


HKLM:SYSTEMCurrentControlSetControlClass{GUID}

For instance:


HKLM:SYSTEMCurrentControlSetControlClass{4d36e967-e325-11ce-bfc1-08002be10318}UpperFilters

for Disk Drives.

The listing of well-known GUIDs representing system lessons might be discovered right here. As we will see, Storage Volumes, Disk Drives and Storage Disks represent separate, though comparable system lessons.

UpperFilters and LowerFilters will also be arrange for system nodes extra selectively – per occasion ID as a substitute of system class.

These are situated in HKLMSYSTEMCurrentControlSetEnum<instance_ID>. For instance: – HKLMSYSTEMCurrentControlSetEnumSWDHWID001 (SWD for gadgets created by way of the Software program Gadget API), – HKLMSYSTEMCurrentControlSetEnumROOTHWID2000 (ROOT for root-enumerated gadgets created by means of SetupAPI).

This supplies extra flexibility within the methods filters might be run. We might use a software-emulated system with an FDO that helps IRP_MJ_CREATE solely to run the filter on high of it, with out making a Disk Drive system node by mounting a disk.

4.4 Compelled driver substitute

The true motive for utilizing software-emulated gadgets as described within the earlier sections is to get the driving force correctly initialized by tricking the PnP supervisor to name its AddDevice callback with a pointer to a PDO.

A substitute for that strategy is utilizing one of many gadgets already current within the system.

So, can we merely pressure our driver to be put in and loaded for an current piece of {hardware}, changing the unique one?

One motive towards this strategy is system stability.

If we pressure an incorrect driver on a chunk of {hardware}, it’s cheap to imagine that {hardware} will cease functioning accurately. To alleviate that threat we might choose a tool that’s not crucial and whose disruption is unlikely to be even observed.

One other potential reason for crucial disruption (leading to system crash) is that if the newly loaded driver makes a reference to the PDO’s system extension at some particular offset that exists within the PDO the driving force was designed to work with. So it’s a matter of trial and error to discover a appropriate system node for this objective.

Assuming that the goal system is comparable sufficient to the system the susceptible driver was developed, or the driving force is easy sufficient, it might work (relying on the driving force).

So, what’s stopping us from attempting this?

Throughout regular driver set up course of, forcing an arbitrary driver on an arbitrary system node is problematic due to the {hardware} ID missmatch. PnP matches the {hardware} ID (reported by the bus driver proudly owning the PDO) towards all INF recordsdata within the native Home windows driver repository.

PnP won’t acknowledge a driver as right if the system node’s {hardware} ID doesn’t match the {hardware} ID within the corresponding INF file.

The INF file is what ties a driver to a particular {hardware} ID.

4.4.1 The issue with INF recordsdata

So, can we use a customized INF file, which merely ties FAKEHWID_1234 to AwinicSmartKAmps.sys as a substitute?

Let’s have a look at.

First, let’s create a brand new system node with an arbitrary {hardware} ID, utilizing create_swdev_cm.c:


create_swdev_cm.exe FAKEHWID_1234
Gadget node created efficiently for {hardware} ID: FAKEHWID_1234

We are able to examine it in Gadget Supervisor. It seems within the Software program Gadgets group due to the category GUID hardcoded in create_swdev_cm.c, however that may be modified if wanted. We are able to clearly see the arbitrary {hardware} ID and and that at this stage there is no such thing as a driver put in for the system:

Software program system with arbitrary {hardware} ID and no driver put in
Software program system with arbitrary {hardware} ID and no driver put in

The PnP supervisor has not discovered any matching drivers, as a result of FAKEHWID_1234 will not be matched by any INF file from the driving force repository. That is anticipated.

Now, let’s have a look at what occurs after we attempt to replace the driving force utilizing a minimal customized INF file, tying FAKEHWID_1234 to AwinicSmartKAmps.sys:

Customized INF file tying FAKEHWID_1234 to AwinicSmartKAmps.sys

If we right-click on the “Unknown system” and invoke “Replace driver”, we will manually level the listing with the INF file after selecting: “Browse my laptop” -> “Let me decide from a listing of accessible drivers on my laptop” -> “Have disk”, we’ll see a warning “This driver will not be digitally signed!”:

Customized INF file – driver not signed warning

If we ignore the warning and click on “Subsequent”, we’ll see this:

Customized INF file – set up interrupted

It is because recordsdata in a driver package deal, together with the INF file, are protected by digital signatures outlined within the catalog file (.cat).

If we take away the CatalogFile = AwinicSmartKAmps.cat line totally and take a look at once more, we’ll find yourself with the identical final result and a barely totally different error message:

Customized INF file – set up interrupted

This logic is applied behind UpdateDriverForPlugAndPlayDevicesW – if we attempt to do that programmatically as a substitute of utilizing GUI, we’ll attain the identical final result, with UpdateDriverForPlugAndPlayDevicesW returning related error codes.

4.4.2 Bypassing the INF file mechanism

If we dig deeper into the PnP structure, we’ll uncover that what actually ties a driver to a tool node is devoted registry constructions.

Relying on whether or not we’re creating a brand new system, or forcing our driver on an current one, we will both immediately create new registry constructions or modify the present ones, to make them replicate the state usually attained with a profitable set up, successfully skipping your complete INF mechanism.

It boils right down to: 1. Deploying the driving force with sc.exe create, the usual approach. 2. Selecting the goal system (for this check we’ll create one utilizing SetupAPI). 3. Creating the related registry constructions within the following areas, tying the driving force’s service title to the system: – SYSTEMCurrentControlSetEnum<DEVICE_INSTANCE_ID>, – SYSTEMCurrentControlSetManagementClass<GUID><INSTANCE_INDEX>. 4. Restarting the system (triggers PnP to load the driving force).

The system occasion ID is the complete path that uniquely identifies a tool within the system and is the precise identifier of a tool node.

It is sensible after we give it some thought. The {hardware} ID solely identifies the make and mannequin, and utilizing it because the system node identifier would stop the OS from supporting a number of gadgets with the identical {hardware} ID linked to the system on the similar time.

Gadget occasion ID has the next type: <Enumerator><DeviceID><InstanceID>, for instance: PCIVEN_8086&DEV_A370&SUBSYS_02348086&REV_103&11583659&0&F5.

Occasion ID is simply the final section – the half that disambiguates a number of gadgets with the identical enumerator and system ID. Within the instance above, that is 3&11583659&0&F5. It identifies which bodily/logical system that is amongst gadgets sharing the identical enumerator and system ID.

In our case the system occasion ID will likely be ROOTSOFTWAREDEVICE000, whereas: – ROOT is the enumerator title, – SOFTWAREDEVICE is the system ID (the worth comes from uppercase conversion of the string handed because the second argument to SetupDiCreateDeviceInfoW), – 0000 is the occasion ID.

The occasion index, alternatively, is a zero-based, four-digit sequential quantity that identifies a particular system occasion inside a tool setup class. Due to this fact, if no different system cases exist for the given system ID on the time of creation, the occasion index will likely be 0000.

Let’s deploy the identical driver as earlier utilizing this strategy.

First, we create the service within the common sc.exe create approach:


sc.exe create AwinicDriver binPath= "C:runtime_serviceAwinicSmartKAmps.sys" kind= kernel begin= demand
[SC] CreateService SUCCESS

sc.exe begin AwinicDriver

SERVICE_NAME: AwinicDriver
        TYPE               : 1  KERNEL_DRIVER
        STATE              : 4  RUNNING
                                (STOPPABLE, NOT_PAUSABLE, IGNORES_SHUTDOWN)
        WIN32_EXIT_CODE    : 0  (0x0)
        SERVICE_EXIT_CODE  : 0  (0x0)
        CHECKPOINT         : 0x0
        WAIT_HINT          : 0x0
        PID                : 0
        FLAGS

Then, we run the installer (full supply code of create_sd_bind_driver.c might be discovered right here):


create_sd_bind_driver.exe FAKEHWID_54321 AwinicDriver {62f9c741-b25a-46ce-b54c-9bccce08b6f2}
Gadget node created: ROOTSOFTWAREDEVICE000 (DevInst=2)
Service sure: AwinicDriver
Class key created: SYSTEMCurrentControlSetControlClass{62f9c741-b25a-46ce-b54c-9bccce08b6f2}003
Driver worth set: {62f9c741-b25a-46ce-b54c-9bccce08b6f2}003
ConfigFlags set: 0
Restarting system (disable/allow cycle)...
Gadget enabled. AddDevice ought to have been known as.

Listed below are the related registry constructions after working create_sd_bind_driver.exe:

HLLMSYSTEMCurrentControlSetControlClass{GUID}
HKLMSYSTEMCurrentControlSetEnumROOTSOFTWAREDEVICE000

By inspecting the system once more within the Gadget Supervisor, we will clearly see that: – the system was created, – the driving force acquired put in for it, – the system stack acquired created.

Gadget working correctly
Arbitrary {hardware} ID
Gadget stack constructed

If we glance into the Driver tab, we’ll discover that the driving force is “not digitally signed”, which generally is a bit deceptive:

Driver not digitally signed

The rationale we’re seeing it’s because there is no such thing as a INF file and no CAT file tied to this driver within the registry.

The .sys file itself is digitally signed, and naturally check signing was not enabled on the time of testing:

Digital signature legitimate, no check signing

This demonstrates that INF recordsdata and their signatures will not be a security boundary, however somewhat a function meant to stop INF file abuse (e.g. risk actors backdooring INF recordsdata by including malicious directives, which might then execute with administrative privileges throughout set up).

That is sensible – in any case, we didn’t want INF recordsdata to append drivers to the UpperFilters/LowerFilters keys. And we do not actually need them to tie a driver to a chunk of {hardware}.

The identical pressured set up strategy might be carried out for already current gadgets. We deploy the driving force with sc.exe, modify the registry to tie it as the driving force for that system, then restart the system.

Alternatively, we might even substitute the related .sys file and restart the system, nonetheless that may not work if we aren’t in a position to unload the unique driver earlier than substitute (as a result of the kernel won’t load one other module with the identical title).

4.5 Working round energetic {hardware} probing

Passing numerous {hardware} probing checks talked about in part 3.4 Lively {hardware} interplay and probing with out the corresponding bodily {hardware} is for essentially the most half doable, however requires both customized kernel mode code (drivers devoted explicitly for this objective, particularly bus and filter drivers) or hypervisor entry.

None of those necessities are glad in a typical BYOVD situation. A radical evaluation of {hardware} interplay mechanisms and the feasibility of spoofing them from user-mode alone is past the scope of this text; nonetheless, my preliminary evaluation means that no purely userland method can generically bypass hardware-gated code paths with out loading extra kernel mode elements.

5. Last ideas

Whereas crucial vulnerabilities are nonetheless fairly widespread in Home windows kernel mode drivers, not all drivers with related vulnerabilities current of their code have sensible worth from the BYOVD perspective on account of conditional (normally hardware-dependant) reachability of susceptible code paths.

As I’ve demonstrated, a lot of these circumstances might be labored round by influencing the interior driver state from user-mode by creating software-emulated system nodes with spoofed {hardware} IDs or pressured substitute of drivers for current {hardware}.

Understanding these caveats will help higher assess dangers related to particular system driver vulnerabilities.

It’s cheap to imagine that in some unspecified time in the future within the close to future the vary of BYOVD-viable drivers will begin shrinking on account of AI-accelerated vulnerability analysis and Microsoft eradicating belief for cross-signed drivers, simply to call a number of causes.

As soon as that begins occurring, it might give risk actors the inducement to begin making the most of susceptible drivers whose exploitability solely seemingly is dependent upon the presence of the corresponding bodily {hardware}, whereas in follow might be labored round by solely working from userland. Due to this fact, it’s price for defenders to concentrate to the forensic footprint related to the strategies demonstrated on this article.

If you wish to learn comparable articles or the predecessor of this text known as “Anatomy of Entry: system objects from a security perspective”, Click on right here.

Be aware: This text was thoughtfully written and contributed for our viewers Julian Horoszkiewicz, Atos Menace Analysis Middle.

- Advertisment -spot_img
RELATED ARTICLES

LEAVE A REPLY

Please enter your comment!
Please enter your name here

- Advertisment -

Most Popular