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