13 min read
The security updates released by Microsoft on April 11, 2023, addressed over 90 individual vulnerabilities. Of particular note was CVE-2023-21554, dubbed QueueJumper, a remote code execution vulnerability affecting the Microsoft Message Queueing (MSMQ) service. MSMQ is an optional Windows component that enables applications to exchange messages via message queues that are reachable both locally and remotely. This analysis was performed in collaboration with the Randori and X-Force Adversary Services teams, by Valentina Palmiotti, Fabius Watson, and Aaron Portnoy.
The following qualities of CVE-2023-21554 drew initial attention:
Industry newsletter
Stay up to date on the most important—and intriguing—industry trends on AI, automation, data and beyond with the Think newsletter. See the IBM Privacy Statement.
Your subscription will be delivered in English. You will find an unsubscribe link in every newsletter. You can manage your subscriptions or unsubscribe here. Refer to our IBM Privacy Statement for more information.
To determine how to detect the presence of MSMQ, a test system was configured with the component in a lab environment. When connecting to the MSMQ endpoint on port 1801, the server did not respond with any data. It could be assumed the server will not reply without receiving reasonably-formed data. To understand how to conduct a conversation with the endpoint, further inspection of the underlying code was required.
From the advisory, it is not immediately clear which binary was patched. The first step to identifying the changed code was to download the update file. This was achieved by searching for KB5025224 in the Microsoft Update Catalog.
Microsoft Update Catalog search results for KB5025224
Specifically, the cumulative update file
windows10.0-kb5025224-x64_3522b1b562ed44bc949541dd1c7d08e1e967d925.msu
for Windows 11 for x86-based Systems was retrieved.
The 7-Zip extractor was used to unpack the contents of the MSU file and the CAB files it contained. Searching for the string “msmq” across all files in the resulting folders yielded the Container Index file,
Windows11.0-KB5025239-x64/express.psf.cix.xml,
which included the following entry:
<File id="21296" name="amd64_microsoft-windows-msmq-queuemanager-core_31bf3856ad364e35_10.0.22621.1555_none_5f975f8fdb349517\f\mqqm.dll" length="34811" time="133245266510000000" attr="128">
This entry references
To identify the changes made between the patched and unpatched versions of theMQQM.dll
1.00
BinDiff results between patched and unpatched MQQM.dll files
Analysis of these functions using Hex-Rays Decompiler revealed symbols for the patched version containing verbose function names that appear to reference Microsoft Security Research Center (MSRC) vulnerability identifiers:
Feature flag symbols within MQQM.dll
After closer inspection, the symbols containing MSRC case numbers correspond to feature flags for vulnerability fixes. Feature flags are a component of Windows that toggle various functionality and experiments. Here, the discovered “feature” is actually a patch for a vulnerability. If the feature is enabled, the secure, patched code path is executed. Otherwise, the original unpatched code path is executed.
Decompiled code snippet showing feature flag for vulnerability fix
A feature-flag check was present for each of the vulnerabilities that comprised CVE-2023-21554 in both the user and kernel components. Analysis of the remaining binaries contained in the security update package revealed that feature flags were also introduced for most or all of the vulnerabilities fixed on April 2023 Patch Tuesday.
Cross-referencing these flags helped us quickly pinpoint the patched code locations. In particular, the changes within
which related to theMSRC76146_MSMQ_OOBRWF
ixes
flag seemed of most interest.
The check for this feature-flag occurs eight times within the function. One such check is depicted below:
Decompiled code snippet showing vulnerability fix
In the decompiled code snippet shown above, the patched code path obtains the pointer to the next section of the MSMQ message via a call to
Decompilation snippet of GetNextSectionPtrSafe function
After examining all the occurrences of this feature-flag and others, it was determined that CVE-2023-21554 consists of several bugs which insufficiently check the size of various MSMQ message section types. These vulnerabilities allow the pointer to the end of the MSMQ message to be incremented by an arbitrary 32-bit offset to outside the bounds of the originally allocated buffer.
Following packet processing, the final step in
Out of Bound memory access check for message end
While evaluating the exploitability of the vulnerabilities, additional kernel vulnerabilities were identified in the corresponding kernel driver for the MSMQ service,
. The vulnerabilities were again indicated by feature-flag symbols, which also reference MSRC case 76146 as observed in
.
Feature flag symbols within mqac.sys
Analysis of the
In order to perform the associated operations, the kernel component parses various sections of the MSMQ packet buffer. Two such instances are pictured below:
Decompiled code snippet showing feature flag for vulnerability fix in kernel driver mqac.sys
As seen in the decompiled code snippet above, if the feature-flag is enabled, the “safe” functions
The majority of the code related to protocol parsing is located within the
library, which is loaded by themqsvc.exe
, a valid MSMQ request must be sent from the client. The MSMQ message specification and protocol is vast and complex. Initially, public code was found for scanning MSMQ servers in a GitHub gist that provided the basis for more in depth exploration of the packet processing. In addition, the Microsoft documentation was helpful for understanding the MSMQ message format.
The code within the DLL accepts data through port 1801 using a call to the WSARecv function, as can be seen in the debugging session below:
0:020> bp ws2_32!wsarecv ; g
Breakpoint 0 hit
WS2_32!WSARecv:
00007ffd`651115c0 48895c2408 mov qword ptr [rsp+8],rbx ss:000000aa`f07fef30=0000000000000006
0:019> k
# Child-SP RetAddr Call Site
00 000000aa`f07fef28 00007ffd`57ba9cb0 WS2_32!WSARecv
01 000000aa`f07fef30 00007ffd`57b9683d
MQQM!NoReceivePartialBuffer+0x38
02 000000aa`f07fefb0 00007ffd`57b2078e MQQM!CWinsockConnection::ReceivePartialBuffer+0x7d
03 000000aa`f07ff010 00007ffd`57b25b28
MQQM!CSockTransport::BeginReceive+0xe6
04 000000aa`f07ff060 00007ffd`57b2d40b
MQQM!CSockTransport::NewSession+0x194
05 000000aa`f07ff3f0 00007ffd`57b2d367 MQQM!CSessionMgr::AcceptSockSession+0x6f
06 000000aa`f07ff430 00007ffd`645e26bd MQQM!AcceptIPThread+0x6a7
07 000000aa`f07ff7d0 00007ffd`6650a9f8
KERNEL32!BaseThreadInitThunk+0x1d
08 000000aa`f07ff800 00000000`00000000 ntdll!RtlUserThreadStart+0x28
0:019> r @$t0=@rdx
0:019> pt
WS2_32!WSARecv+0x19f:
00007ffd`6511175f c3 ret
0:019> dc poi(@$t0+8) LC
000001b5`880ff490 62f06110 524f494c 00000070 5a5a5a5a .a.bLIORp…ZZZZ
000001b5`880ff4a0 0073006e 00610074 0063006e 00200065 n.s.t.a.n.c.e. .
000001b5`880ff4b0 00440049 00000000 00000000 00000000 I.D………….
0:019> ba r1 poi(@$t0+8) ; g
Breakpoint 1 hit
MQQM!CBaseHeader::SectionIsValid+0x154:
00007ffd`57b53450 7462 je
MQQM!CBaseHeader::SectionIsValid+0x1b8 (00007ffd`57b534b4) [br=1]
The
function is responsible for parsing the beginning of a new message, which starts with a BaseHeader structure of the form:
Structure of the BaseHeader object
The incoming message fields are validated by
Disassembly code for SectionIsValid within MQQM.dll
After initial validation, the majority of the protocol parsing occurs within the
Decompilation showing vulnerability in handling of EodHeader
The above decompilation shows the patched path calling the function named
The structure of an
Disassembly calculating total size of EodHeader section
In the disassembly above, the pointer to the beginning of the
WinDbg session showing an access violation when writing to the end of a malformed MSMQ message
To evaluate the strength of the out-of-bounds write obtained by the vulnerabilities, we first investigated the allocation and management of the underlying memory.
Before aMSMQ
. This function calls into the
kernel driver viaNtDeviceIoControl
.
Decompilation of packet buffer allocation function
The kernel component returns a buffer that is partitioned from a mapped view of a file on disk, stored in the
ProcessHacker memory layout of MQSVC process showing packet buffer memory is a file mapping
The packet buffer address, along with a randomized packet handle, is returned to user space following the allocation request via IOCTL. The driver uses the handle to calculate the packet buffer address when handling requests from user space.
The backing memory for the vulnerable buffers is within a mapped file, and thus not in a heap of the process. Additionally, the affected memory does not store any objects. The only thing that is contained in the file mapping is the contents of MSMQ messages along with metadata that is stored in the
Furthermore, without prior knowledge of the memory layout it is not possible to know the relative positioning of the file mapping to the process’ heap in order to overwrite object pointers. Therefore, in order to feasibly obtain remote code execution, we require some method for shaping the memory into a predictable position.
After experimenting with sending legitimate MSMQ messages to the target, it was discovered that it is possible to force a new heap allocation adjacent to a
Memory layout of MQSVC process showing a new heap allocated adjacently to a MQ file mapping
However, this requires that the attacker have access to send messages to a least one queue on the target, otherwise, the messages will be discarded and overwritten and therefore do not occupy packet memory persistently.
In the conducted research experimentation, it was discovered that it is possible for an unprivileged user to create a queue that is open to anyone to send messages remotely, by default. The queue persists on the system indefinitely. Although most modern uses of MSMQ exist as optional components and adapters, vendors such Oracle, Veritas, and Xerox offer enterprise software that rely on MSMQ as a core dependency. Therefore, the attack scenario is not unrealistic.
The out-of-bound memory access vulnerability introduces an exploit primitive that allows a
malicious client to write anOnDiskExtensionHeader
allocated for the packet.
When assessing a vulnerability that allows for writing values to an offset, some properties
must be considered:
In the case of the QueueJumper vulnerabilities, the offset of allocated buffer to the OOB write is controllable because it is calculated using attacker-controlled data. The contents of the OOB write, however, has limited control.
Here,Address
header will be written. The series of operations that occur is as follows:
0x000000000000000C
is written toAddress
0x00000000
Address+0x2
0x0000000000000000
Address+0x12
0x0000000000000000
is written to Address+0x1A
0x00000094
is written Address+0xE
0x0000
Address+0x22
0x0000
is written to Address+0x62
memcpy(Address+0xA6, Source, Source->AddressLength+0x08)
TheSource
memcpy
structure defines a single transport address of a specific type (for example, NetBIOS). The definition follows:
typedef struct _TA_ADDRESS {
USHORT AddressLength;;
USHORT AddressType; Info;
UCHAR Address[1];;
} TA_ADDRESS, *PTA_ADDRESS;
Specifies the number of bytes in an address of the specified AddressType.
Specifies the type of the transport address.
Specifies a variable-sized array containing the transport address.
In a debugging session below,TA_ADDRESS
rax=0000014e1d110180 rbx=0000014e1d110180 rcx=0000014e1d110184
rdx=0000014e1ce86b10 rsi=0000014e1d110001 rdi=0000000545d7fa50
rip=00007ff843208074 rsp=0000000545d7f940 rbp=0000000545d7f980
r8=000000000000000c r9=0000000000000002 r10=0000000000000000
r11=0000000545d7f938 r12=0000000000000002 r13=0000000000001000
r14=0000014e1ce86b10 r15=0000000000000000
iopl=0 nv up ei pl nz na po nc
cs=0033 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000206
MQQM!CQmPacket::CQmPacket+0x89c:
00007ff8`43208074 e8a5780a00 call MQQM!memcpy (00007ff8`432af91e)
0:017> dc rcx
0000014e`1d110184 00010004 00000000 8620a8c0 00000000 ………. …..
Above, theTA_ADDRESS
, a type of1
. Converting each byte to an IPv4 octet yields the address
, which is the IPv4 source address of the client.
This scenario allows for the writing of attacker-controlled data via a source address to a controlled offset from the packet allocation in memory. While very restrictive and possibly impractical, this could theoretically be used to precisely control the values written to memory by making multiple requests from varying source addresses at decrementing packet offsets.
Because of the number of limitations encountered to achieve blind remote code execution, alternative attack scenarios, such as information leaks, were investigated.
One attack that was considered was corrupting the pointer to a specific message section to point to out-of-bounds memory and then later retrieving the message to read the adjacent memory.
However, the beginning of each section parsing does a check on the position of the current section, therefore we cannot trick the parsing logic into parsing a data section that is out of bounds.
Another possible attack scenario is to overwrite the OnDiskExtensionHeader
of another message to trick the recipient of the message of the origins of the received message. Similarly, it’s possible to overwrite the contents of messages intended for queues that the attacker does not have access to. Overwriting specific contents of a message would require the attacker to have information about the message, such as its size.
There is an optional section named SoapHeader
that is susceptible to out-of-bounds data access, with the following format:
SoapHeader packet format
It was observed that the memory used to store MSMQ packet data is not properly cleared when the buffer is freed. As a result, sending an MSMQ packet that is smaller in size than a prior MSMQ packet will result in a memory layout contained the current packet’s data followed by data from previously processed MSMQ packets.
It was discovered that the
The limited control in write contents with the additional non-controlled writes corrupting adjacent memory, along with limited knowledge in message layout proved to be a big obstacle in exploitation.
At the time of analysis, only the user space vulnerabilities involved in the initial processing of a MSMQ message packet were evaluated for exploitability. Analysis of the kernel variant vulnerabilities could uncover additional exploitation avenues. For example, it is possible including a malformed header could gain a write primitive in the kernel memory mapping of the
file. In some cases, checks in user space processing prevent the kernel from performing some post-processing operations.
Additionally, in the case of the kernel variants the attacker has less direct control over message contents and is also operating on the same file mapping as user space, not in a kernel pool (heap). Mitigations, such as KASLR, also present obstacles that are difficult to overcome for remote exploitation.
Due to the implementation of the patched code, a remote client can safely determine if a system has applied the update. This can be done by sending a MSMQ message that triggers the vulnerability, but does not actually cause an out of bound access, thus not crashing the service process. If the HTTP flag is set in the UserHeader of the message, a SRMPEnvelopeHeader is expected. In the patch, a check for an integer overflow is performed on the
field multiplied by 2. This length can be set so that the result of the multiplication overflows to a small number equal to the actual size of the data.
Decompiled code snippet showing integer overflow check on SRMPEnvelopeHeader DataLength
If the target is patched, the vulnerability causes an exception to be thrown and the server will abort the processing of the message, thus no response is sent back to the client. If it is not patched, the server will process the message normally and send a response.
Due to the location backing memory of the vulnerable buffers, remote code execution seems more feasible for an attacker with the ability to send messages to any queue on the target. In this scenario, it is possible to groom so that an adjacent heap is allocated. The extremely limited control over write contents presents challenges for remote exploitation. Because of mitigations like ASLR, an information leak must also be obtained. It is possible that a single write of a constant (0xC
, 0x0
Ultimately, we conclude that while the remote exploitation of QueueJumper may not be impossible, the aforementioned requirements make it difficult to accomplish. This blog post only scratches the surface of what is a very complex message specification, service, and protocol. Further vulnerability research into both the user space and kernel component operations is warranted.