require 'msf/core' module Msf ### # # ExploitEvents # ------------- # # Event notifications that affect exploits. # ### module ExploitEvents # # Notified when an exploit is successful # def on_exploit_success(exploit) end # # Notified when an exploit is unsuccessful # def on_exploit_failure(exploit, reason) end end ### # # Exploit # ------- # # The exploit class acts as the base class for all exploit modules. It # provides a common interface for interacting with exploits at the most basic # level. # ### class Exploit < Msf::Module # # The various check codes that can be returned from the ``check'' routine. # module CheckCode Safe = [ 0, "The target is not exploitable." ] Detected = [ 1, "The target service is running, but could not be validated." ] Appears = [ 2, "The target appears to be vulnerable." ] Vulnerable = [ 3, "The target is vulnerable." ] Unsupported = [ 4, "This exploit does not support check." ] end # # The various basic types of exploits # module Type Remote = "remote" Local = "local" Omni = "omnipresent" end # # The types of stances an exploit can take, such as passive or aggressive. # Stances indicate whether or not the exploit triggers the exploit without # waiting for one or more conditions to be met (aggressive) or whether it # must wait for certain conditions to be satisfied before the exploit can # be initiated (passive) # module Stance Aggressive = "aggresive" Passive = "passive" end ### # # Local # ----- # # The local exploit class is a specialization of the exploit module class that # is geared toward exploits that are performed locally. Locally, in this # case, is defined as an exploit that is realized by means other than network # communication. # ### class Local < Exploit def exploit_type Exploit::Type::Local end end ### # # Remote # ------ # # The remote exploit class is a specialization of the exploit module class # that is geared toward exploits that are performed against targets other than # the local machine. This typically implies exploiting other machines via a # network connection, though it is not limited to this scope. # ### class Remote < Exploit def exploit_type Exploit::Type::Remote end end require 'msf/core/exploit/brute' require 'msf/core/exploit/tcp' require 'msf/core/exploit/dcerpc' # # Constructo the clown! Watch as he kills small children with balloons. # def initialize(info = {}) super(info) self.targets = Rex::Transformer.transform(info['Targets'], Array, [ Target ], 'Targets') self.default_target = info['DefaultTarget'] self.payload_info = info['Payload'] || {} end ## # # Core exploit interface # ---------------------- # # These are the methods that exploits will override to perform various # tasks, such as checking a target to see if it's vulnerable, automatically # selecting a target, or performing an exploit. # ## # # Checks to see if the target is vulnerable, returning unsupported if it's # not supported. # def check CheckCode::Unsupported end # # Kicks off the actual exploit. Prior to this call, the framework will # have validated the data store using the options associated with this # exploit module. It will also pre-generate the desired payload, though # exploits can re-generate the payload if necessary. # def exploit end # # Prepares the module for exploitation, initializes any state, and starts # the payload handler. # def setup if (payload_instance) # Set up the payload handlers payload_instance.setup_handler # Start the payload handler payload_instance.start_handler end end # # Performs any cleanup that may be necessary, such as disconnecting # connections and any other such fun things. If a payload is active then # its handler cleanup routines are called as well. # def cleanup if (payload_instance) payload_instance.cleanup_handler end end # # Generates the encoded version of the supplied payload using the payload # requirements specific to this exploit. The encoded instance is returned # to the caller. This method is exposed in the manner that it is such # that passive exploits and re-generate an encoded payload on the fly # rather than having to use the pre-generated one. # # The return value is an EncodedPayload instance. # def generate_payload(pinst = nil) # Set the encoded payload to the result of the encoding process self.payload = generate_single_payload(pinst) # Save the payload instance self.payload_instance = (pinst) ? pinst : self.payload_instance return self.payload end # # This method generates a non-cached payload which is typically useful for # passive exploits that will have more than one client. # def generate_single_payload(pinst = nil) if (target == nil) raise MissingTargetError, "No target has been specified.", caller end # If a payload instance was supplied, use it, otherwise # use the active payload instance real_payload = (pinst) ? pinst : self.payload_instance if (real_payload == nil) raise MissingPayloadError, "No payload has been selected.", caller end # Duplicate the exploit payload requirements reqs = self.payload_info # Pass save register requirements to the NOP generator reqs['SaveRegisters'] = nop_save_registers return EncodedPayload.create(real_payload, reqs) end # # Re-generates an encoded payload, typically called after something in the # datastore has changed. # def regenerate_payload generate_single_payload end ## # # Feature detection # ----------------- # # These methods check to see if there is a derived implementation of # various methods as a way of inferring whether or not a given exploit # supports the feature. # ## def supports_check? derived_implementor?(Msf::Exploit, 'check') end def supports_exploit? derived_implementor?(Msf::Exploit, 'exploit') end # # Returns a hash of the capabilities this exploit module has # def capabilities { 'check' => supports_check?, 'exploit' => supports_exploit? } end ## # # Getters/Setters # --------------- # # Querying and set interfaces for some of the exploit's attributes. # ## # # The module's type # def self.type MODULE_EXPLOIT end def type MODULE_EXPLOIT end # # If we don't know the exploit type, then I guess it's omnipresent! # def exploit_type Type::Omni end # # Generally, all exploits take an aggressive stance. # def stance module_info['Stance'] || Stance::Aggressive end # # Returns if the exploit has a passive stance # def passive? (stance == Stance::Passive) end # # Returns the active target for this exploit # def target target_idx = datastore['TARGET'] return (target_idx) ? targets[target_idx.to_i] : nil end # # Returns a list of compatible payloads based on platform, architecture, # and size requirements. # def compatible_payloads payloads = [] framework.payloads.each_module( 'Platform' => target ? target.platform : nil, 'Arch' => target ? target.arch : nil) { |name, mod| # Skip over payloads that are too big if ((payload_space) and (framework.payloads.sizes[name] > payload_space)) dlog("#{refname}: Skipping payload #{name} for being too large", 'core', LEV_1) next end # This one be compatible! payloads << [ name, mod ] } return payloads; end # # Return any text that should be prepended to the payload. The payload # module is passed so that the exploit can take a guess at architecture # and platform if it's a multi exploit. # def payload_prepend(payload_module) payload_info['Prepend'] || '' end # # Return any text that should be appended to the payload. The payload # module is passed so that the exploit can take a guess at architecture # and platform if it's a multi exploit. # def payload_append(payload_module) payload_info['Append'] || '' end # # Return any text that should be prepended to the encoder of the payload. # The payload module is passed so that the exploit can take a guess # at architecture and platform if it's a multi exploit. # def payload_prepend_encoder(payload_module) payload_info['PrependEncoder'] || '' end # # Maximum number of nops to use as a hint to the framework. # Nil signifies that the framework should decide. # def payload_max_nops payload_info['MaxNops'] || nil end # # Minimum number of nops to use as a hint to the framework. # Nil snigifies that the framework should decide. # def payload_min_nops payload_info['MinNops'] || nil end # # Returns the maximum amount of room the exploit has for a payload. # def payload_space if (payload_info['Space']) payload_info['Space'].to_i else nil end end # # Returns the bad characters that cannot be in any payload used by this # exploit. # def payload_badchars payload_info['BadChars'] end ## # # NOP requirements # ---------------- # # Hints to the nop generator on how it should perform if it's used. # ## # # Returns the list of registers that the NOP generator should save, # if any. It will use the current target's save registers in precedence # over those defined globally for the exploit module. # # If there are no save registers, nil is returned. # def nop_save_registers if (target and target.save_registers) return target.save_registers else return module_info['SaveRegisters'] end end # # Returns the first compatible NOP generator for this exploit's payload # instance. # def nop_generator return nil if (!payload_instance) payload_instance.compatible_nops.each { |nopname, nopmod| return nopmod.new } end # # Generates a nop sled of a supplied length and returns it to the caller. # def make_nops(count) nop_sled = nil # If there is no payload instance then we can't succeed. return nil if (!payload_instance) payload_instance.compatible_nops.each { |nopname, nopmod| # Create an instance of the nop module nop = nopmod.new # The list of save registers save_regs = nop_save_registers || [] if (save_regs.empty? == true) save_regs = nil end begin nop_sled = nop.generate_sled(count, 'BadChars' => payload_badchars || '', 'SaveRegisters' => save_regs) rescue dlog("#{self.refname}: Nop generator #{nop.refname} failed to generate sled for exploit: #{$!}", 'core', LEV_1) end break } nop_sled end ## # # Handler interaction # ## # # Passes the connection to the associated payload handler to see if the # exploit succeeded and a connection has been established. The return # value can be one of the Handler::constants. # def handler(*args) return self.payload_instance.handler(*args) if (self.payload_instance) end ## # # Attributes # ## # # The list of targets. # attr_reader :targets # # The default target. # attr_reader :default_target # # The payload requirement hash. # attr_reader :payload_info # # The active payload instance. # attr_accessor :payload_instance # # The encoded payload instance. An instance of an # EncodedPayload object. # attr_accessor :payload protected attr_writer :targets attr_writer :default_target attr_writer :payload_info end end