Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Path: blob/master/lib/msf/core/evasion.rb
Views: 11778
1module Msf2class Evasion < Msf::Module34include Msf::Auxiliary::Report56class Complete < RuntimeError ; end78class Failed < RuntimeError ; end910def initialize(info={})11if (info['Payload'] and info['Payload']['Compat'])12info['Compat'] = Hash.new if (info['Compat'] == nil)13info['Compat']['Payload'] = Hash.new if (info['Compat']['Payload'] == nil)14info['Compat']['Payload'].update(info['Payload']['Compat'])15end1617super(info)1819self.payload_info = info['Payload'] || {}20self.targets = Rex::Transformer.transform(info['Targets'], Array, [ Target ], 'Targets')2122if info.key? 'DefaultTarget'23self.default_target = info['DefaultTarget']24else25self.default_target = 026# Add an auto-target to the evasion if it doesn't have one27if info['Targets'] && info['Targets'].count > 1 && !has_auto_target?(info['Targets'])28# Finally, only add the target if there is a remote host option29if self.respond_to?(:rhost) && self.respond_to?(:auto_targeted_index)30auto = ["Automatic", {'AutoGenerated' => true}.merge(info['Targets'][self.default_target][1])]31info['Targets'].unshift(auto)32end33end34end3536if (info['Payload'] and info['Payload']['ActiveTimeout'])37self.active_timeout = info['Payload']['ActiveTimeout'].to_i38end3940register_options([41OptString.new(42'FILENAME',43[44true,45'Filename for the evasive file (default: random)',46"#{Rex::Text.rand_text_alpha(3..10)}.exe"47])48], self.class)49end5051def self.type52Msf::MODULE_EVASION53end5455def type56Msf::MODULE_EVASION57end5859def setup60alert_user61end6263def file_format_filename64datastore['FILENAME']65end6667def file_create(data)68fname = file_format_filename69ltype = "evasion.fileformat.#{self.shortname}"70full_path = store_local(ltype, nil, data, fname)71print_good "#{fname} stored at #{full_path}"72end7374#75# Returns the target's platform, or the one assigned to the module itself.76#77def target_platform78(target and target.platform) ? target.platform : platform79end8081#82# Returns the target's architecture, or the one assigned to the module83# itself.84#85def target_arch86(target and target.arch) ? target.arch : (arch == []) ? nil : arch87end8889def normalize_platform_arch90c_platform = (target && target.platform) ? target.platform : platform91c_arch = (target && target.arch) ? target.arch : (arch == []) ? nil : arch92c_arch ||= [ ARCH_X86 ]93return c_platform, c_arch94end9596# Returns whether the requested payload is compatible with the module97#98# @param [String] name The payload name99# @return [Boolean] True if the payload is compatible, False if not.100def is_payload_compatible?(name)101p = framework.payloads[name]102return false unless p103104begin105pi = p.new106rescue ::Exception, ::LoadError => e107wlog("Module #{name} failed to initialize payload when checking evasion compatibility: #{e}", 'core', LEV_0)108return false109end110111# Are we compatible in terms of conventions and connections and112# what not?113return false if !compatible?(pi)114115# If the payload is privileged but the evasion does not give116# privileged access, then fail it.117return false if !self.privileged && pi.privileged118119return true120end121122# Returns a list of compatible payloads based on platform, architecture,123# and size requirements.124def compatible_payloads(excluded_platforms: [], excluded_archs: [])125payloads = []126127c_platform, c_arch = normalize_platform_arch128129# The "All" platform name represents generic payloads130results = Msf::Modules::Metadata::Cache.instance.find(131'type' => [['payload'], []],132'platform' => [[*c_platform.names, 'All'], excluded_platforms],133'arch' => [c_arch, excluded_archs]134)135136results.each do |res|137if is_payload_compatible?(res.ref_name)138payloads << [res.ref_name, framework.payloads[res.ref_name]]139end140end141142payloads143end144145def run146raise NotImplementedError147end148149def cleanup150end151152def fail_with(reason, msg=nil)153raise Msf::Evasion::Failed, "#{reason}: #{msg}"154end155156def evasion_commands157{}158end159160def stance161'passive'162end163164def passive?165true166end167168def aggressive?169false170end171172# Generates the encoded version of the supplied payload using the payload173# requirements specific to this evasion module. The encoded instance is returned174# to the caller. This method is exposed in the manner that it is such that passive175# evasions and re-generate an encoded payload on the fly rather than having to use176# the pre-generated one.177def generate_payload(pinst = nil)178# Set the encoded payload to the result of the encoding process179self.payload = generate_single_payload(pinst)180181# Save the payload instance182self.payload_instance = (pinst) ? pinst : self.payload_instance183184return self.payload185end186187def generate_single_payload(pinst = nil, platform = nil, arch = nil, explicit_target = nil)188explicit_target ||= target189190# If a payload instance was supplied, use it, otherwise191# use the active payload instance192real_payload = (pinst) ? pinst : self.payload_instance193194if (real_payload == nil)195raise MissingPayloadError, "No payload has been selected.",196caller197end198199# If this is a generic payload, then we should specify the platform200# and architecture so that it knows how to pass things on.201if real_payload.kind_of?(Msf::Payload::Generic)202# Convert the architecture specified into an array.203if arch and arch.kind_of?(String)204arch = [ arch ]205end206207# Define the explicit platform and architecture information only if208# it's been specified.209if platform210real_payload.explicit_platform = Msf::Module::PlatformList.transform(platform)211end212213if arch214real_payload.explicit_arch = arch215end216217# Force it to reset so that it will find updated information.218real_payload.reset219end220221# Duplicate the evasion payload requirements222reqs = self.payload_info.dup223224# Pass save register requirements to the NOP generator225reqs['Space'] = payload_info['Space'] ? payload_info['Space'].to_i : nil226reqs['SaveRegisters'] = module_info['SaveRegisters']227reqs['Prepend'] = payload_info['Prepend']228reqs['PrependEncoder'] = payload_info['PrependEncoder']229reqs['BadChars'] = payload_info['BadChars']230reqs['Append'] = payload_info['Append']231reqs['AppendEncoder'] = payload_info['AppendEncoder']232reqs['DisableNops'] = payload_info['DisableNops']233reqs['MaxNops'] = payload_info['MaxNops']234reqs['MinNops'] = payload_info['MinNops']235reqs['Encoder'] = datastore['ENCODER'] || payload_info['Encoder']236reqs['Nop'] = datastore['NOP'] || payload_info['Nop']237reqs['EncoderType'] = payload_info['EncoderType']238reqs['EncoderOptions'] = payload_info['EncoderOptions']239reqs['ExtendedOptions'] = payload_info['ExtendedOptions']240reqs['ForceEncode'] = payload_info['ForceEncode']241reqs['Evasion'] = self242243# Pass along the encoder don't fall through flag244reqs['EncoderDontFallThrough'] = datastore['EncoderDontFallThrough']245246# Incorporate any context encoding requirements that are needed247define_context_encoding_reqs(reqs)248249# Call the encode begin routine.250encode_begin(real_payload, reqs)251252# Generate the encoded payload.253encoded = EncodedPayload.create(real_payload, reqs)254255# Call the encode end routine which is expected to return the actual256# encoded payload instance.257return encode_end(real_payload, reqs, encoded)258end259260def define_context_encoding_reqs(reqs)261return unless datastore['EnableContextEncoding']262263# At present, we don't support any automatic methods of obtaining264# context information. In the future, we might support obtaining265# temporal information remotely.266267# Pass along the information specified in our evasion datastore as268# encoder options269reqs['EncoderOptions'] = {} if reqs['EncoderOptions'].nil?270reqs['EncoderOptions']['EnableContextEncoding'] = datastore['EnableContextEncoding']271reqs['EncoderOptions']['ContextInformationFile'] = datastore['ContextInformationFile']272end273274def encode_begin(real_payload, reqs)275end276277def encode_end(real_payload, reqs, encoded)278encoded279end280281def target282if self.respond_to?(:auto_targeted_index)283if auto_target?284auto_idx = auto_targeted_index285if auto_idx.present?286datastore['TARGET'] = auto_idx287else288# If our inserted Automatic Target was selected but we failed to289# find a suitable target, we just grab the original first target.290datastore['TARGET'] = 1291end292end293end294295target_idx = target_index296return (target_idx) ? targets[target_idx.to_i] : nil297end298299def target_index300target_idx =301begin302Integer(datastore['TARGET'])303rescue TypeError, ArgumentError304datastore['TARGET']305end306307default_idx = default_target || 0308# Use the default target if one was not supplied.309if (target_idx == nil and default_idx and default_idx >= 0)310target_idx = default_idx311elsif target_idx.is_a?(String)312target_idx = targets.index { |target| target.name == target_idx }313end314315return (target_idx) ? target_idx.to_i : nil316end317318def has_auto_target?(targets=[])319target_names = targets.collect { |target| target.first}320target_names.each do |target|321return true if target =~ /Automatic/322end323return false324end325326attr_accessor :default_target327328attr_accessor :targets329330attr_reader :payload_info331332attr_accessor :payload_info333334attr_accessor :payload_instance335336attr_accessor :payload337end338end339340341