diff --git a/lib/rex/mime/encoding.rb b/lib/rex/mime/encoding.rb new file mode 100644 index 0000000000..d9805c00e1 --- /dev/null +++ b/lib/rex/mime/encoding.rb @@ -0,0 +1,17 @@ +# -*- coding: binary -*- +module Rex +module MIME +# Set of helpers methods to deal with SMTP encoding related topics. +module Encoding + + # Enforces CRLF on the input data + # + # @param data [String] The data to CRLF enforce. + # @return [String] CRLF enforced data. + def force_crlf(data) + data.gsub("\r", '').gsub("\n", "\r\n") + end + +end +end +end diff --git a/lib/rex/mime/message.rb b/lib/rex/mime/message.rb index 2685a4e790..c8f3467377 100644 --- a/lib/rex/mime/message.rb +++ b/lib/rex/mime/message.rb @@ -5,10 +5,14 @@ class Message require 'rex/mime/header' require 'rex/mime/part' + require 'rex/mime/encoding' require 'rex/text' + include Rex::MIME::Encoding + attr_accessor :header, :parts, :bound, :content + def initialize(data=nil) self.header = Rex::MIME::Header.new self.parts = [] @@ -130,8 +134,7 @@ class Message self.parts.each do |part| msg << force_crlf("--" + self.bound + "\r\n") - msg << force_crlf(part.header.to_s + "\r\n") - msg << part.content + "\r\n" + msg << part.to_s end if self.parts.length > 0 @@ -141,11 +144,6 @@ class Message msg end - # Force CRLF for SMTP compatibility - def force_crlf(data) - data.gsub("\r", '').gsub("\n", "\r\n") - end - end end end diff --git a/lib/rex/mime/part.rb b/lib/rex/mime/part.rb index 5f2acfb96e..40ddcdded7 100644 --- a/lib/rex/mime/part.rb +++ b/lib/rex/mime/part.rb @@ -4,6 +4,9 @@ module MIME class Part require 'rex/mime/header' + require 'rex/mime/encoding' + + include Rex::MIME::Encoding attr_accessor :header, :content @@ -13,7 +16,33 @@ class Part end def to_s - self.header.to_s + "\r\n" + self.content + "\r\n" + self.header.to_s + "\r\n" + content_encoded + "\r\n" + end + + # Returns the part content with any necessary encoding or transformation + # applied. + # + # @return [String] Content with encoding or transformations applied. + def content_encoded + binary_content? ? content : force_crlf(content) + end + + # Answers if the part content is binary. + # + # @return [Boolean] true if the part content is binary, false otherwise. + def binary_content? + transfer_encoding && transfer_encoding == 'binary' + end + + # Returns the Content-Transfer-Encoding of the part. + # + # @returns [nil] if the part hasn't Content-Transfer-Encoding. + # @returns [String] The Content-Transfer-Encoding or the part. + def transfer_encoding + h = header.find('Content-Transfer-Encoding') + return nil if h.nil? + + h[1] end end diff --git a/modules/exploits/multi/http/mediawiki_thumb.rb b/modules/exploits/multi/http/mediawiki_thumb.rb index 848cf73fed..fec4fb5a3a 100644 --- a/modules/exploits/multi/http/mediawiki_thumb.rb +++ b/modules/exploits/multi/http/mediawiki_thumb.rb @@ -274,7 +274,7 @@ class Metasploit3 < Msf::Exploit::Remote djvu_file = ::File.read(::File.join(Msf::Config.data_directory, "exploits", "cve-2014-1610", "metasploit.djvu")) file_name = "#{rand_text_alpha(4)}.djvu" - upload_mime.add_part(djvu_file, "application/octet-stream", nil, "form-data; name=\"wpUploadFile\"; filename=\"#{file_name}\"") + upload_mime.add_part(djvu_file, "application/octet-stream", "binary", "form-data; name=\"wpUploadFile\"; filename=\"#{file_name}\"") upload_mime.add_part("#{file_name}", nil, nil, "form-data; name=\"wpDestFile\"") upload_mime.add_part("#{rand_text_alpha(4)}", nil, nil, "form-data; name=\"wpUploadDescription\"") upload_mime.add_part("", nil, nil, "form-data; name=\"wpLicense\"")