mirror of
https://github.com/rapid7/metasploit-framework
synced 2024-11-05 14:57:30 +01:00
fixed up encoding, made payload generation pimper
git-svn-id: file:///home/svn/incoming/trunk@2746 4d416f70-5f16-0410-b530-b9f4589650da
This commit is contained in:
parent
d4f569dddf
commit
72ad97dfd1
@ -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
|
||||
|
@ -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'
|
||||
|
||||
|
@ -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
|
||||
|
@ -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 = [ ]
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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'
|
||||
|
Loading…
Reference in New Issue
Block a user