diff --git a/lib/rex/mime/message.rb b/lib/rex/mime/message.rb index 34bb54f..c949467 100644 --- a/lib/rex/mime/message.rb +++ b/lib/rex/mime/message.rb @@ -26,7 +26,7 @@ def initialize(data=nil) if ctype && ctype[1] && ctype[1] =~ /multipart\/mixed;\s*boundary="?([A-Za-z0-9'\(\)\+\_,\-\.\/:=\?^\s]+)"?/ self.bound = $1 - chunks = body.to_s.split(/--#{self.bound}(--)?\r?\n/) + chunks = body.to_s.split(/--#{self.bound}(--)?\r?\n?/) self.content = chunks.shift.to_s.gsub(/\s+$/, '') self.content << "\r\n" unless self.content.empty? @@ -35,7 +35,7 @@ def initialize(data=nil) head,body = chunk.split(/\r?\n\r?\n/, 2) part = Rex::MIME::Part.new part.header.parse(head) - part.content = body.gsub(/\s+$/, '') + part.content = body&.delete_suffix("\r\n") self.parts << part end else diff --git a/spec/lib/rex/mime/message_spec.rb b/spec/lib/rex/mime/message_spec.rb index edcd0e8..bd198da 100644 --- a/spec/lib/rex/mime/message_spec.rb +++ b/spec/lib/rex/mime/message_spec.rb @@ -15,6 +15,32 @@ described_class.allocate end + let(:binary_junk) do + "\xBF^1\x00\v\xD9\xD3X\x8D:\xA1\xABS\xDD\xFA\xFBm\xE0\x8A\x96\xE6\x97\x8Aagfc\xAC\x98\xBEL\x1C\xDD\xAA'\xEA6s\r\x19V\xA6\xC0\x967\xFC\x8D\xF9\x9Et-\xAA\x14x\xB2\\\xEA\xF12u\xC3\xFB\xB6\x8A\xDB\xB3\x84\xB6}\x9A\x044K\x12T\tY\xEB\x83B\x8F.\x1D\xEF\xEC\xEE\xE6H]\x11W?\n\xAE\xE6\x94\xC7\xAF\xD9\x9E" + end + + let(:binary_message) do + message = '' + message << "HTTP/1.1 200 OK\r\n" + message << "Content-Type: multipart/mixed; boundary=\"aAbBcCdDv1234567890VxXyYzZ\"\r\n" + message << "Server: Microsoft-IIS/10.0\r\n" + message << "Persistent-Auth: true\r\n" + message << "X-Powered-By: ASP.NET\r\n" + message << "Date: Thu, 05 Dec 2024 05:01:55 GMT\r\n" + message << "Content-Length: 4025\r\n" + message << "\r\n" + message << "--aAbBcCdDv1234567890VxXyYzZ\r\n" + message << "content-type: text/plain; charset=UTF-16\r\n\r\n" + message << "utf-16-encoded text\x00".encode('utf-16le').bytes.pack('C*') + message << "\r\n--aAbBcCdDv1234567890VxXyYzZ\r\n" + message << "content-type: application/octet-stream\r\n" + message << "\r\n" + message << binary_junk + message << "\r\n--aAbBcCdDv1234567890VxXyYzZ--" + + message + end + let(:raw_message) do message = "MIME-Version: 1.0\r\n" message << "Content-Type: multipart/mixed; boundary=\"_Part_12_3195573780_381739540\"\r\n" @@ -51,6 +77,15 @@ expect(message_class.bound).to include('---------------------------') end + + it "populates binary parts correctly" do + message_class.send(:initialize, binary_message) + expect(message_class.parts.length).to eq(2) + expect(message_class.parts[0].content.force_encoding('utf-16le')).to eq("utf-16-encoded text\x00".encode('utf-16le')) + expect(message_class.parts[1].content).to eq(binary_junk) + end + + it "allows to populate headers from argument" do message_class.send(:initialize, raw_message) expect(message_class.header.headers.length).to eq(7) @@ -105,7 +140,7 @@ it "allows to populate parts contents from argument" do message_class.send(:initialize, raw_message) part = message_class.parts[0] - expect(part.content).to eq("Q29udGVudHM=") + expect(part.content).to eq("Q29udGVudHM=\r\n") end end