# Root Cause Analysis — CVE-2023-21554

## Summary

| Field | Value |
|---|---|
| **CVE** | CVE-2023-21554 (QueueJumper) |
| **Binary** | MQQM.dll (Microsoft Message Queuing Queue Manager) |
| **Component** | CQmPacket::CQmPacket — MSMQ packet constructor |
| **Bug Class** | Out-of-Bounds Write (CWE-787) |
| **Impact** | Remote Code Execution (unauthenticated) |
| **CVSS 3.1** | 9.8 (AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H) |
| **Exploited ITW** | No |
| **Patch** | April 2023 Patch Tuesday (KB5025239 Win11 22H2) |

## BinDiff Summary

### Versions Compared

- **Pre-patch**: MQQM.dll 10.0.22621.963 (March 2023)
- **Post-patch**: MQQM.dll 10.0.22621.1555 (April 2023)

### Changed Functions

BinDiff revealed multiple functions with similarity < 1.00:

| Function | Change Type | Description |
|---|---|---|
| `CQmPacket::CQmPacket` | Code (8 feature-flag checks) | 8 instances of `GetNextSectionPtrSafe` replacing unsafe pointer arithmetic |
| `GetNextSectionPtrSafe` | New function | Validates calculated next-section pointer against packet length |
| `CEodHeader::GetNextSectionSafe` | New function | Safe variant for EodHeader section boundary |
| `CBaseHeader::SectionIsValid` | Code (validation added) | Additional section boundary checks |
| Feature flag functions | New | `MSRC76146_MSMQ_OOBRWFixes` flag check functions |

### Feature Flag Discovery

The patched binary contains symbols referencing MSRC case numbers as feature flags:

```
MSRC76146_MSMQ_OOBRWFixes
MSRC76146_MSMQ_KernelVariants
```

When enabled, the patched code path executes. When disabled, the original vulnerable code
runs. This reveals that the fix uses Windows Feature Store toggles.

## Vulnerability Overview

MQQM.dll is the core user-space component of the MSMQ service, loaded by `mqsvc.exe`.
It accepts data via TCP port 1801 using `WSARecv`. The `CQmPacket::CQmPacket` constructor
parses incoming MSMQ messages by iterating through a chain of section headers. Each section
specifies its own size, and the next section's location is computed by adding this size to
the current pointer. If the declared size is larger than the actual data, the calculated
pointer goes out of bounds.

## Root Cause — Insufficient Section Size Validation

### The Vulnerable Code (pre-patch)

In `CQmPacket::CQmPacket`, section pointers are computed by simple addition:

```c
// Pre-patch: Unsafe pointer arithmetic
// pEodHeader points to the current EodHeader section
// The total section size is computed from header fields
ULONG eodSize = pEodHeader->field_0x00 + pEodHeader->field_0x04 + 0xF;
PVOID pNextSection = (BYTE*)pEodHeader + eodSize;
// No check that pNextSection is still within the packet buffer!
```

This pattern repeats for multiple section types: EodHeader, SRMPEnvelopeHeader,
SoapHeader, and others. Each uses user-controlled size fields to compute the next
section pointer.

### The Patch (post-patch)

```c
// Post-patch: Safe pointer computation
if (MSRC76146_MSMQ_OOBRWFixes_enabled) {
    pNextSection = CEodHeader::GetNextSectionSafe(pEodHeader, packetLength);
    if (pNextSection == NULL) {
        // Section extends beyond packet boundary — reject
        goto error;
    }
} else {
    // Legacy unsafe path
    pNextSection = (BYTE*)pEodHeader + eodSize;
}
```

The new `GetNextSectionPtrSafe` function:

```c
PVOID GetNextSectionPtrSafe(PVOID currentSection, ULONG sectionSize, ULONG packetLength) {
    PVOID nextPtr = (BYTE*)currentSection + sectionSize;
    if (nextPtr > packetEndPtr || nextPtr < currentSection) {  // overflow check
        return NULL;  // Out of bounds — reject
    }
    return nextPtr;
}
```

### The Out-of-Bounds Write

After iterating through all sections, `CQmPacket::CQmPacket` appends an
`OnDiskExtensionHeader` at the computed end-of-message pointer. If any section's
size was malformed, this pointer points beyond the packet buffer:

```c
// At computed end-of-message (may be OOB)
pEndOfMessage->field_0x00 = 0x0000000C;              // Address + 0x00
pEndOfMessage->field_0x02 = 0x00000000;              // Address + 0x02
pEndOfMessage->field_0x12 = 0;                        // Address + 0x12
pEndOfMessage->field_0x1A = 0;                        // Address + 0x1A
pEndOfMessage->field_0x0E = 0x00000094;              // Address + 0x0E
pEndOfMessage->field_0x22 = 0;                        // Address + 0x22
pEndOfMessage->field_0x62 = 0;                        // Address + 0x62
memcpy(pEndOfMessage + 0xA6, &taAddress, addrLen+8); // TA_ADDRESS with client IP
```

## MSMQ Message Format

### BaseHeader (entry point)

```
┌──────────────────────────┐
│ VersionNumber (2 bytes)  │ Must be 0x10
│ Reserved (2 bytes)       │
│ Flags (4 bytes)          │ Bit field controlling section presence
│ Signature (4 bytes)      │ 0x4C494F52 ("LIOR")
│ PacketSize (4 bytes)     │ Total message size
│ TimeToReachQueue (4 bytes)│
└──────────────────────────┘
```

### Message Section Chain

```
BaseHeader → UserHeader → [SecurityHeader] → [PropertyHeader]
  → [DebugSection] → [SRMPEnvelopeHeader] → [CompoundMessageHeader]
  → [EodHeader] → [EodAckHeader] → [SoapHeader]
  → OnDiskExtensionHeader (appended at end)
```

Each section's presence is controlled by flags in the BaseHeader and UserHeader.
The vulnerability allows any section with user-controlled size to push the
end-of-message pointer beyond the packet buffer.

### EodHeader (trigger example)

```
┌──────────────────────────┐
│ field_0x00 (4 bytes)     │ Size component 1 (attacker-controlled)
│ field_0x04 (4 bytes)     │ Size component 2 (attacker-controlled)
│ ... (0x0F total minimum) │
└──────────────────────────┘

Total section size = field_0x00 + field_0x04 + 0x0F
```

The EodHeader flag bit is described as "reserved" in Microsoft documentation.

## Memory Management

### Packet Buffer Allocation

```
QmAcAllocatePacket → NtDeviceIoControl → mqac.sys
    └── Allocates buffer from mapped view of .mq file
        (C:\Windows\System32\msmq\storage\*.mq)
        Each .mq file can hold up to 4MB
        Multiple queues share the same file
```

Key implications for exploitation:
- Buffers are in file-mapped memory, NOT in process heap
- No heap objects to corrupt directly (unlike typical heap-based OOB)
- Heap grooming requires sending many messages to force adjacent heap allocations
- Requires queue send access (usually requires an open queue on the target)

### OOB Write Contents

The attacker has limited control over the written values:

| Offset | Value Written | Controllable? |
|---|---|---|
| +0x00 | 0x0000000C | No (constant) |
| +0x02 | 0x00000000 | No (zero) |
| +0x0E | 0x00000094 | No (constant) |
| +0x12 | 0x0000000000000000 | No (zero) |
| +0x1A | 0x0000000000000000 | No (zero) |
| +0x22 | 0x0000 | No (zero) |
| +0x62 | 0x0000 | No (zero) |
| +0xA6 | TA_ADDRESS (client IP) | Partially (source IP) |

The write offset from the buffer base IS fully controllable (via section size fields).

## Kernel Variants (mqac.sys)

Feature flag `MSRC76146_MSMQ_KernelVariants` in mqac.sys indicates analogous bugs in:
- `CPacketBuffer::MsgDeadletterHeader` / `MsgDeadletterHeaderSafe`
- `CPacketBuffer::MsgOnDiskExtensionHeader` / `MsgOnDiskExtensionHeaderSafe`

These parse the same MSMQ packet sections for dead-letter queue forwarding and
acknowledgement messages. The kernel driver operates on the same .mq file mapping,
not kernel pool, limiting kernel exploitation utility.

## Remote Patch Detection

An unpatched server can be detected remotely:

1. Send MSMQ message with HTTP flag set in UserHeader
2. Set SRMPEnvelopeHeader DataLength to a value that overflows when multiplied by 2
   (e.g., `DataLength * 2` wraps to equal actual data size)
3. **Patched**: Integer overflow detected → exception → no response
4. **Unpatched**: Overflow not detected → message processed → response sent

This allows safe remote scanning without triggering the OOB write.

## Detection

### YARA — Exploit Artifacts

```yara
rule CVE_2023_21554_QueueJumper_Exploit
{
    meta:
        description = "Detects tools exploiting CVE-2023-21554 MSMQ QueueJumper"
        cve         = "CVE-2023-21554"
        author      = "OnlyFm252"

    strings:
        $sig_lior    = { 4C 49 4F 52 }
        $port_1801   = { 09 07 }
        $s_msmq      = "MSMQ" ascii wide nocase
        $s_mqsvc     = "mqsvc" ascii wide nocase
        $s_mqqm      = "mqqm" ascii wide nocase
        $s_queue     = "QueueJumper" ascii wide nocase
        $s_eod       = "EodHeader" ascii wide
        $s_srmp      = "SRMPEnvelope" ascii wide

        $hex_packet  = { 10 00 00 00 ?? ?? ?? ?? 52 4F 49 4C }

    condition:
        uint16(0) == 0x5A4D and
        (
            ($sig_lior and ($s_msmq or $s_mqsvc or $s_mqqm)) or
            ($hex_packet and filesize < 1MB) or
            ($s_queue)
        )
}
```

### Sigma — MSMQ Service Exploitation Attempt

```yaml
title: CVE-2023-21554 MSMQ QueueJumper RCE Attempt
id: b2c3d4e5-f6a7-8901-bcde-f01234567890
status: experimental
description: >
    Detects potential exploitation of CVE-2023-21554 via unusual MSMQ
    service behavior including crashes or abnormal network connections.
author: OnlyFm252
date: 2026/07/26
references:
    - https://www.ibm.com/think/x-force/msmq-queuejumper-rce-vulnerability-technical-analysis
    - https://research.checkpoint.com/2023/queuejumper-critical-unauthorized-rce-vulnerability-in-msmq-service/
    - https://msrc.microsoft.com/update-guide/vulnerability/CVE-2023-21554
logsource:
    product: windows
    category: network_connection
detection:
    selection:
        DestinationPort: 1801
        Initiated: 'true'
    filter_legitimate:
        Image|endswith:
            - '\mqsvc.exe'
            - '\mmc.exe'
    condition: selection and not filter_legitimate
level: medium
tags:
    - attack.initial_access
    - attack.t1190
    - cve.2023.21554
```

### Sigma — MSMQ Service Crash

```yaml
title: CVE-2023-21554 MSMQ Service Crash Detection
id: c3d4e5f6-a7b8-9012-cdef-012345678901
status: experimental
description: Detects MSMQ service crashes that may indicate exploitation attempts.
author: OnlyFm252
date: 2026/07/26
logsource:
    product: windows
    service: system
detection:
    selection:
        Provider_Name: 'Service Control Manager'
        EventID: 7034
        param1|contains: 'Message Queuing'
    condition: selection
level: high
tags:
    - attack.initial_access
    - attack.t1190
    - cve.2023.21554
```

### Sysmon Configuration

```xml
<Sysmon schemaversion="4.90">
  <EventFiltering>
    <!-- Event 3: Detect inbound connections to MSMQ port 1801 -->
    <NetworkConnect onmatch="include">
      <DestinationPort condition="is">1801</DestinationPort>
    </NetworkConnect>

    <!-- Event 1: Detect mqsvc.exe child processes (post-exploitation) -->
    <ProcessCreate onmatch="include">
      <ParentImage condition="end with">\mqsvc.exe</ParentImage>
    </ProcessCreate>

    <!-- Event 11: Detect .mq file creation (message storage) -->
    <FileCreate onmatch="include">
      <TargetFilename condition="contains">\msmq\storage\</TargetFilename>
      <TargetFilename condition="end with">.mq</TargetFilename>
    </FileCreate>

    <!-- Event 7: Detect MQQM.dll loading -->
    <ImageLoad onmatch="include">
      <ImageLoaded condition="end with">\mqqm.dll</ImageLoaded>
    </ImageLoad>
  </EventFiltering>
</Sysmon>
```

## References

- [IBM X-Force — MSMQ QueueJumper (RCE Vulnerability): An In-Depth Technical Analysis](https://www.ibm.com/think/x-force/msmq-queuejumper-rce-vulnerability-technical-analysis)
- [Check Point Research — QueueJumper: Critical Unauthorized RCE in MSMQ](https://research.checkpoint.com/2023/queuejumper-critical-unauthorized-rce-vulnerability-in-msmq-service/)
- [Microsoft — MSMQ Message Format Specification](https://learn.microsoft.com/openspecs/windows_protocols/ms-mqqb/85498b96-f2c8-43b3-a108-c9d6269dc4af)
- [MSRC Advisory — CVE-2023-21554](https://msrc.microsoft.com/update-guide/vulnerability/CVE-2023-21554)
