diff --git a/modules/auxiliary/scanner/msmq/cve_2023_21554_queuejumper.rb b/modules/auxiliary/scanner/msmq/cve_2023_21554_queuejumper.rb
index 02ed23948d24..0598e2bbc1d0 100644
--- a/modules/auxiliary/scanner/msmq/cve_2023_21554_queuejumper.rb
+++ b/modules/auxiliary/scanner/msmq/cve_2023_21554_queuejumper.rb
@@ -3,6 +3,8 @@
 # Current source: https://github.com/rapid7/metasploit-framework
 ##
 
+require 'bindata'
+
 class MetasploitModule < Msf::Auxiliary
   include Msf::Exploit::Remote::Tcp
   include Msf::Auxiliary::Scanner
@@ -48,137 +50,85 @@ def initialize(info = {})
 
   # Preparing message struct according to https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-mqrr/f9e71595-339a-4cc4-8341-371e0a4cb232
 
-  def base_header
+  class BaseHeader < BinData::Record
     # BaseHeader (https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-mqmq/058cdeb4-7a3c-405b-989c-d32b9d6bddae)
     #
     # Simple header containing a static signature, packet size, some flags and some sort of timeout value for the message to arrive
     #
-    # Fields: VersionNumber(1), Reserved(1), Flags(2), Signature(4), PacketSize(4), TimeToReachQueue(4)
 
-    "\x10\x00\x03\x10\x4c\x49\x4f\x52\x64\x09\x00\x00\x63\x76\x09\x6c"
+    endian :big
+
+    uint8 :version_number
+    uint8 :reserved
+    uint16 :flags
+    uint32 :signature
+    uint32le :packet_size
+    uint32le :time_to_reach_queue
   end
 
-  def user_header
+  class UserHeader < BinData::Record
     # UserHeader (https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-mqmq/056b43bc-2466-4342-8504-1630310d5965)
     #
     # The UserHeader is an essential header that defines the destination, message id,
     # source, sent time and expiration time
     #
-    # Fields: SourceQueueManager(16), QueueManagerAddress(16), TimeToBeReceived(4), SentTime(4),
-    #         MessageID(4), Flags(4), DestinationQueue(16),  DestinationQueue(2), Padding(2)
-
-    "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
-    "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
-    "\x00\x00\x00\x00\x63\xaa\xbe\x64\x01\x00\x00\x00\x01\x1c\x20\x02" \
-    "\x60\x00\x68\x00\x74\x00\x74\x00\x70\x00\x3a\x00\x2f\x00\x2f\x00" \
-    "\x31\x00\x39\x00\x32\x00\x2e\x00\x31\x00\x36\x00\x38\x00\x2e\x00" \
-    "\x35\x00\x36\x00\x2e\x00\x31\x00\x31\x00\x33\x00\x2f\x00\x6d\x00" \
-    "\x73\x00\x6d\x00\x71\x00\x2f\x00\x70\x00\x72\x00\x69\x00\x76\x00" \
-    "\x61\x00\x74\x00\x65\x00\x24\x00\x2f\x00\x71\x00\x75\x00\x65\x00" \
-    "\x75\x00\x65\x00\x6a\x00\x75\x00\x6d\x00\x70\x00\x65\x00\x72\x00" \
-    "\x00\x00\x00\x00"
+
+    endian :big
+
+    string :source_queue_manager, length: 16
+    string :queue_manager_address, length: 16
+    uint32le :time_to_be_received
+    uint32le :sent_time
+    uint32le :message_id
+    uint32 :flags
+    uint16le :destination_queue_length
+    string :destination_queue
+    string :padding
   end
 
-  def message_properties_header
+  class MessagePropertiesHeader < BinData::Record
     # MessagePropertiesHeader (https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-mqmq/b219bdf4-1bf6-4688-94d8-25fdba45e5ec)
     #
     # This header contains meta information about the message like its label,
     # message size and whether encryption is used.
     #
-    # Fields: Flags(1), LabelLength(1), MessageClass(2), CorrelationID(8), CorrelationID(12),
-    #         BodyType(4), ApplicationTag(4), MessageSize(4), AllocationBodySize(4), PrivacyLevel(4),
-    #         HashAlgorithm(4), EncryptionAlgorithm(4), ExtensionSize(4), Label (8)
-
-    "\x00\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
-    "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
-    "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
-    "\x00\x00\x00\x00\x00\x00\x00\x00\x70\x00\x6f\x00\x63\x00\x00\x00"
+
+    endian :big
+
+    uint8  :flags
+    uint8  :label_length
+    uint16 :message_class
+    string :correlation_id, length: 20
+    uint32 :body_type
+    uint32 :application_tag
+    uint32 :message_size
+    uint32 :allocation_body_size
+    uint32 :privacy_level
+    uint32 :hash_algorithm
+    uint32 :encryption_algorithm
+    uint32 :extension_size
+    string :label
   end
 
-  def srmp_envelope_header
+  class SRMPEnvelopeHeader < BinData::Record
     # SRMPEnvelopeHeader (https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-mqrr/062b8317-2ade-4b1c-804d-1674b2fdcad3)
     #
     # This header contains information about the SOAP envelope of the message.
     # It includes information about destination queue, label, message and sent
     # or expiration dates.
     # The Data field contains a SRMP Message Structure (https://learn.microsoft.com/en-us/openspecs/windows_protocols/mc-mqsrm/38cfc717-c703-46aa-a145-34f60b79399b)
-    # The DataLength field is modified by this module to cause an integer overflow,
-    # however the module makes sure that in case of a vulnerable system the
-    # resulting length is identical to the previous one to prevent actual crashes.
     #
-    # Fields: HeaderId(2), Reserved(2), Datalength(4), Data(1078), Padding(2)
-
-    "\x00\x00\x00\x00\x1b\x02\x00\x00\x3c\x00\x73\x00\x65\x00\x3a\x00" \
-    "\x45\x00\x6e\x00\x76\x00\x65\x00\x6c\x00\x6f\x00\x70\x00\x65\x00" \
-    "\x20\x00\x78\x00\x6d\x00\x6c\x00\x6e\x00\x73\x00\x3a\x00\x73\x00" \
-    "\x65\x00\x3d\x00\x22\x00\x68\x00\x74\x00\x74\x00\x70\x00\x3a\x00" \
-    "\x2f\x00\x2f\x00\x73\x00\x63\x00\x68\x00\x65\x00\x6d\x00\x61\x00" \
-    "\x73\x00\x2e\x00\x78\x00\x6d\x00\x6c\x00\x73\x00\x6f\x00\x61\x00" \
-    "\x70\x00\x2e\x00\x6f\x00\x72\x00\x67\x00\x2f\x00\x73\x00\x6f\x00" \
-    "\x61\x00\x70\x00\x2f\x00\x65\x00\x6e\x00\x76\x00\x65\x00\x6c\x00" \
-    "\x6f\x00\x70\x00\x65\x00\x2f\x00\x22\x00\x20\x00\x0d\x00\x0a\x00" \
-    "\x78\x00\x6d\x00\x6c\x00\x6e\x00\x73\x00\x3d\x00\x22\x00\x68\x00" \
-    "\x74\x00\x74\x00\x70\x00\x3a\x00\x2f\x00\x2f\x00\x73\x00\x63\x00" \
-    "\x68\x00\x65\x00\x6d\x00\x61\x00\x73\x00\x2e\x00\x78\x00\x6d\x00" \
-    "\x6c\x00\x73\x00\x6f\x00\x61\x00\x70\x00\x2e\x00\x6f\x00\x72\x00" \
-    "\x67\x00\x2f\x00\x73\x00\x72\x00\x6d\x00\x70\x00\x2f\x00\x22\x00" \
-    "\x3e\x00\x0d\x00\x0a\x00\x3c\x00\x73\x00\x65\x00\x3a\x00\x48\x00" \
-    "\x65\x00\x61\x00\x64\x00\x65\x00\x72\x00\x3e\x00\x0d\x00\x0a\x00" \
-    "\x20\x00\x3c\x00\x70\x00\x61\x00\x74\x00\x68\x00\x20\x00\x78\x00" \
-    "\x6d\x00\x6c\x00\x6e\x00\x73\x00\x3d\x00\x22\x00\x68\x00\x74\x00" \
-    "\x74\x00\x70\x00\x3a\x00\x2f\x00\x2f\x00\x73\x00\x63\x00\x68\x00" \
-    "\x65\x00\x6d\x00\x61\x00\x73\x00\x2e\x00\x78\x00\x6d\x00\x6c\x00" \
-    "\x73\x00\x6f\x00\x61\x00\x70\x00\x2e\x00\x6f\x00\x72\x00\x67\x00" \
-    "\x2f\x00\x72\x00\x70\x00\x2f\x00\x22\x00\x20\x00\x73\x00\x65\x00" \
-    "\x3a\x00\x6d\x00\x75\x00\x73\x00\x74\x00\x55\x00\x6e\x00\x64\x00" \
-    "\x65\x00\x72\x00\x73\x00\x74\x00\x61\x00\x6e\x00\x64\x00\x3d\x00" \
-    "\x22\x00\x31\x00\x22\x00\x3e\x00\x0d\x00\x0a\x00\x20\x00\x20\x00" \
-    "\x20\x00\x3c\x00\x61\x00\x63\x00\x74\x00\x69\x00\x6f\x00\x6e\x00" \
-    "\x3e\x00\x4d\x00\x53\x00\x4d\x00\x51\x00\x3a\x00\x70\x00\x6f\x00" \
-    "\x63\x00\x3c\x00\x2f\x00\x61\x00\x63\x00\x74\x00\x69\x00\x6f\x00" \
-    "\x6e\x00\x3e\x00\x0d\x00\x0a\x00\x20\x00\x20\x00\x20\x00\x3c\x00" \
-    "\x74\x00\x6f\x00\x3e\x00\x68\x00\x74\x00\x74\x00\x70\x00\x3a\x00" \
-    "\x2f\x00\x2f\x00\x31\x00\x39\x00\x32\x00\x2e\x00\x31\x00\x36\x00" \
-    "\x38\x00\x2e\x00\x35\x00\x36\x00\x2e\x00\x31\x00\x31\x00\x33\x00" \
-    "\x2f\x00\x6d\x00\x73\x00\x6d\x00\x71\x00\x2f\x00\x70\x00\x72\x00" \
-    "\x69\x00\x76\x00\x61\x00\x74\x00\x65\x00\x24\x00\x2f\x00\x71\x00" \
-    "\x75\x00\x65\x00\x75\x00\x65\x00\x6a\x00\x75\x00\x6d\x00\x70\x00" \
-    "\x65\x00\x72\x00\x3c\x00\x2f\x00\x74\x00\x6f\x00\x3e\x00\x0d\x00" \
-    "\x0a\x00\x20\x00\x20\x00\x20\x00\x3c\x00\x69\x00\x64\x00\x3e\x00" \
-    "\x75\x00\x75\x00\x69\x00\x64\x00\x3a\x00\x31\x00\x40\x00\x30\x00" \
-    "\x30\x00\x30\x00\x30\x00\x30\x00\x30\x00\x30\x00\x30\x00\x2d\x00" \
-    "\x30\x00\x30\x00\x30\x00\x30\x00\x2d\x00\x30\x00\x30\x00\x30\x00" \
-    "\x30\x00\x2d\x00\x30\x00\x30\x00\x30\x00\x30\x00\x2d\x00\x30\x00" \
-    "\x30\x00\x30\x00\x30\x00\x30\x00\x30\x00\x30\x00\x30\x00\x30\x00" \
-    "\x30\x00\x30\x00\x30\x00\x3c\x00\x2f\x00\x69\x00\x64\x00\x3e\x00" \
-    "\x0d\x00\x0a\x00\x20\x00\x3c\x00\x2f\x00\x70\x00\x61\x00\x74\x00" \
-    "\x68\x00\x3e\x00\x0d\x00\x0a\x00\x20\x00\x3c\x00\x70\x00\x72\x00" \
-    "\x6f\x00\x70\x00\x65\x00\x72\x00\x74\x00\x69\x00\x65\x00\x73\x00" \
-    "\x20\x00\x73\x00\x65\x00\x3a\x00\x6d\x00\x75\x00\x73\x00\x74\x00" \
-    "\x55\x00\x6e\x00\x64\x00\x65\x00\x72\x00\x73\x00\x74\x00\x61\x00" \
-    "\x6e\x00\x64\x00\x3d\x00\x22\x00\x31\x00\x22\x00\x3e\x00\x0d\x00" \
-    "\x0a\x00\x20\x00\x20\x00\x20\x00\x3c\x00\x65\x00\x78\x00\x70\x00" \
-    "\x69\x00\x72\x00\x65\x00\x73\x00\x41\x00\x74\x00\x3e\x00\x32\x00" \
-    "\x30\x00\x32\x00\x37\x00\x30\x00\x36\x00\x30\x00\x39\x00\x54\x00" \
-    "\x31\x00\x36\x00\x34\x00\x34\x00\x31\x00\x39\x00\x3c\x00\x2f\x00" \
-    "\x65\x00\x78\x00\x70\x00\x69\x00\x72\x00\x65\x00\x73\x00\x41\x00" \
-    "\x74\x00\x3e\x00\x0d\x00\x0a\x00\x20\x00\x20\x00\x20\x00\x3c\x00" \
-    "\x73\x00\x65\x00\x6e\x00\x74\x00\x41\x00\x74\x00\x3e\x00\x32\x00" \
-    "\x30\x00\x32\x00\x33\x00\x30\x00\x37\x00\x32\x00\x34\x00\x54\x00" \
-    "\x31\x00\x36\x00\x34\x00\x34\x00\x31\x00\x39\x00\x3c\x00\x2f\x00" \
-    "\x73\x00\x65\x00\x6e\x00\x74\x00\x41\x00\x74\x00\x3e\x00\x0d\x00" \
-    "\x0a\x00\x20\x00\x3c\x00\x2f\x00\x70\x00\x72\x00\x6f\x00\x70\x00" \
-    "\x65\x00\x72\x00\x74\x00\x69\x00\x65\x00\x73\x00\x3e\x00\x0d\x00" \
-    "\x0a\x00\x3c\x00\x2f\x00\x73\x00\x65\x00\x3a\x00\x48\x00\x65\x00" \
-    "\x61\x00\x64\x00\x65\x00\x72\x00\x3e\x00\x0d\x00\x0a\x00\x3c\x00" \
-    "\x73\x00\x65\x00\x3a\x00\x42\x00\x6f\x00\x64\x00\x79\x00\x3e\x00" \
-    "\x3c\x00\x2f\x00\x73\x00\x65\x00\x3a\x00\x42\x00\x6f\x00\x64\x00" \
-    "\x79\x00\x3e\x00\x0d\x00\x0a\x00\x3c\x00\x2f\x00\x73\x00\x65\x00" \
-    "\x3a\x00\x45\x00\x6e\x00\x76\x00\x65\x00\x6c\x00\x6f\x00\x70\x00" \
-    "\x65\x00\x3e\x00\x0d\x00\x0a\x00\x0d\x00\x0a\x00\x00\x00\x64\x00"
+
+    endian :big
+
+    uint16  :header_id
+    uint16  :reserved
+    uint32le :data_length
+    string :data
+    string :padding
   end
 
-  def compound_message_header
+  class CompoundMessageHeader < BinData::Record
     # CompoundMessageHeader (https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-mqrr/ecf70c09-d312-4afc-9e2c-f61a5c827f47)
     #
     # This header contains information about the SRMP compound message.
@@ -186,109 +136,206 @@ def compound_message_header
     # body that defines parameters like the message destination, sent date,
     # label and some more.
     #
-    # Fields:
-    #   HeaderId(2), Reserved(2), HTTPBodySize(4), MsgBodySize(4), MsgBodyOffset(4), Data(1060)
-
-    "\xf4\x01\x00\x00\x24\x04\x00\x00\x07\x00\x00\x00\xe3\x03\x00\x00" \
-    "\x50\x4f\x53\x54\x20\x2f\x6d\x73\x6d\x71\x20\x48\x54\x54\x50\x2f" \
-    "\x31\x2e\x31\x0d\x0a\x43\x6f\x6e\x74\x65\x6e\x74\x2d\x4c\x65\x6e" \
-    "\x67\x74\x68\x3a\x20\x38\x31\x36\x0d\x0a\x43\x6f\x6e\x74\x65\x6e" \
-    "\x74\x2d\x54\x79\x70\x65\x3a\x20\x6d\x75\x6c\x74\x69\x70\x61\x72" \
-    "\x74\x2f\x72\x65\x6c\x61\x74\x65\x64\x3b\x20\x62\x6f\x75\x6e\x64" \
-    "\x61\x72\x79\x3d\x22\x4d\x53\x4d\x51\x20\x2d\x20\x53\x4f\x41\x50" \
-    "\x20\x62\x6f\x75\x6e\x64\x61\x72\x79\x2c\x20\x35\x33\x32\x38\x37" \
-    "\x22\x3b\x20\x74\x79\x70\x65\x3d\x74\x65\x78\x74\x2f\x78\x6d\x6c" \
-    "\x0d\x0a\x48\x6f\x73\x74\x3a\x20\x31\x39\x32\x2e\x31\x36\x38\x2e" \
-    "\x35\x36\x2e\x31\x31\x33\x0d\x0a\x53\x4f\x41\x50\x41\x63\x74\x69" \
-    "\x6f\x6e\x3a\x20\x22\x4d\x53\x4d\x51\x4d\x65\x73\x73\x61\x67\x65" \
-    "\x22\x0d\x0a\x50\x72\x6f\x78\x79\x2d\x41\x63\x63\x65\x70\x74\x3a" \
-    "\x20\x4e\x6f\x6e\x49\x6e\x74\x65\x72\x61\x63\x74\x69\x76\x65\x43" \
-    "\x6c\x69\x65\x6e\x74\x0d\x0a\x0d\x0a\x2d\x2d\x4d\x53\x4d\x51\x20" \
-    "\x2d\x20\x53\x4f\x41\x50\x20\x62\x6f\x75\x6e\x64\x61\x72\x79\x2c" \
-    "\x20\x35\x33\x32\x38\x37\x0d\x0a\x43\x6f\x6e\x74\x65\x6e\x74\x2d" \
-    "\x54\x79\x70\x65\x3a\x20\x74\x65\x78\x74\x2f\x78\x6d\x6c\x3b\x20" \
-    "\x63\x68\x61\x72\x73\x65\x74\x3d\x55\x54\x46\x2d\x38\x0d\x0a\x43" \
-    "\x6f\x6e\x74\x65\x6e\x74\x2d\x4c\x65\x6e\x67\x74\x68\x3a\x20\x36" \
-    "\x30\x36\x0d\x0a\x0d\x0a\x3c\x73\x65\x3a\x45\x6e\x76\x65\x6c\x6f" \
-    "\x70\x65\x20\x78\x6d\x6c\x6e\x73\x3a\x73\x65\x3d\x22\x68\x74\x74" \
-    "\x70\x3a\x2f\x2f\x73\x63\x68\x65\x6d\x61\x73\x2e\x78\x6d\x6c\x73" \
-    "\x6f\x61\x70\x2e\x6f\x72\x67\x2f\x73\x6f\x61\x70\x2f\x65\x6e\x76" \
-    "\x65\x6c\x6f\x70\x65\x2f\x22\x20\x0d\x0a\x78\x6d\x6c\x6e\x73\x3d" \
-    "\x22\x68\x74\x74\x70\x3a\x2f\x2f\x73\x63\x68\x65\x6d\x61\x73\x2e" \
-    "\x78\x6d\x6c\x73\x6f\x61\x70\x2e\x6f\x72\x67\x2f\x73\x72\x6d\x70" \
-    "\x2f\x22\x3e\x0d\x0a\x3c\x73\x65\x3a\x48\x65\x61\x64\x65\x72\x3e" \
-    "\x0d\x0a\x20\x3c\x70\x61\x74\x68\x20\x78\x6d\x6c\x6e\x73\x3d\x22" \
-    "\x68\x74\x74\x70\x3a\x2f\x2f\x73\x63\x68\x65\x6d\x61\x73\x2e\x78" \
-    "\x6d\x6c\x73\x6f\x61\x70\x2e\x6f\x72\x67\x2f\x72\x70\x2f\x22\x20" \
-    "\x73\x65\x3a\x6d\x75\x73\x74\x55\x6e\x64\x65\x72\x73\x74\x61\x6e" \
-    "\x64\x3d\x22\x31\x22\x3e\x0d\x0a\x20\x20\x20\x3c\x61\x63\x74\x69" \
-    "\x6f\x6e\x3e\x4d\x53\x4d\x51\x3a\x70\x6f\x63\x3c\x2f\x61\x63\x74" \
-    "\x69\x6f\x6e\x3e\x0d\x0a\x20\x20\x20\x3c\x74\x6f\x3e\x68\x74\x74" \
-    "\x70\x3a\x2f\x2f\x31\x39\x32\x2e\x31\x36\x38\x2e\x35\x36\x2e\x31" \
-    "\x31\x33\x2f\x6d\x73\x6d\x71\x2f\x70\x72\x69\x76\x61\x74\x65\x24" \
-    "\x2f\x71\x75\x65\x75\x65\x6a\x75\x6d\x70\x65\x72\x3c\x2f\x74\x6f" \
-    "\x3e\x0d\x0a\x20\x20\x20\x3c\x69\x64\x3e\x75\x75\x69\x64\x3a\x31" \
-    "\x40\x30\x30\x30\x30\x30\x30\x30\x30\x2d\x30\x30\x30\x30\x2d\x30" \
-    "\x30\x30\x30\x2d\x30\x30\x30\x30\x2d\x30\x30\x30\x30\x30\x30\x30" \
-    "\x30\x30\x30\x30\x30\x3c\x2f\x69\x64\x3e\x0d\x0a\x20\x3c\x2f\x70" \
-    "\x61\x74\x68\x3e\x0d\x0a\x20\x3c\x70\x72\x6f\x70\x65\x72\x74\x69" \
-    "\x65\x73\x20\x73\x65\x3a\x6d\x75\x73\x74\x55\x6e\x64\x65\x72\x73" \
-    "\x74\x61\x6e\x64\x3d\x22\x31\x22\x3e\x0d\x0a\x20\x20\x20\x3c\x65" \
-    "\x78\x70\x69\x72\x65\x73\x41\x74\x3e\x32\x30\x32\x37\x30\x36\x30" \
-    "\x39\x54\x31\x36\x34\x34\x31\x39\x3c\x2f\x65\x78\x70\x69\x72\x65" \
-    "\x73\x41\x74\x3e\x0d\x0a\x20\x20\x20\x3c\x73\x65\x6e\x74\x41\x74" \
-    "\x3e\x32\x30\x32\x33\x30\x37\x32\x34\x54\x31\x36\x34\x34\x31\x39" \
-    "\x3c\x2f\x73\x65\x6e\x74\x41\x74\x3e\x0d\x0a\x20\x3c\x2f\x70\x72" \
-    "\x6f\x70\x65\x72\x74\x69\x65\x73\x3e\x0d\x0a\x3c\x2f\x73\x65\x3a" \
-    "\x48\x65\x61\x64\x65\x72\x3e\x0d\x0a\x3c\x73\x65\x3a\x42\x6f\x64" \
-    "\x79\x3e\x3c\x2f\x73\x65\x3a\x42\x6f\x64\x79\x3e\x0d\x0a\x3c\x2f" \
-    "\x73\x65\x3a\x45\x6e\x76\x65\x6c\x6f\x70\x65\x3e\x0d\x0a\x0d\x0a" \
-    "\x2d\x2d\x4d\x53\x4d\x51\x20\x2d\x20\x53\x4f\x41\x50\x20\x62\x6f" \
-    "\x75\x6e\x64\x61\x72\x79\x2c\x20\x35\x33\x32\x38\x37\x0d\x0a\x43" \
-    "\x6f\x6e\x74\x65\x6e\x74\x2d\x54\x79\x70\x65\x3a\x20\x61\x70\x70" \
-    "\x6c\x69\x63\x61\x74\x69\x6f\x6e\x2f\x6f\x63\x74\x65\x74\x2d\x73" \
-    "\x74\x72\x65\x61\x6d\x0d\x0a\x43\x6f\x6e\x74\x65\x6e\x74\x2d\x4c" \
-    "\x65\x6e\x67\x74\x68\x3a\x20\x37\x0d\x0a\x43\x6f\x6e\x74\x65\x6e" \
-    "\x74\x2d\x49\x64\x3a\x20\x62\x6f\x64\x79\x40\x66\x66\x33\x61\x66" \
-    "\x33\x30\x31\x2d\x33\x31\x39\x36\x2d\x34\x39\x37\x61\x2d\x61\x39" \
-    "\x31\x38\x2d\x37\x32\x31\x34\x37\x63\x38\x37\x31\x61\x31\x33\x0d" \
-    "\x0a\x0d\x0a\x4d\x65\x73\x73\x61\x67\x65\x0c\x00\x00\x00\x94\x00" \
-    "\x00\x00\x02\x00\x00\x00\x94\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
-    "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x20\x53\x4f\x41" \
-    "\x50\x20\x62\x6f\x75\x6e\x64\x61\x72\x79\x2c\x20\x35\x33\x32\x38" \
-    "\x37\x2d\x2d\x00"
+
+    endian :big
+
+    uint16le :header_id
+    uint16 :reserved
+    uint32le :http_body_size
+    uint32le :msg_body_size
+    uint32le :msg_body_offset
+    string :data
   end
 
-  def extension_header
+  class ExtensionHeader < BinData::Record
     #  ExtensionHeader (https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-mqrr/baf230bf-7f15-4d03-bd1d-f8276608a955)
     #
     #  Header detailing if any further headers are present. In this case
     #  no further headers were appended.
     #
-    #  Fields:
-    #    HeaderSize(4), RemainingHeadersSize(4), Flags(1), Reserved(3)
-
-    "\x0c\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
-  end
 
-  def message_normal
-    base_header + user_header + message_properties_header + srmp_envelope_header + compound_message_header + extension_header
-  end
+    endian :big
 
-  def message_malformed
-    base_header + user_header + message_properties_header + srmp_envelope_header[0..6] + "\x80" + srmp_envelope_header[8..] + compound_message_header + extension_header
+    uint32le :header_size
+    uint32le :remaining_headers_size
+    uint8 :flags
+    string :reserved, length: 3
   end
 
   def send_message(msg)
     connect
     sock.put(msg)
-    response = sock.read(1024)
+    response = sock.timed_read(1024)
     disconnect
     return response
   end
 
   def run_host(ip)
-    response = send_message(message_normal)
+    base_header = BaseHeader.new
+
+    # Version number is always 0x10
+    base_header.version_number = 16
+
+    base_header.reserved = 0
+
+    # Flags: PR=3 (Message Priority)
+    base_header.flags = 768
+
+    # Signature is static and always set to 'LIOR'
+    base_header.signature = 0x4C494F52
+
+    # TimeToReachQueue set to 'infinite' (0xFFFFFFFF)
+    base_header.time_to_reach_queue = 4294967295
+
+    user_header = UserHeader.new
+
+    # SourceQueueManager is set to a null UUID, since SRMP Messages use the SOAP Headers for this
+    user_header.source_queue_manager = "\x00" * 16
+
+    # QueueManagerAddress is set to a null UUID, since SRMP Messages use the SOAP Headers for this
+    user_header.queue_manager_address = "\x00" * 16
+
+    user_header.time_to_be_received = 0
+
+    # SentTime is set to an arbitrary value. For this purpose it doesn't matter if it's in the past
+    user_header.sent_time = 1690217059
+
+    user_header.message_id = 1
+
+    # Flags: RC=1, DQ=7 (Direct Format Type), F=1 (MessagePropertiesHeader present), J=1 (HTTP used)
+    user_header.flags = 18620418
+
+    # An arbitrary ip address and queue name was choosen to send the message.
+    # Usually this need to match an existing IP address and queue name, however
+    # for this Proof-of-Concept it doesn't matter what values are used.
+    user_header.destination_queue = "http://192.168.10.100/msmq/private$/queuejumper\x00".encode('utf-16le')
+
+    user_header.destination_queue_length = user_header.destination_queue.length
+    user_header.padding = ''
+    user_header_padding_required = (4 - (user_header.to_binary_s.length % 4)) % 4
+    user_header.padding = "\x00" * user_header_padding_required
+
+    message_properties_header = MessagePropertiesHeader.new
+    message_properties_header.flags = 0
+    message_properties_header.message_class = 0
+    message_properties_header.correlation_id = "\x00" * 20
+    message_properties_header.body_type = 0
+    message_properties_header.application_tag = 0
+
+    # Usually this field contains the size of the message. In SRMP messages this is handles within the SOAP headers
+    message_properties_header.message_size = 0
+
+    message_properties_header.allocation_body_size = 0
+    message_properties_header.privacy_level = 0
+    message_properties_header.hash_algorithm = 0
+    message_properties_header.encryption_algorithm = 0
+    message_properties_header.extension_size = 0
+
+    # Label of the message was set to the arbitrary value 'poc'
+    message_properties_header.label = "poc\x00".encode('utf-16le')
+
+    message_properties_header.label_length = message_properties_header.label.length / 2
+
+    srmp_envelope_header = SRMPEnvelopeHeader.new
+    srmp_envelope_header.header_id = 0
+    srmp_envelope_header.reserved = 0
+
+    # The payload within the SRMPEnvelopeHeader structure is a SOAP request that defines message label, destination queue
+    # and expiry and sent dates.
+    # Usually the destination information need to match the IP address and queue name, however
+    # for this Proof-of-Concept it doesn't matter what values are used.
+    srmp_envelope_header.data = <<~EOF.chomp
+      <se:Envelope xmlns:se="http://schemas.xmlsoap.org/soap/envelope/" \r
+      xmlns="http://schemas.xmlsoap.org/srmp/">\r
+      <se:Header>\r
+       <path xmlns="http://schemas.xmlsoap.org/rp/" se:mustUnderstand="1">\r
+         <action>MSMQ:poc</action>\r
+         <to>http://192.168.10.100/msmq/private$/queuejumper</to>\r
+         <id>uuid:1@00000000-0000-0000-0000-000000000000</id>\r
+       </path>\r
+       <properties se:mustUnderstand="1">\r
+         <expiresAt>20600609T164419</expiresAt>\r
+         <sentAt>20230724T164419</sentAt>\r
+       </properties>\r
+      </se:Header>\r
+      <se:Body></se:Body>\r
+      </se:Envelope>\r\n\r\n\x00
+    EOF
+
+    srmp_envelope_header.data = srmp_envelope_header.data.encode('utf-16le')
+    srmp_envelope_header.data_length = srmp_envelope_header.data.length / 2
+    srmp_envelope_header_padding_required = (4 - (srmp_envelope_header.to_binary_s.length % 4)) % 4
+    srmp_envelope_header.padding = "\x00" * srmp_envelope_header_padding_required
+
+    compound_message_header = CompoundMessageHeader.new
+
+    # HeaderId is set to an arbitrary value
+    compound_message_header.header_id = 500
+
+    compound_message_header.reserved = 0
+
+    # MsgBodySize denotes the size of the actual message
+    compound_message_header.msg_body_size = 7
+
+    # MsgBodyOffset is the offset of the actual message within the CompoundMessageHeader payload
+    compound_message_header.msg_body_offset = 995
+
+    # The data field within the CompoundMessageHeader structure contains a HTTP-POST request that is used to submit the message
+    # to MSMQ. It contains the destination host, the SOAP envelope from SRMPEnvelopeHeader, sent and expiry dates. The destination
+    # addresses and queue names don't need to match for this proof-of-concept to work. With incorrect information the message will
+    # never reach the destination, however parsing of the structure and triggering the vulnerable code sequence happens before anyway.
+    compound_message_header.data = <<~EOF.chomp
+      POST /msmq HTTP/1.1\r
+      Content-Length: 816\r
+      Content-Type: multipart/related; boundary="MSMQ - SOAP boundary, 53287"; type=text/xml\r
+      Host: 192.168.10.100\r
+      SOAPAction: "MSMQMessage"\r
+      Proxy-Accept: NonInteractiveClient\r
+      \r
+      --MSMQ - SOAP boundary, 53287\r
+      Content-Type: text/xml; charset=UTF-8\r
+      Content-Length: 606\r
+      \r
+      <se:Envelope xmlns:se="http://schemas.xmlsoap.org/soap/envelope/" \r
+      xmlns="http://schemas.xmlsoap.org/srmp/">\r
+      <se:Header>\r
+       <path xmlns="http://schemas.xmlsoap.org/rp/" se:mustUnderstand="1">\r
+         <action>MSMQ:poc</action>\r
+         <to>http://192.168.10.100/msmq/private$/queuejumper</to>\r
+         <id>uuid:1@00000000-0000-0000-0000-000000000000</id>\r
+       </path>\r
+       <properties se:mustUnderstand="1">\r
+         <expiresAt>20600609T164419</expiresAt>\r
+         <sentAt>20230724T164419</sentAt>\r
+       </properties>\r
+      </se:Header>\r
+      <se:Body></se:Body>\r
+      </se:Envelope>\r
+      \r
+      --MSMQ - SOAP boundary, 53287\r
+      Content-Type: application/octet-stream\r
+      Content-Length: 7\r
+      Content-Id: body@ff3af301-3196-497a-a918-72147c871a13\r
+      \r
+      Message\r
+      --MSMQ - SOAP boundary, 53287--\x00
+    EOF
+    compound_message_header.http_body_size = compound_message_header.data.length
+
+    extension_header = ExtensionHeader.new
+
+    # Extension header will be empty in this case. The length is set to the minimal value of 12.
+    extension_header.header_size = 12
+
+    extension_header.remaining_headers_size = 0
+    extension_header.flags = 0
+    extension_header.reserved = "\x00" * 3
+
+    # Total packet size within the BaseHeader is calculated, now that all message parts were instantiated
+    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
+
+    # A normal message is sent to the server. This should yield a result for both, vulnerable and patched MSMQ instances
+    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)
 
     if !response
       print_error('No response received due to a timeout')
@@ -296,13 +343,22 @@ def run_host(ip)
     end
 
     if response.include?('LIOR')
+      # Response from server contains the static signature value 'LIOR'. Presence of MSMQ is confirmed
       print_status('MSMQ detected. Checking for CVE-2023-21554')
     else
       print_error('Service does not look like MSMQ')
       return
     end
 
-    response = send_message(message_malformed)
+    # This statement increases the DataLength field within the SRMPEnvelopeHeader by 0x80000000. This will cause
+    # an integer overflow, that overflows the 4 integer bytes. By adding this value the least significant 4 bytes will
+    # remain the same, to ensure that a vulnerable MSMQ instance doesn't try to access invalid memory. This means that
+    # vulnerable instances are expected to sent a normal response, like for the first, unmodified packet.
+    #
+    # Patched instances will detect the overflow, throw an exception and stop processing the message. No response is expected.
+    srmp_envelope_header.data_length = srmp_envelope_header.data_length + 2147483648
+
+    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)
 
     if response.nil?
       print_error('No response received, MSMQ seems to be patched')
@@ -327,8 +383,12 @@ def run_host(ip)
     end
   rescue ::Rex::ConnectionError
     print_error('Unable to connect to the service')
+  rescue ::Errno::ECONNRESET
+    print_error('Connection reset by service')
   rescue ::Errno::EPIPE
     print_error('pipe error')
+  rescue Timeout::Error
+    print_error('Timeout after waiting for service to respond')
   rescue StandardError => e
     print_error(e)
   end