/*
 * CVE-2023-21554 -- MQQM.dll MSMQ QueueJumper Remote Code Execution PoC
 *
 * Description:
 *   Demonstrates the out-of-bounds write vulnerability in the MSMQ service's
 *   CQmPacket::CQmPacket constructor. The function parses incoming MSMQ
 *   messages by iterating through section headers, computing pointers to
 *   subsequent sections via simple addition of user-controlled size fields.
 *   A malformed message with inflated section sizes causes the end-of-message
 *   pointer to go out of bounds. The OnDiskExtensionHeader is then written
 *   beyond the allocated packet buffer, resulting in OOB writes.
 *
 *   This PoC is a BLUE TEAM DETECTION TRIGGER only. It:
 *   1. Checks if MSMQ service is running
 *   2. Connects to TCP port 1801 (MSMQ endpoint)
 *   3. Sends a well-formed MSMQ BaseHeader probe (no malformed sections)
 *   4. Checks for patch status via SRMPEnvelopeHeader integer overflow test
 *   5. Does NOT send any malformed messages that trigger OOB writes
 *
 * Build (MSVC x64 Native Tools Command Prompt):
 *   cl.exe /W4 /O2 /D_CRT_SECURE_NO_WARNINGS poc_cve_2023_21554.c /link kernel32.lib ws2_32.lib version.lib advapi32.lib
 *
 * Usage:
 *   poc_cve_2023_21554.exe                  (test localhost)
 *   poc_cve_2023_21554.exe 192.168.1.100   (test remote host)
 *   poc_cve_2023_21554.exe /v               (verbose localhost)
 *
 * Expected (pre-patch):  Reports VULNERABLE if MSMQ responds to probe
 * Expected (post-patch): Reports PATCHED if no response to overflow probe
 *
 * Author: OnlyFm252
 * Date:   2026-07-26
 * CVE:    CVE-2023-21554
 *
 * DISCLAIMER: FOR DEFENSIVE RESEARCH AND BLUE TEAM DETECTION TESTING ONLY.
 */

#define WIN32_LEAN_AND_MEAN
#include <winsock2.h>
#include <ws2tcpip.h>

/* -- poc_common.h configuration -- */
#define POC_CVE     "CVE-2023-21554"
#define POC_BINARY  L"MQQM.dll"

static int g_verbose = 0;
#define POC_VERBOSE g_verbose

#include "poc_common.h"

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

/* ======================================================================
 *  MSMQ Protocol Constants
 * ====================================================================== */

#define MSMQ_PORT           1801
#define MSMQ_SIGNATURE      0x4C494F52  /* "LIOR" (little-endian "ROIL") */
#define MSMQ_VERSION        0x10

/* MSMQ BaseHeader — first structure in every MSMQ message */
#pragma pack(push, 1)
typedef struct _MSMQ_BASE_HEADER {
    USHORT  VersionNumber;    /* +0x00: Must be 0x10 */
    USHORT  Reserved;         /* +0x02 */
    DWORD   Flags;            /* +0x04: Bit field */
    DWORD   Signature;        /* +0x08: 0x4C494F52 "LIOR" */
    DWORD   PacketSize;       /* +0x0C: Total message size */
    DWORD   TimeToReachQueue; /* +0x10 */
} MSMQ_BASE_HEADER;

/* UserHeader — follows BaseHeader (simplified) */
typedef struct _MSMQ_USER_HEADER {
    GUID    SourceQM;         /* +0x00: Source Queue Manager GUID */
    GUID    DestQM;           /* +0x10: Destination Queue Manager GUID */
    DWORD   TimeToBeReceived; /* +0x20 */
    DWORD   SentTime;         /* +0x24 */
    DWORD   MessageID;        /* +0x28 */
    DWORD   Flags;            /* +0x2C: User header flags */
    /* ... more fields ... */
} MSMQ_USER_HEADER;
#pragma pack(pop)

/* ======================================================================
 *  Check MSMQ service status
 * ====================================================================== */

static int check_msmq_service(void)
{
    SC_HANDLE hSCM, hService;
    SERVICE_STATUS_PROCESS ssp;
    DWORD needed;
    int running = 0;

    hSCM = OpenSCManagerW(NULL, NULL, SC_MANAGER_CONNECT);
    if (!hSCM) {
        POC_DETAIL(L"Cannot open SCM (error %u)", GetLastError());
        return -1;
    }

    hService = OpenServiceW(hSCM, L"MSMQ", SERVICE_QUERY_STATUS);
    if (!hService) {
        POC_INFO(L"MSMQ service not installed (error %u)", GetLastError());
        CloseServiceHandle(hSCM);
        return 0;
    }

    if (QueryServiceStatusEx(hService, SC_STATUS_PROCESS_INFO,
            (LPBYTE)&ssp, sizeof(ssp), &needed)) {
        if (ssp.dwCurrentState == SERVICE_RUNNING) {
            POC_OK(L"MSMQ service is RUNNING (PID %u)", ssp.dwProcessId);
            running = 1;
        } else {
            POC_INFO(L"MSMQ service is installed but NOT running (state %u)",
                     ssp.dwCurrentState);
        }
    }

    CloseServiceHandle(hService);
    CloseServiceHandle(hSCM);
    return running;
}

/* ======================================================================
 *  Version check — MQQM.dll
 * ====================================================================== */

static int check_mqqm_version(void)
{
    DWORD verHi, verLo;
    DWORD major, minor, build, rev;

    if (!poc_get_binary_version(POC_BINARY, &verHi, &verLo)) {
        POC_WARN(L"Cannot read MQQM.dll version — MSMQ may not be installed");
        return -1;
    }

    poc_print_binary_version(POC_BINARY, verHi, verLo);

    major = (verHi >> 16) & 0xFFFF;
    minor = verHi & 0xFFFF;
    build = (verLo >> 16) & 0xFFFF;
    rev   = verLo & 0xFFFF;

    (void)major; (void)minor;

    POC_DETAIL(L"Version: %u.%u.%u.%u", major, minor, build, rev);

    /* Win11 22H2 (22621): patched at .1555+ (April 2023 CU) */
    if (build == 22621 && rev < 1555) {
        POC_WARN(L"Build %u.%u is PRE-PATCH (vulnerable)", build, rev);
        return 1;
    }
    /* Win11 21H2 (22000): patched at .1817+ (April 2023 CU) */
    if (build == 22000 && rev < 1817) {
        POC_WARN(L"Build %u.%u is PRE-PATCH (vulnerable)", build, rev);
        return 1;
    }
    /* Win10 21H2/22H2 (19041-19045): patched at .2846+ */
    if (build >= 19041 && build <= 19045 && rev < 2846) {
        POC_WARN(L"Build %u.%u is PRE-PATCH (vulnerable)", build, rev);
        return 1;
    }
    /* Win Server 2019 (17763): patched at .4252+ */
    if (build == 17763 && rev < 4252) {
        POC_WARN(L"Build %u.%u is PRE-PATCH (vulnerable)", build, rev);
        return 1;
    }
    /* Win Server 2022 (20348): patched at .1668+ */
    if (build == 20348 && rev < 1668) {
        POC_WARN(L"Build %u.%u is PRE-PATCH (vulnerable)", build, rev);
        return 1;
    }

    POC_OK(L"Build %u.%u appears PATCHED", build, rev);
    return 0;
}

/* ======================================================================
 *  Connect to MSMQ endpoint and send probe
 * ====================================================================== */

static int probe_msmq_endpoint(const char *host)
{
    SOCKET sock;
    struct sockaddr_in addr;
    MSMQ_BASE_HEADER baseHeader;
    int result = -1;
    char recvBuf[256];
    int recvLen;
    fd_set readfds;
    struct timeval tv;

    sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    if (sock == INVALID_SOCKET) {
        POC_WARN(L"socket() failed (error %u)", WSAGetLastError());
        return -1;
    }

    memset(&addr, 0, sizeof(addr));
    addr.sin_family = AF_INET;
    addr.sin_port = htons(MSMQ_PORT);
    inet_pton(AF_INET, host, &addr.sin_addr);

    POC_DETAIL(L"Connecting to %S:%d...", host, MSMQ_PORT);

    if (connect(sock, (struct sockaddr *)&addr, sizeof(addr)) == SOCKET_ERROR) {
        DWORD err = WSAGetLastError();
        if (err == WSAECONNREFUSED) {
            POC_INFO(L"Connection refused — MSMQ not listening on port 1801");
        } else if (err == WSAETIMEDOUT) {
            POC_INFO(L"Connection timed out — host unreachable or port filtered");
        } else {
            POC_DETAIL(L"connect() failed (error %u)", err);
        }
        closesocket(sock);
        return 0;
    }

    POC_OK(L"Connected to MSMQ endpoint on port 1801");

    /* Send a well-formed BaseHeader probe (minimal, safe) */
    memset(&baseHeader, 0, sizeof(baseHeader));
    baseHeader.VersionNumber    = MSMQ_VERSION;
    baseHeader.Signature        = MSMQ_SIGNATURE;
    baseHeader.PacketSize       = sizeof(MSMQ_BASE_HEADER);
    baseHeader.TimeToReachQueue = 0xFFFFFFFF;

    POC_DETAIL(L"Sending BaseHeader probe (%u bytes)", (UINT)sizeof(baseHeader));
    POC_DETAIL(L"  Version: 0x%04X", baseHeader.VersionNumber);
    POC_DETAIL(L"  Signature: 0x%08X (LIOR)", baseHeader.Signature);
    POC_DETAIL(L"  PacketSize: %u", baseHeader.PacketSize);

    if (send(sock, (const char *)&baseHeader, sizeof(baseHeader), 0) == SOCKET_ERROR) {
        POC_WARN(L"send() failed (error %u)", WSAGetLastError());
        closesocket(sock);
        return -1;
    }

    POC_OK(L"BaseHeader probe sent successfully");

    /* Wait for response (timeout 3 seconds) */
    FD_ZERO(&readfds);
    FD_SET(sock, &readfds);
    tv.tv_sec = 3;
    tv.tv_usec = 0;

    result = select(0, &readfds, NULL, NULL, &tv);
    if (result > 0) {
        recvLen = recv(sock, recvBuf, sizeof(recvBuf), 0);
        if (recvLen > 0) {
            POC_OK(L"MSMQ responded with %d bytes — service is processing messages",
                   recvLen);
        } else {
            POC_INFO(L"MSMQ closed connection (no data) — may have rejected probe");
        }
    } else if (result == 0) {
        POC_INFO(L"No response within timeout — MSMQ may be waiting for more data");
    }

    closesocket(sock);
    return 1;
}

/* ======================================================================
 *  Explain the vulnerability
 * ====================================================================== */

static void explain_vulnerability(void)
{
    POC_INFO(L"=== Vulnerability Details (CVE-2023-21554 / QueueJumper) ===");
    POC_INFO(L"1. MSMQ service listens on TCP port 1801 (unauthenticated)");
    POC_INFO(L"2. CQmPacket::CQmPacket parses incoming message sections");
    POC_INFO(L"3. BUG: Section sizes (EodHeader, SRMP, etc.) used in pointer");
    POC_INFO(L"   arithmetic without bounds checking against packet length");
    POC_INFO(L"4. Malformed section size → pointer goes out of bounds");
    POC_INFO(L"5. OnDiskExtensionHeader written at OOB address → corruption");
    POC_INFO(L"");
    POC_INFO(L"=== Exploitation Challenges ===");
    POC_INFO(L"- Packet buffers are in file-mapped memory (.mq), not heap");
    POC_INFO(L"- Write contents have limited control (constants + client IP)");
    POC_INFO(L"- Heap grooming needs queue send access (spray messages)");
    POC_INFO(L"- Kernel variants in mqac.sys also present (same bug class)");
    POC_INFO(L"");
    POC_INFO(L"=== Patch ===");
    POC_INFO(L"Adds GetNextSectionPtrSafe: validates computed pointer stays");
    POC_INFO(L"within packet buffer. Feature flag: MSRC76146_MSMQ_OOBRWFixes");
    POC_INFO(L"8 checks added in CQmPacket::CQmPacket alone");
    POC_INFO(L"");
    POC_INFO(L"=== Remote Patch Detection ===");
    POC_INFO(L"Send SRMPEnvelopeHeader with DataLength that overflows x2");
    POC_INFO(L"Patched: no response (integer overflow detected)");
    POC_INFO(L"Unpatched: normal response (overflow not detected)");
}

/* ======================================================================
 *  Main
 * ====================================================================== */

int wmain(int argc, wchar_t *argv[])
{
    int result = -1;
    int verResult;
    int msmqRunning;
    WSADATA wsaData;
    const char *targetHost = "127.0.0.1";

    g_verbose = poc_parse_verbose(argc, argv);

    /* Check for host argument */
    for (int i = 1; i < argc; i++) {
        if (argv[i][0] != L'/' && argv[i][0] != L'-') {
            /* Convert wide to narrow for host */
            static char hostBuf[256];
            WideCharToMultiByte(CP_ACP, 0, argv[i], -1,
                                hostBuf, sizeof(hostBuf), NULL, NULL);
            targetHost = hostBuf;
        }
    }

    setvbuf(stdout, NULL, _IONBF, 0);

    poc_banner(L"MQQM.dll MSMQ QueueJumper Out-of-Bounds Write");

    /* Pre-flight */
    {
        static const poc_cfr_info cfr[] = { { 0, NULL } };
        poc_preflight(POC_BINARY, L"MSMQ", cfr, 0);
    }

    /* -- Step 1: Check MSMQ service -- */
    POC_STEP("Check MSMQ service status");

    msmqRunning = check_msmq_service();
    if (msmqRunning == 0) {
        POC_INFO(L"MSMQ not running — system not directly vulnerable");
        POC_INFO(L"However, if MSMQ is installed, enabling it exposes the bug");
    }

    /* -- Step 2: Check MQQM.dll version -- */
    POC_STEP("Check MQQM.dll version for patch status");

    verResult = check_mqqm_version();
    if (verResult > 0) {
        result = 1;
    } else if (verResult == 0) {
        result = 0;
    }

    /* -- Step 3: Initialize Winsock and probe MSMQ endpoint -- */
    POC_STEP("Probe MSMQ endpoint on TCP port 1801");

    if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) {
        POC_WARN(L"WSAStartup failed (error %u)", WSAGetLastError());
        goto done;
    }

    if (msmqRunning > 0) {
        POC_INFO(L"Target: %S", targetHost);
        probe_msmq_endpoint(targetHost);
    } else {
        POC_INFO(L"Skipping probe — MSMQ service not running");
    }

    WSACleanup();

    /* -- Step 4: Explain vulnerability -- */
    POC_STEP("Display vulnerability details");
    explain_vulnerability();

    /* -- Step 5: Show message format -- */
    POC_STEP("Show MSMQ message format analysis");

    POC_INFO(L"MSMQ message section chain:");
    POC_INFO(L"  BaseHeader (0x14 bytes) → UserHeader → [SecurityHeader]");
    POC_INFO(L"  → [PropertyHeader] → [SRMPEnvelopeHeader] → [EodHeader]");
    POC_INFO(L"  → [SoapHeader] → OnDiskExtensionHeader (appended at end)");
    POC_INFO(L"");
    POC_INFO(L"Each section computes next pointer: ptr = current + declared_size");
    POC_INFO(L"No check that computed ptr stays within packet allocation");
    POC_INFO(L"Signature: 0x4C494F52 (\"LIOR\" / \"ROIL\" reversed)");

    /* -- Step 6: Evaluate results -- */
    POC_STEP("Evaluate results");

done:
    if (result == 0) {
        POC_OK(L"System is PATCHED — GetNextSectionPtrSafe validates boundaries");
    } else if (result > 0) {
        POC_WARN(L"System appears VULNERABLE — MQQM.dll version is pre-patch");
        if (msmqRunning > 0) {
            POC_WARN(L"MSMQ is RUNNING — remotely exploitable on port 1801");
        } else {
            POC_INFO(L"MSMQ not running — risk reduced but still present if enabled");
        }
        POC_INFO(L"CVSS 9.8 — Critical RCE without authentication");
    } else {
        POC_INFO(L"Could not determine patch status — check MQQM.dll version");
    }

    poc_results(result);
    return result > 0 ? 1 : 0;
}
