Files
metasploit-gs/lib/msf/core/payload_generator.rb
T

572 lines
23 KiB
Ruby
Raw Normal View History

# -*- coding: binary -*-
2015-12-22 14:47:55 +00:00
require 'msf/core/payload/apk'
2014-02-12 13:20:13 -06:00
require 'active_support/core_ext/numeric/bytes'
2019-11-18 15:12:15 -06:00
require 'msf/core/payload/windows/payload_db_conf'
2014-02-02 14:35:16 -06:00
module Msf
2014-02-05 18:12:44 -06:00
class PayloadGeneratorError < StandardError
end
2014-02-05 17:47:32 -06:00
class EncoderSpaceViolation < PayloadGeneratorError
2014-02-02 14:35:16 -06:00
end
class PayloadSpaceViolation < PayloadGeneratorError
end
2014-02-05 17:47:32 -06:00
class IncompatibleArch < PayloadGeneratorError
2014-02-02 21:09:17 -06:00
end
2014-02-05 17:47:32 -06:00
class IncompatibleEndianess < PayloadGeneratorError
2014-02-04 15:52:18 -06:00
end
2014-02-05 17:47:32 -06:00
class IncompatiblePlatform < PayloadGeneratorError
2014-02-03 17:51:22 -06:00
end
2014-02-05 17:47:32 -06:00
class InvalidFormat < PayloadGeneratorError
end
2014-02-02 14:35:16 -06:00
class PayloadGenerator
2014-02-05 18:12:44 -06:00
# @!attribute add_code
2015-04-13 13:21:41 +05:00
# @return [String] The path to a shellcode file to execute in a separate thread
2014-02-07 11:04:17 -06:00
attr_accessor :add_code
2014-02-05 18:12:44 -06:00
# @!attribute arch
# @return [String] The CPU architecture to build the payload for
2014-02-07 11:04:17 -06:00
attr_accessor :arch
2014-02-05 18:12:44 -06:00
# @!attribute badchars
# @return [String] The bad characters that can't be in the payload
2014-02-07 11:04:17 -06:00
attr_accessor :badchars
2014-02-05 18:12:44 -06:00
# @!attribute cli
# @return [Boolean] Whether this is being run by a CLI script
2014-02-07 11:04:17 -06:00
attr_accessor :cli
2014-02-05 18:12:44 -06:00
# @!attribute datastore
# @return [Hash] The datastore to apply to the payload module
2014-02-07 11:04:17 -06:00
attr_accessor :datastore
2014-02-05 18:12:44 -06:00
# @!attribute encoder
# @return [String] The encoder(s) you want applied to the payload
2014-02-07 11:04:17 -06:00
attr_accessor :encoder
# @!attribute secname
# @return [String] The name of the new section within the generated Windows binary
attr_accessor :secname
2014-02-05 18:12:44 -06:00
# @!attribute format
# @return [String] The format you want the payload returned in
2014-02-07 11:04:17 -06:00
attr_accessor :format
2014-02-05 18:12:44 -06:00
# @!attribute framework
# @return [Msf::Framework] The framework instance to use for generation
2014-02-07 11:04:17 -06:00
attr_accessor :framework
2014-02-05 18:12:44 -06:00
# @!attribute iterations
# @return [Integer] The number of iterations to run the encoder
2014-02-07 11:04:17 -06:00
attr_accessor :iterations
2014-02-05 18:12:44 -06:00
# @!attribute keep
# @return [Boolean] Whether or not to preserve the original functionality of the template
2014-02-07 11:04:17 -06:00
attr_accessor :keep
2014-02-05 18:12:44 -06:00
# @!attribute nops
# @return [Integer] The size in bytes of NOP sled to prepend the payload with
2014-02-07 11:04:17 -06:00
attr_accessor :nops
# @!attribute padnops
# @return [Boolean] Whether to use @!attribute nops as the total payload size
attr_accessor :padnops
2014-02-05 18:12:44 -06:00
# @!attribute payload
# @return [String] The refname of the payload to generate
2014-02-07 11:04:17 -06:00
attr_accessor :payload
2019-05-08 05:37:46 -04:00
# @!attribute payload_module
# @return [Module] The payload module object if applicable
attr_accessor :payload_module
2014-02-05 18:12:44 -06:00
# @!attribute platform
# @return [String] The platform to build the payload for
2014-02-07 11:04:17 -06:00
attr_accessor :platform
# @!attribute smallest
# @return [Boolean] Whether or not to find the smallest possible output
attr_accessor :smallest
2014-02-05 18:12:44 -06:00
# @!attribute space
# @return [Integer] The maximum size in bytes of the payload
2014-02-07 11:04:17 -06:00
attr_accessor :space
# @!attribute encoder_space
# @return [Integer] The maximum size in bytes of the encoded payload
attr_accessor :encoder_space
2014-02-05 18:12:44 -06:00
# @!attribute stdin
# @return [String] The raw bytes of a payload taken from STDIN
2014-02-07 11:04:17 -06:00
attr_accessor :stdin
2014-02-05 18:12:44 -06:00
# @!attribute template
# @return [String] The path to an executable template to use
2014-02-02 14:35:16 -06:00
attr_accessor :template
# @!attribute var_name
# @return [String] The custom variable string for certain output formats
attr_accessor :var_name
2018-04-10 11:14:14 -05:00
# @!attribute encryption_format
# @return [String] The encryption format to use for the shellcode.
attr_accessor :encryption_format
# @!attribute encryption_key
# @return [String] The key to use for the encryption
attr_accessor :encryption_key
# @!attribute encryption_iv
# @return [String] The initialization vector for the encryption (not all apply)
attr_accessor :encryption_iv
2014-02-02 14:35:16 -06:00
2014-02-02 21:09:17 -06:00
# @param opts [Hash] The options hash
2014-02-06 11:16:00 -06:00
# @option opts [String] :payload (see #payload)
# @option opts [String] :format (see #format)
# @option opts [String] :encoder (see #encoder)
# @option opts [String] :secname (see #secname)
# @option opts [Integer] :iterations (see #iterations)
2014-02-06 11:16:00 -06:00
# @option opts [String] :arch (see #arch)
# @option opts [String] :platform (see #platform)
# @option opts [String] :badchars (see #badchars)
# @option opts [String] :template (see #template)
# @option opts [Integer] :space (see #space)
# @option opts [Integer] :encoder_space (see #encoder_space)
# @option opts [Integer] :nops (see #nops)
# @option opts [Boolean] :padnops (see #padnops)
2014-02-06 11:16:00 -06:00
# @option opts [String] :add_code (see #add_code)
# @option opts [Boolean] :keep (see #keep)
# @option opts [Hash] :datastore (see #datastore)
# @option opts [Msf::Framework] :framework (see #framework)
# @option opts [Boolean] :cli (see #cli)
# @option opts [Boolean] :smallest (see #smallest)
2014-02-05 18:12:44 -06:00
# @raise [KeyError] if framework is not provided in the options hash
2014-02-02 14:35:16 -06:00
def initialize(opts={})
2014-02-02 21:09:17 -06:00
@add_code = opts.fetch(:add_code, '')
2014-02-02 14:35:16 -06:00
@arch = opts.fetch(:arch, '')
@badchars = opts.fetch(:badchars, '')
2014-02-05 11:00:57 -06:00
@cli = opts.fetch(:cli, false)
2014-02-02 14:35:16 -06:00
@datastore = opts.fetch(:datastore, {})
@encoder = opts.fetch(:encoder, '')
@secname = opts.fetch(:secname, '')
2014-02-02 14:35:16 -06:00
@format = opts.fetch(:format, 'raw')
@iterations = opts.fetch(:iterations, 1)
@keep = opts.fetch(:keep, false)
@nops = opts.fetch(:nops, 0)
@padnops = opts.fetch(:padnops, false)
2014-02-02 14:35:16 -06:00
@payload = opts.fetch(:payload, '')
@platform = opts.fetch(:platform, '')
2014-02-07 15:52:19 -06:00
@space = opts.fetch(:space, 1.gigabyte)
2014-02-02 21:09:17 -06:00
@stdin = opts.fetch(:stdin, nil)
2014-02-02 14:35:16 -06:00
@template = opts.fetch(:template, '')
@var_name = opts.fetch(:var_name, 'buf')
@smallest = opts.fetch(:smallest, false)
@encoder_space = opts.fetch(:encoder_space, @space)
2018-04-10 18:57:02 -05:00
@encryption_format = opts.fetch(:encryption_format, nil)
@encryption_key = opts.fetch(:encryption_key, nil)
@encryption_iv = opts.fetch(:encryption_iv, nil)
2014-02-02 14:35:16 -06:00
@framework = opts.fetch(:framework)
2019-05-08 05:37:46 -04:00
raise InvalidFormat, "invalid format: #{format}" unless format_is_valid?
raise ArgumentError, "invalid payload: #{payload}" unless payload_is_valid?
# A side-effecto of running framework.payloads.create is that
# framework.payloads.keys gets pruned of unloadable payloads. So, we do it
# after checking payload_is_valid?, which refers to the cached keys.
@payload_module = framework.payloads.create(@payload)
2019-05-31 15:02:59 -05:00
raise ArgumentError, "unloadable payload: #{payload}" unless payload_module || @payload == 'stdin'
# In smallest mode, override the payload @space & @encoder_space settings
if @smallest
@space = 0
@encoder_space = 1.gigabyte
end
2014-02-02 14:35:16 -06:00
end
2014-02-05 18:12:44 -06:00
# This method takes the shellcode generated so far and adds shellcode from
2015-04-13 13:21:41 +05:00
# a supplied file. The added shellcode is executed in a separate thread
2014-02-05 18:12:44 -06:00
# from the main payload.
2014-02-04 18:05:03 -06:00
# @param shellcode [String] The shellcode to add to
2015-04-13 13:21:41 +05:00
# @return [String] the combined shellcode which executes the added code in a separate thread
2014-02-04 18:05:03 -06:00
def add_shellcode(shellcode)
if add_code.present? and platform_list.platforms.include? Msf::Module::Platform::Windows and arch == ARCH_X86
2014-02-05 11:00:57 -06:00
cli_print "Adding shellcode from #{add_code} to the payload"
2014-02-04 18:05:03 -06:00
shellcode_file = File.open(add_code)
shellcode_file.binmode
added_code = shellcode_file.read
shellcode_file.close
shellcode = ::Msf::Util::EXE.win32_rwx_exec_thread(shellcode,0,'end')
shellcode << added_code
2014-02-04 15:52:18 -06:00
else
2014-02-04 18:05:03 -06:00
shellcode.dup
end
end
2014-02-05 18:12:44 -06:00
# This method takes a payload module and tries to reconcile a chosen
# arch with the arches supported by the module.
2014-02-04 18:05:03 -06:00
# @param mod [Msf::Payload] The module class to choose an arch for
# @return [String] String form of the arch if a valid arch found
2014-02-04 18:05:03 -06:00
# @return [Nil] if no valid arch found
def choose_arch(mod)
if arch.blank?
@arch = mod.arch.first
2018-05-23 18:26:01 +01:00
cli_print "[-] No arch selected, selecting arch: #{arch} from the payload"
datastore['ARCH'] = arch if mod.kind_of?(Msf::Payload::Generic)
2014-02-04 18:05:03 -06:00
return mod.arch.first
elsif mod.arch.include? arch
datastore['ARCH'] = arch if mod.kind_of?(Msf::Payload::Generic)
2014-02-04 18:05:03 -06:00
return arch
else
return nil
end
end
2014-02-05 18:12:44 -06:00
# This method takes a payload module and tries to reconcile a chosen
# platform with the platforms supported by the module.
2014-02-04 18:05:03 -06:00
# @param mod [Msf::Payload] The module class to choose a platform for
# @return [Msf::Module::PlatformList] The selected platform list
def choose_platform(mod)
# By default, platform_list will at least return Msf::Module::Platform
# if there is absolutely no pre-configured platform info at all
2014-02-04 18:05:03 -06:00
chosen_platform = platform_list
2014-02-04 18:05:03 -06:00
if chosen_platform.platforms.empty?
chosen_platform = mod.platform
2018-06-01 12:55:37 +01:00
cli_print "[-] No platform was selected, choosing #{chosen_platform.platforms.first} from the payload"
2014-02-04 18:05:03 -06:00
@platform = mod.platform.platforms.first.to_s.split("::").last
elsif (chosen_platform & mod.platform).empty?
chosen_platform = Msf::Module::PlatformList.new
end
begin
platform_object = Msf::Module::Platform.find_platform(platform)
rescue ArgumentError
platform_object = nil
end
if mod.kind_of?(Msf::Payload::Generic) && mod.send(:module_info)['Platform'].empty? && platform_object
datastore['PLATFORM'] = platform
end
2014-02-04 18:05:03 -06:00
chosen_platform
end
def multiple_encode_payload(shellcode)
encoder_str = encoder[1..-1]
encoder_str.scan(/([^:, ]+):?([^,]+)?/).map do |encoder_opt|
@iterations = (encoder_opt[1] || 1).to_i
@iterations = 1 if iterations < 1
encoder_mod = framework.encoders.create(encoder_opt[0])
encoder_mod.datastore.import_options_from_hash(datastore)
shellcode = run_encoder(encoder_mod, shellcode)
end
shellcode
end
2014-02-05 18:12:44 -06:00
# This method takes the shellcode generated so far and iterates through
# the chosen or compatible encoders. It attempts to encode the payload
# with each encoder until it finds one that works.
2014-02-04 18:05:03 -06:00
# @param shellcode [String] The shellcode to encode
# @return [String] The encoded shellcode
def encode_payload(shellcode)
shellcode = shellcode.dup
encoder_list = get_encoders
if encoder_list.empty?
2015-01-21 00:26:42 -06:00
cli_print "No encoder or badchars specified, outputting raw payload"
return shellcode
end
results = {}
cli_print "Found #{encoder_list.count} compatible encoders"
encoder_list.each do |encoder_mod|
cli_print "Attempting to encode payload with #{iterations} iterations of #{encoder_mod.refname}"
begin
encoder_mod.available_space = @encoder_space unless @smallest
results[encoder_mod.refname] = run_encoder(encoder_mod, shellcode.dup)
break unless @smallest
rescue ::Msf::EncoderSpaceViolation => e
cli_print "#{encoder_mod.refname} failed with #{e.message}"
next
rescue ::Msf::EncodingError => e
cli_print "#{encoder_mod.refname} failed with #{e.message}"
next
2014-02-04 18:05:03 -06:00
end
end
if results.keys.length == 0
2014-02-05 15:25:14 -06:00
raise ::Msf::EncodingError, "No Encoder Succeeded"
2014-02-04 18:05:03 -06:00
end
# Return the shortest encoding of the payload
chosen_encoder = results.keys.sort{|a,b| results[a].length <=> results[b].length}.first
cli_print "#{chosen_encoder} chosen with final size #{results[chosen_encoder].length}"
results[chosen_encoder]
2014-02-04 18:05:03 -06:00
end
2014-02-05 18:12:44 -06:00
# This returns a hash for the exe format generation of payloads
2014-02-04 18:05:03 -06:00
# @return [Hash] The hash needed for generating an executable format
def exe_options
2014-02-05 12:10:14 -06:00
opts = { inject: keep }
unless template.blank?
opts[:template_path] = File.dirname(template)
opts[:template] = File.basename(template)
end
2018-10-31 20:37:59 -05:00
unless secname.blank?
opts[:secname] = secname
end
2014-02-05 12:10:14 -06:00
opts
2014-02-04 18:05:03 -06:00
end
2014-02-05 18:12:44 -06:00
# This method takes the payload shellcode and formats it appropriately based
# on the selected output format.
2014-02-04 18:05:03 -06:00
# @param shellcode [String] the processed shellcode to be formatted
# @return [String] The final formatted form of the payload
def format_payload(shellcode)
2018-04-10 18:57:02 -05:00
encryption_opts = {}
encryption_opts[:format] = encryption_format if encryption_format
encryption_opts[:iv] = encryption_iv if encryption_iv
encryption_opts[:key] = encryption_key if encryption_key
2018-04-10 11:14:14 -05:00
if Msf::Util::EXE.elf?(shellcode) && format.downcase != 'elf'
# TODO: force generation from stager/stage if available
raise InvalidFormat, 'selected payload can only generate ELF files'
end
if Msf::Util::EXE.macho?(shellcode) && format.downcase != 'macho'
# TODO: force generation from stager/stage if available
raise InvalidFormat, 'selected payload can only generate MACHO files'
end
2014-02-04 18:05:03 -06:00
case format.downcase
when "js_be"
if Rex::Arch.endian(arch) != ENDIAN_BIG
raise IncompatibleEndianess, "Big endian format selected for a non big endian payload"
else
2018-04-10 11:14:14 -05:00
::Msf::Simple::Buffer.transform(shellcode, format, @var_name, encryption_opts)
2014-02-04 18:05:03 -06:00
end
when *::Msf::Simple::Buffer.transform_formats
2018-04-10 11:14:14 -05:00
::Msf::Simple::Buffer.transform(shellcode, format, @var_name, encryption_opts)
2014-02-04 18:05:03 -06:00
when *::Msf::Util::EXE.to_executable_fmt_formats
2014-02-25 15:51:06 -06:00
::Msf::Util::EXE.to_executable_fmt(framework, arch, platform_list, shellcode, format, exe_options)
2014-02-04 18:05:03 -06:00
else
raise InvalidFormat, "you have selected an invalid payload format"
2014-02-04 15:52:18 -06:00
end
end
2014-02-05 18:12:44 -06:00
# This method generates Java payloads which are a special case.
# They can be generated in raw or war formats, which respectively
# produce a JAR or WAR file for the java payload.
2014-02-04 15:52:18 -06:00
# @return [String] Java payload as a JAR or WAR file
def generate_java_payload
2017-09-13 13:00:21 +08:00
payload_module.datastore.import_options_from_hash(datastore)
2014-02-04 15:52:18 -06:00
case format
2016-05-12 22:48:07 +02:00
when "raw", "jar"
if payload_module.respond_to? :generate_jar
payload_module.generate_jar.pack
else
payload_module.generate
end
when "war"
if payload_module.respond_to? :generate_war
payload_module.generate_war.pack
else
raise InvalidFormat, "#{payload} is not a Java payload"
end
when "axis2"
if payload_module.respond_to? :generate_axis2
payload_module.generate_axis2.pack
2014-02-04 15:52:18 -06:00
else
2016-05-12 22:48:07 +02:00
raise InvalidFormat, "#{payload} is not a Java payload"
end
else
raise InvalidFormat, "#{format} is not a valid format for Java payloads"
2014-02-04 15:52:18 -06:00
end
end
2014-02-05 18:12:44 -06:00
# This method is a wrapper around all of the other methods. It calls the correct
# methods in order based on the supplied options and returns the finished payload.
2014-02-04 18:05:03 -06:00
# @return [String] A string containing the bytes of the payload in the format selected
def generate_payload
if payload.include?("pingback") and framework.db.active == false
cli_print "[-] WARNING: UUID cannot be saved because database is inactive."
end
2014-02-04 18:05:03 -06:00
if platform == "java" or arch == "java" or payload.start_with? "java/"
2015-12-22 14:37:57 +00:00
raw_payload = generate_java_payload
encoded_payload = raw_payload
gen_payload = raw_payload
2015-12-22 16:06:01 +00:00
elsif payload.start_with? "android/" and not template.blank?
cli_print "Using APK template: #{template}"
apk_backdoor = ::Msf::Payload::Apk.new
raw_payload = apk_backdoor.backdoor_apk(template, generate_raw_payload)
gen_payload = raw_payload
2014-02-04 18:05:03 -06:00
else
2019-11-18 13:45:24 -06:00
if payload_module.is_a?(Msf::Payload::Windows::PayloadDBConf)
2019-10-07 08:44:48 -05:00
payload_module.datastore.import_options_from_hash(datastore)
ds_opt = payload_module.datastore
2019-10-10 12:08:57 -05:00
cli_print("[!] Database is not active! Payload key and nonce must be manually set when creating handler") unless framework.db.active
2019-10-07 08:44:48 -05:00
cli_print("[-] Please ensure payload key and nonce match when setting up handler: #{ds_opt['ChachaKey']} - #{ds_opt['ChachaNonce']}")
2019-09-30 15:05:07 -05:00
end
2014-02-04 18:05:03 -06:00
raw_payload = generate_raw_payload
raw_payload = add_shellcode(raw_payload)
2016-06-23 15:44:35 +02:00
if encoder != nil and encoder.start_with?("@")
raw_payload = multiple_encode_payload(raw_payload)
else
raw_payload = encode_payload(raw_payload)
end
if padnops
@nops = nops - raw_payload.length
end
raw_payload = prepend_nops(raw_payload)
gen_payload = format_payload(raw_payload)
end
cli_print "Payload size: #{raw_payload.length} bytes"
if gen_payload.nil?
raise PayloadGeneratorError, 'The payload could not be generated, check options'
elsif raw_payload.length > @space and not @smallest
2016-05-23 15:40:32 -05:00
raise PayloadSpaceViolation, 'The payload exceeds the specified space'
else
2016-07-19 23:43:38 -05:00
if format.to_s != 'raw'
cli_print "Final size of #{format} file: #{gen_payload.length} bytes"
end
gen_payload
2014-02-04 18:05:03 -06:00
end
end
2014-02-05 18:12:44 -06:00
# This method generates the raw form of the payload as generated by the payload module itself.
2014-02-02 21:09:17 -06:00
# @raise [Msf::IncompatiblePlatform] if no platform was selected for a stdin payload
# @raise [Msf::IncompatibleArch] if no arch was selected for a stdin payload
# @raise [Msf::IncompatiblePlatform] if the platform is incompatible with the payload
# @raise [Msf::IncompatibleArch] if the arch is incompatible with the payload
# @return [String] the raw bytes of the payload to be generated
2014-02-02 14:35:16 -06:00
def generate_raw_payload
2014-02-02 21:09:17 -06:00
if payload == 'stdin'
if arch.blank?
raise IncompatibleArch, "You must select an arch for a custom payload"
elsif platform.blank?
raise IncompatiblePlatform, "You must select a platform for a custom payload"
end
stdin
else
chosen_platform = choose_platform(payload_module)
if chosen_platform.platforms.empty?
raise IncompatiblePlatform, "The selected platform is incompatible with the payload"
end
chosen_arch = choose_arch(payload_module)
unless chosen_arch
raise IncompatibleArch, "The selected arch is incompatible with the payload"
end
payload_module.generate_simple(
'Format' => 'raw',
'Options' => datastore,
'Encoder' => nil,
'MaxSize' => @space,
'DisableNops' => true
2014-02-02 21:09:17 -06:00
)
2014-02-02 14:35:16 -06:00
end
2014-02-02 21:09:17 -06:00
end
2014-02-02 14:35:16 -06:00
2014-02-05 18:12:44 -06:00
# This method returns an array of encoders that either match the
# encoders selected by the user, or match the arch selected.
2014-02-04 18:05:03 -06:00
# @return [Array<Msf::Encoder>] An array of potential encoders to use
2014-02-03 00:59:08 -06:00
def get_encoders
encoders = []
if encoder.present?
2015-04-13 13:21:41 +05:00
# Allow comma separated list of encoders so users can choose several
2014-02-03 00:59:08 -06:00
encoder.split(',').each do |chosen_encoder|
e = framework.encoders.create(chosen_encoder)
if e.nil?
cli_print "[-] Skipping invalid encoder #{chosen_encoder}"
next
end
e.datastore.import_options_from_hash(datastore)
encoders << e if e
2014-02-03 00:59:08 -06:00
end
if encoders.empty?
cli_print "[!] Couldn't find encoder to use"
2018-06-01 18:33:07 -05:00
return encoders
end
2014-02-03 00:59:08 -06:00
encoders.sort_by { |my_encoder| my_encoder.rank }.reverse
elsif !badchars.empty? && !badchars.nil?
framework.encoders.each_module_ranked('Arch' => [arch], 'Platform' => platform_list) do |name, mod|
e = framework.encoders.create(name)
e.datastore.import_options_from_hash(datastore)
encoders << e if e
2014-02-03 00:59:08 -06:00
end
encoders.select{ |my_encoder| my_encoder.rank != ManualRanking }.sort_by { |my_encoder| my_encoder.rank }.reverse
2014-02-03 00:59:08 -06:00
else
encoders
end
end
2014-02-05 18:12:44 -06:00
# Returns a PlatformList object based on the platform string given at creation.
2014-02-04 18:05:03 -06:00
# @return [Msf::Module::PlatformList] It will be empty if no valid platforms found
def platform_list
if platform.blank?
list = Msf::Module::PlatformList.new
else
begin
list = ::Msf::Module::PlatformList.transform(platform)
rescue
list = Msf::Module::PlatformList.new
end
end
list
end
2014-02-05 18:12:44 -06:00
# This method takes an encoded payload and prepends a NOP Sled to it
# with a size based on the nops value given to the generator.
2014-02-02 22:51:12 -06:00
# @param shellcode [String] The shellcode to prepend the NOPs to
# @return [String] the shellcode with the appropriate nopsled affixed
def prepend_nops(shellcode)
if nops > 0
framework.nops.each_module_ranked('Arch' => [arch]) do |name, mod|
2014-02-05 15:25:14 -06:00
nop = framework.nops.create(name)
raw = nop.generate_sled(nops, {'BadChars' => badchars, 'SaveRegisters' => [ 'esp', 'ebp', 'esi', 'edi' ] })
if raw
cli_print "Successfully added NOP sled of size #{raw.length} from #{name}"
2014-02-05 15:25:14 -06:00
return raw + shellcode
end
2014-02-02 22:51:12 -06:00
end
else
2014-02-05 17:47:32 -06:00
shellcode
2014-02-02 22:51:12 -06:00
end
end
2014-02-05 18:12:44 -06:00
# This method runs a specified encoder, for a number of defined iterations against the shellcode.
2014-02-04 18:05:03 -06:00
# @param encoder_module [Msf::Encoder] The Encoder to run against the shellcode
# @param shellcode [String] The shellcode to be encoded
# @return [String] The encoded shellcode
# @raise [Msf::EncoderSpaceViolation] If the Encoder makes the shellcode larger than the supplied space limit
def run_encoder(encoder_module, shellcode)
2014-02-05 11:00:57 -06:00
iterations.times do |x|
2014-02-04 18:05:03 -06:00
shellcode = encoder_module.encode(shellcode.dup, badchars, nil, platform_list)
2014-02-05 11:00:57 -06:00
cli_print "#{encoder_module.refname} succeeded with size #{shellcode.length} (iteration=#{x})"
if shellcode.length > encoder_space
2014-09-20 17:48:03 -05:00
raise EncoderSpaceViolation, "encoder has made a buffer that is too big"
end
2014-02-02 21:09:17 -06:00
end
2014-02-04 18:05:03 -06:00
shellcode
2014-02-02 21:09:17 -06:00
end
2014-02-02 16:05:11 -06:00
private
2014-02-05 18:12:44 -06:00
# This method prints output to the console if running in CLI mode
# @param [String] message The message to print to the console.
2014-02-05 11:00:57 -06:00
def cli_print(message= '')
2014-02-07 10:22:39 -06:00
$stderr.puts message if cli
2014-02-05 11:00:57 -06:00
end
2014-02-05 18:12:44 -06:00
# This method checks if the Generator's selected format is valid
2014-02-02 14:35:16 -06:00
# @return [True] if the format is valid
# @return [False] if the format is not valid
def format_is_valid?
formats = (::Msf::Util::EXE.to_executable_fmt_formats + ::Msf::Simple::Buffer.transform_formats).uniq
2014-02-04 15:52:18 -06:00
formats.include? format.downcase
2014-02-02 14:35:16 -06:00
end
2014-02-05 18:12:44 -06:00
# This method checks if the Generator's selected payload is valid
2014-02-04 18:05:03 -06:00
# @return [True] if the payload is a valid Metasploit Payload
# @return [False] if the payload is not a valid Metasploit Payload
def payload_is_valid?
(framework.payloads.keys + ['stdin']).include? payload
end
2014-02-02 14:35:16 -06:00
end
end