diff --git a/lib/msf/base/simple/payload.rb b/lib/msf/base/simple/payload.rb index 917d94fa9c..5ff0390df7 100644 --- a/lib/msf/base/simple/payload.rb +++ b/lib/msf/base/simple/payload.rb @@ -19,13 +19,14 @@ class Payload # # opts can have: # - # Encoder => A encoder module instance. - # Badchars => A string of bad characters. - # Format => The format to represent the data as: ruby, perl, c, raw - # Options => A hash of options to set. - # OptionStr => A string of options in VAR=VAL form separated by - # whitespace. - # NoComment => Disables prepention of a comment + # Encoder => A encoder module instance. + # Badchars => A string of bad characters. + # Format => The format to represent the data as: ruby, perl, c, raw + # Options => A hash of options to set. + # OptionStr => A string of options in VAR=VAL form separated by + # whitespace. + # NoComment => Disables prepention of a comment + # NopSledSize => The number of NOPs to use # # raises: # @@ -43,30 +44,28 @@ class Payload end # Generate the payload - buf = payload.generate - - # If an encoder was specified, encode the generated payload - if (opts['Encoder']) - buf = opts['Encoder'].encode(buf, opts['Badchars']) - end + e = EncodedPayload.create(payload, + 'BadChars' => opts['BadChars'], + 'MinNops' => opts['NopSledSize'], + 'Encoder' => opts['Encoder']) fmt = opts['Format'] || 'raw' # Save off the original payload length - len = buf.length + len = e.encoded.length # Serialize the generated payload to some sort of format - buf = Buffer.transform(buf, fmt) + buf = Buffer.transform(e.encoded, fmt) # Prepend a comment if (fmt != 'raw' and opts['NoComment'] != true) ((ds = payload.datastore.to_s) and ds.length > 0) ? ds += "\n" : ds = '' - buf = Buffer.comment( "#{payload.refname} - #{len} bytes\n" + "http://www.metasploit.com\n" + "#{ds}" + - ((opts['Encoder']) ? "Encoder=" + opts['Encoder'].refname + "\n" : ''), fmt) + buf + ((e.encoder) ? "Encoder: #{e.encoder.refname}\n" : '') + + ((e.nop) ? "NOP generator: #{e.nop.refname}\n" : ''), fmt) + buf end return buf diff --git a/lib/msf/core.rb b/lib/msf/core.rb index e374989b0e..531542d5c3 100644 --- a/lib/msf/core.rb +++ b/lib/msf/core.rb @@ -24,6 +24,9 @@ require 'msf/core/framework' require 'msf/core/session_manager' require 'msf/core/session' +# Wrappers +require 'msf/core/encoded_payload' + # Pseudo-modules require 'msf/core/handler' diff --git a/lib/msf/core/encoded_payload.rb b/lib/msf/core/encoded_payload.rb index 8c24076aa4..5637ea14b9 100644 --- a/lib/msf/core/encoded_payload.rb +++ b/lib/msf/core/encoded_payload.rb @@ -18,9 +18,9 @@ class EncodedPayload # # Creates an encoded payload instance # - def self.create(framework, pinst, reqs) + def self.create(pinst, reqs) # Create the encoded payload instance - p = EncodedPayload.new(framework, pinst, reqs) + p = EncodedPayload.new(pinst.framework, pinst, reqs) p.generate @@ -37,10 +37,12 @@ class EncodedPayload # Generate the full encoded payload # def generate - raw = nil - encoded = nil - nop_sled_size = 0 - nop_sled = nil + self.raw = nil + self.encoded = nil + self.nop_sled_size = 0 + self.nop_sled = nil + self.encoder = nil + self.nop = nil # Generate the raw version of the payload first generate_raw() @@ -52,7 +54,7 @@ class EncodedPayload generate_sled() # Finally, set the complete payload definition - encoded = (nop_sled || '') + encoded + self.encoded = (self.nop_sled || '') + self.encoded # Return the complete payload return encoded @@ -63,7 +65,7 @@ class EncodedPayload # raw attribute. # def generate_raw - raw = (reqs['Prepend'] || '') + pisnt.generate + (reqs['Append'] || '') + self.raw = (reqs['Prepend'] || '') + pinst.generate + (reqs['Append'] || '') end # @@ -74,32 +76,44 @@ class EncodedPayload # If the exploit has bad characters, we need to run the list of encoders # in ranked precedence and try to encode without them. if (reqs['BadChars']) - pinst.compatible_encoders.each { |enc| - encoder = enc.new + encoders = pinst.compatible_encoders + + # If the caller had a preferred encoder, try to find it and prefix it + if ((reqs['Encoder']) and + (preferred = framework.encoders[reqs['Encoder']])) + encoders.unshift(preferred) + elsif (reqs['Encoder']) + wlog("#{pinst.refname}: Failed to find preferred encoder #{reqs['Encoder']}") + end + + encoders.each { |encmod| + self.encoder = encmod.new # Try encoding with the current encoder begin - p.encoded = encoder.encode(raw, reqs['BadChars']) + self.encoded = self.encoder.encode(self.raw, reqs['BadChars']) rescue wlog("#{pinst.refname}: Failed to encode payload with encoder #{encoder.refname}: #{$!}", 'core', LEV_1) + next end - # Minimum number of NOPs to use - min = reqs['MinNops'] || 0 - # Check to see if we have enough room for the minimum requirements if ((reqs['Space']) and - (reqs['Space'] < encoded.length + min)) + (reqs['Space'] < self.encoded.length + min)) wlog("#{pinst.refname}: Encoded payload version is too large with encoder #{encoder.refname}", 'core', LEV_1) next end + + break } # If the encoded payload is nil, raise an exception saying that we # suck at life. - if (encoded == nil) + if (self.encoded == nil) + encoder = nil + raise NoEncodersSucceededError, "#{pinst.refname}: All encoders failed to encode.", caller @@ -107,11 +121,11 @@ class EncodedPayload # If there are no bad characters, then the raw is the same as the # encoded else - encoded = raw + self.encoded = raw end # Prefix the prepend encoder value - encoded = (reqs['PrependEncoder'] || '') + encoded + self.encoded = (reqs['PrependEncoder'] || '') + self.encoded end # @@ -121,48 +135,52 @@ class EncodedPayload min = reqs['MinNops'] || 0 space = reqs['Space'] - nop_sled_size = 0 + self.nop_sled_size = min # Calculate the number of NOPs to pad out the buffer with based on the # requirements. If there was a space requirement, check to see if # there's any room at all left for a sled. if ((space) and (space > encoded.length)) - nop_sled_size = reqs['Space'] - encoded.length + self.nop_sled_size = reqs['Space'] - self.encoded.length end # If the maximum number of NOPs has been exceeded, wrap it back down. if ((reqs['MaxNops']) and (reqs['MaxNops'] > sled_size)) - nop_sled_size = reqs['MaxNops'] + self.nop_sled_size = reqs['MaxNops'] end # Now construct the actual sled - if (nop_sled_size > 0) + if (self.nop_sled_size > 0) pinst.compatible_nops.each { |nopmod| # Create an instance of the nop module - nop = nopmod.new + self.nop = nopmod.new begin - nop_sled = nop.generate_sled(nop_sled_size, + self.nop_sled = nop.generate_sled(nop_sled_size, 'BadChars' => reqs['BadChars'], 'SaveRegisters' => reqs['SaveRegisters']) rescue + self.nop = nil + dlog("#{pinst.refname}: Nop generator #{nop.refname} failed to generate sled for payload: #{$!}", 'core', LEV_1) end + + break } - if (nop_sled == nil) + if (self.nop_sled == nil) raise NoNopsSucceededError, "#{pinst.refname}: All NOP generators failed to construct sled for.", caller end else - nop_sled = '' + self.nop_sled = '' end - return nop_sled + return self.nop_sled end # @@ -182,6 +200,14 @@ class EncodedPayload # The NOP sled itself # attr_reader :nop_sled + # + # The encoder that was used + # + attr_reader :encoder + # + # The NOP generator that was used + # + attr_reader :nop protected @@ -190,6 +216,8 @@ protected attr_writer :nop_sled_size attr_writer :nop_sled attr_writer :payload + attr_writer :encoder + attr_writer :nop # # The payload instance used to generate the payload diff --git a/lib/msf/core/encoder.rb b/lib/msf/core/encoder.rb index b8d1c0395b..8f574d9367 100644 --- a/lib/msf/core/encoder.rb +++ b/lib/msf/core/encoder.rb @@ -116,10 +116,7 @@ class Encoder < Module end end - # Update the state with default decoder information - state.decoder_key_offset = decoder_key_offset - state.decoder_key_size = decoder_key_size - state.decoder_key_pack = decoder_key_pack + init_state(state) # Save the buffer in the encoding state state.badchars = badchars @@ -200,6 +197,13 @@ class Encoder < Module protected + def init_state(state) + # Update the state with default decoder information + state.decoder_key_offset = decoder_key_offset + state.decoder_key_size = decoder_key_size + state.decoder_key_pack = decoder_key_pack + end + def find_key(buf, badchars) key_bytes = [ ] cur_key = [ ] diff --git a/lib/msf/core/encoder/xor_additive_feedback.rb b/lib/msf/core/encoder/xor_additive_feedback.rb index b93fcd43d3..f93a6d39ac 100644 --- a/lib/msf/core/encoder/xor_additive_feedback.rb +++ b/lib/msf/core/encoder/xor_additive_feedback.rb @@ -30,6 +30,8 @@ class Msf::Encoder::XorAdditiveFeedback < Msf::Encoder::Xor key_bytes = integer_to_key_bytes(super(buf, badchars)) state = Msf::EncoderState.new valid = false + + init_state(state) # Save the original key_bytes so we can tell if we loop around orig_key_bytes = key_bytes.dup diff --git a/lib/msf/core/exploit.rb b/lib/msf/core/exploit.rb index 18cc4f4074..efd791ff1a 100644 --- a/lib/msf/core/exploit.rb +++ b/lib/msf/core/exploit.rb @@ -179,7 +179,7 @@ class Exploit < Msf::Module reqs['SaveRegisters'] = nop_save_registers # Set the encoded payload to the result of the encoding process - encoded_payload = EncodedPayload.create(framework, real_payload, reqs) + encoded_payload = EncodedPayload.create(real_payload, reqs) return encoded_payload end diff --git a/lib/msf/core/module_manager.rb b/lib/msf/core/module_manager.rb index b4d652751a..a115b4090d 100644 --- a/lib/msf/core/module_manager.rb +++ b/lib/msf/core/module_manager.rb @@ -107,8 +107,8 @@ protected b_name, b_mod = b # Extract the ranking between the two modules - a_rank = a.const_defined?('Rank') ? a.const_get('Rank') : NormalRanking - b_rank = b.const_defined?('Rank') ? b.const_get('Rank') : NormalRanking + a_rank = a[1].const_defined?('Rank') ? a[1].const_get('Rank') : NormalRanking + b_rank = b[1].const_defined?('Rank') ? b[1].const_get('Rank') : NormalRanking # Compare their relevant rankings. Since we want highest to lowest, # we compare b_rank to a_rank in terms of higher/lower precedence diff --git a/lib/msf/core/payload.rb b/lib/msf/core/payload.rb index 54d11fd1da..285e68b18b 100644 --- a/lib/msf/core/payload.rb +++ b/lib/msf/core/payload.rb @@ -170,8 +170,8 @@ class Payload < Msf::Module encoders = [] framework.encoders.each_module_ranked( - 'Arch' => self.arch) { |entry| - encoders << entry[1] + 'Arch' => self.arch) { |name, mod| + encoders << mod } return encoders @@ -184,8 +184,8 @@ class Payload < Msf::Module nops = [] framework.nops.each_module_ranked( - 'Arch' => self.arch) { |entry| - nops << entry[1] + 'Arch' => self.arch) { |name, mod| + nops << mod } return nops diff --git a/lib/msf/ui/console/command_dispatcher/payload.rb b/lib/msf/ui/console/command_dispatcher/payload.rb index 22c0418b05..88f731bfc6 100644 --- a/lib/msf/ui/console/command_dispatcher/payload.rb +++ b/lib/msf/ui/console/command_dispatcher/payload.rb @@ -12,6 +12,7 @@ class Payload "-t" => [ true, "The output type: ruby, perl, c, or raw." ], "-e" => [ true, "The name of the encoder module to use." ], "-o" => [ true, "A space separated list of options in VAR=VAL format." ], + "-s" => [ true, "NOP sled length." ], "-h" => [ false, "Help banner." ]) include Msf::Ui::Console::ModuleCommandDispatcher @@ -29,9 +30,9 @@ class Payload # Parse the arguments encoder_name = nil + sled_size = nil option_str = nil badchars = nil - encoder = nil type = "ruby" @@generate_opts.parse(args) { |opt, idx, val| @@ -44,6 +45,8 @@ class Payload encoder_name = val when '-o' option_str = val + when '-s' + sled_size = val.to_i when '-h' print( "Usage: generate [options]\n\n" + @@ -53,21 +56,15 @@ class Payload end } - # If an encoder name was specified, try to instantiate it - if ((encoder_name) and - (encoder = framework.modules.create(encoder_name)) == nil) - print_error("Invalid encoder specified: #{encoder_name}") - return false - end - # Generate the payload begin buf = Msf::Simple::Payload.generate( mod, - 'Badchars' => badchars, - 'Encoder' => encoder, - 'Format' => type, - 'OptionStr' => option_str) + 'BadChars' => badchars, + 'Encoder' => encoder_name, + 'Format' => type, + 'NopSledSize' => sled_size, + 'OptionStr' => option_str) rescue print_error("Payload generation failed: #{$!}") return false diff --git a/msfconsole b/msfconsole index b220e1375a..c0b5200bc4 100755 --- a/msfconsole +++ b/msfconsole @@ -1,4 +1,7 @@ -#!/usr/bin/ruby -I../lib +#!/usr/bin/ruby + +# Ghetto include for lib relative to the msfconsole script +$:.unshift(File.join(File.dirname(__FILE__), '../lib')) require 'rex' require 'msf/ui'