Class: Msf::PayloadSet
- Defined in:
- lib/msf/core/payload_set.rb
Overview
This class is a special case of the generic module set class because payloads are generated in terms of combinations between various components, such as a stager and a stage. As such, the payload set needs to be built on the fly and cannot be simply matched one-to-one with a payload module. Yeah, the term module is kind of overloaded here, but eat it!
Instance Attribute Summary collapse
-
#_instances ⇒ Object
protected
:nodoc:.
-
#payload_type_modules ⇒ Object
protected
:nodoc:.
-
#singles ⇒ Object
The list of singles that have been loaded.
-
#stages ⇒ Object
The list of stages that have been loaded.
Attributes inherited from ModuleSet
#ambiguous_module_reference_name_set, #architectures_by_module, #mod_extensions, #mod_sorted, #module_type, #platforms_by_module
Attributes included from Framework::Offspring
Instance Method Summary collapse
- #_adapters ⇒ Object protected
-
#_singles ⇒ Object
protected
Return the hash of single payloads.
-
#_stagers ⇒ Object
protected
Return the hash of stager payloads.
-
#_stages ⇒ Object
protected
Return the hash of stage payloads.
-
#add_blob_cache(key, blob, offsets) ⇒ Object
Adds a blob to the blob cache so that the payload does not have to be recompiled in the future.
-
#add_module(payload_module, reference_name, modinfo = {}) ⇒ void
This method is called when a new payload module class is loaded up.
-
#add_single(p, name, modinfo) ⇒ Object
This method adds a single payload to the set and adds it to the singles hash.
-
#add_stage(p, full_name, stage_name, handler_type, modinfo) ⇒ Object
This method adds a stage payload to the set and adds it to the stages hash using the supplied handler type.
- #build_adapted_name(aname, pname) ⇒ Object protected
-
#build_payload(*modules) ⇒ Object
protected
Builds a duplicate, extended version of the Payload base class using the supplied modules.
-
#check_blob_cache(key) ⇒ Object
Checks to see if a payload has a blob cache entry.
-
#each_module_filter(opts, name, mod) ⇒ Object
Performs custom filtering during each_module enumeration.
-
#find_payload(platform, arch, handler, session, payload_type) ⇒ Object
Looks for a payload that matches the specified requirements and returns an instance of that payload.
-
#find_payload_from_set(set, platform, arch, handler, session, payload_type) ⇒ Object
Looks for a payload from a given set that matches the specified requirements and returns an instance of that payload.
-
#flush_blob_cache ⇒ Object
Flushes all entries from the blob cache.
-
#initialize ⇒ PayloadSet
constructor
Creates an instance of a payload set which is just a specialized module set class that has custom handling for payloads.
-
#instance(name) ⇒ Object
Returns a single read-only instance of the supplied payload name such that specific attributes, like compatibility, can be evaluated.
-
#on_module_reload(mod) ⇒ Object
When a payload module is reloaded, the blob cache entry associated with it must be removed (if one exists).
-
#recalculate ⇒ Object
This method builds the hash of alias names based on all the permutations of singles, stagers, and stages.
-
#stagers ⇒ Object
Returns the hash of payload stagers that have been loaded.
Methods inherited from ModuleSet
#[], #create, #demand_load_modules, #each, #each_module, #each_module_list, #each_module_ranked, #force_load_set, #module_rank, #rank_modules, #valid?
Constructor Details
#initialize ⇒ PayloadSet
Creates an instance of a payload set which is just a specialized module set class that has custom handling for payloads.
20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 |
# File 'lib/msf/core/payload_set.rb', line 20 def initialize super(Msf::MODULE_PAYLOAD) # A hash of each of the payload types that holds an array # for all of the associated modules self.payload_type_modules = {} # Initialize the hash entry for each type to an empty list [ Payload::Type::Single, Payload::Type::Stager, Payload::Type::Stage, Payload::Type::Adapter ].each { |type| self.payload_type_modules[type] = {} } # Initialize hashes for each of the stages and singles. Stagers # never exist independent. The stages hash will have entries that # point to another hash that point to the per-stager implementation # payload class. For instance: # # ['windows/shell']['reverse_tcp'] # # Singles will simply point to the single payload class. self.stages = {} self.singles = {} # Single instance cache of modules for use with doing quick referencing # of attributes that would require an instance. self._instances = {} # Initializes an empty blob cache @blob_cache = {} end |
Instance Attribute Details
#_instances ⇒ Object (protected)
:nodoc:
472 473 474 |
# File 'lib/msf/core/payload_set.rb', line 472 def _instances @_instances end |
#payload_type_modules ⇒ Object (protected)
:nodoc:
470 471 472 |
# File 'lib/msf/core/payload_set.rb', line 470 def payload_type_modules @payload_type_modules end |
#singles ⇒ Object
The list of singles that have been loaded.
415 416 417 |
# File 'lib/msf/core/payload_set.rb', line 415 def singles @singles end |
#stages ⇒ Object
The list of stages that have been loaded.
411 412 413 |
# File 'lib/msf/core/payload_set.rb', line 411 def stages @stages end |
Instance Method Details
#_adapters ⇒ Object (protected)
419 420 421 |
# File 'lib/msf/core/payload_set.rb', line 419 def _adapters return payload_type_modules[Payload::Type::Adapter] || {} end |
#_singles ⇒ Object (protected)
Return the hash of single payloads
426 427 428 |
# File 'lib/msf/core/payload_set.rb', line 426 def _singles return payload_type_modules[Payload::Type::Single] || {} end |
#_stagers ⇒ Object (protected)
Return the hash of stager payloads
433 434 435 |
# File 'lib/msf/core/payload_set.rb', line 433 def _stagers return payload_type_modules[Payload::Type::Stager] || {} end |
#_stages ⇒ Object (protected)
Return the hash of stage payloads
440 441 442 |
# File 'lib/msf/core/payload_set.rb', line 440 def _stages return payload_type_modules[Payload::Type::Stage] || {} end |
#add_blob_cache(key, blob, offsets) ⇒ Object
Adds a blob to the blob cache so that the payload does not have to be recompiled in the future
389 390 391 |
# File 'lib/msf/core/payload_set.rb', line 389 def add_blob_cache(key, blob, offsets) @blob_cache[key] = [ blob, offsets ] end |
#add_module(payload_module, reference_name, modinfo = {}) ⇒ void
This method returns an undefined value.
This method is called when a new payload module class is loaded up. For the payload set we simply create an instance of the class and do some magic to figure out if it's a single, stager, or stage. Depending on which it is, we add it to the appropriate list.
224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 |
# File 'lib/msf/core/payload_set.rb', line 224 def add_module(payload_module, reference_name, modinfo={}) if (md = reference_name.match(/^(adapters|singles|stagers|stages)#{File::SEPARATOR}(.*)$/)) ptype = md[1] reference_name = md[2] end # Duplicate the Payload base class and extend it with the module # class that is passed in. This allows us to inspect the actual # module to see what type it is, and to grab other information for # our own evil purposes. instance = build_payload(payload_module).new # Create an array of information about this payload module pinfo = [ payload_module, instance.handler_klass, instance.platform, instance.arch, instance, modinfo ] # Use the module's preferred alias if it has one reference_name = instance.alias if (instance.alias) # Store the module and alias name for this payload. We # also convey other information about the module, such as # the platforms and architectures it supports payload_type_modules[instance.payload_type][reference_name] = pinfo end |
#add_single(p, name, modinfo) ⇒ Object
This method adds a single payload to the set and adds it to the singles hash.
316 317 318 319 320 321 322 323 324 325 326 327 328 |
# File 'lib/msf/core/payload_set.rb', line 316 def add_single(p, name, modinfo) p.framework = framework p.refname = name p.file_path = modinfo['files'][0] # Associate this class with the single payload's name self[name] = p # Add the singles hash singles[name] = p dlog("Built single payload #{name}.", 'core', LEV_2) end |
#add_stage(p, full_name, stage_name, handler_type, modinfo) ⇒ Object
This method adds a stage payload to the set and adds it to the stages hash using the supplied handler type.
334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 |
# File 'lib/msf/core/payload_set.rb', line 334 def add_stage(p, full_name, stage_name, handler_type, modinfo) p.framework = framework p.refname = full_name p.file_path = modinfo['files'][0] # Associate this stage's full name with the payload class in the set self[full_name] = p # Create the hash entry for this stage and then create # the associated entry for the handler type stages[stage_name] = {} if (!stages[stage_name]) # Add it to this stage's stager hash stages[stage_name][handler_type] = p dlog("Built staged payload #{full_name}.", 'core', LEV_2) end |
#build_adapted_name(aname, pname) ⇒ Object (protected)
461 462 463 464 465 466 467 468 |
# File 'lib/msf/core/payload_set.rb', line 461 def build_adapted_name(aname, pname) aparts = aname.split('/') pparts = pname.split('/') pparts.shift if aparts.last.start_with?(pparts.first) aparts.each { |apart| pparts.delete(apart) if pparts.include?(apart) } (aparts + pparts).join('/') end |
#build_payload(*modules) ⇒ Object (protected)
Builds a duplicate, extended version of the Payload base class using the supplied modules.
448 449 450 451 452 453 454 455 456 457 458 459 |
# File 'lib/msf/core/payload_set.rb', line 448 def build_payload(*modules) klass = Class.new(Payload) # Remove nil modules modules.compact! # Include the modules supplied to us with the mad skillz # spoonfu style klass.include(*modules.reverse) return klass end |
#check_blob_cache(key) ⇒ Object
Checks to see if a payload has a blob cache entry. If it does, the blob is returned to the caller.
397 398 399 |
# File 'lib/msf/core/payload_set.rb', line 397 def check_blob_cache(key) @blob_cache[key] end |
#each_module_filter(opts, name, mod) ⇒ Object
Performs custom filtering during each_module enumeration. This allows us to filter out certain stagers as necessary.
60 61 62 |
# File 'lib/msf/core/payload_set.rb', line 60 def each_module_filter(opts, name, mod) return false end |
#find_payload(platform, arch, handler, session, payload_type) ⇒ Object
Looks for a payload that matches the specified requirements and returns an instance of that payload.
261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 |
# File 'lib/msf/core/payload_set.rb', line 261 def find_payload(platform, arch, handler, session, payload_type) # Pre-filter based on platform and architecture. each_module( 'Platform' => platform, 'Arch' => arch) { |name, mod| p = mod.new # We can't substitute one generic with another one. next if (p.kind_of?(Msf::Payload::Generic)) # Check to see if the handler classes match. next if (handler and not p.handler_klass.ancestors.include?(handler)) # Check to see if the session classes match. next if (session and p.session and not p.session.ancestors.include?(session)) # Check for matching payload types next if (payload_type and p.payload_type != payload_type) return p } return nil end |
#find_payload_from_set(set, platform, arch, handler, session, payload_type) ⇒ Object
Looks for a payload from a given set that matches the specified requirements and returns an instance of that payload.
291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 |
# File 'lib/msf/core/payload_set.rb', line 291 def find_payload_from_set(set, platform, arch, handler, session, payload_type) set.each do |name, mod| p = mod.new # We can't substitute one generic with another one. next if (p.kind_of?(Msf::Payload::Generic)) # Check to see if the handler classes match. next if (handler and p.handler_klass != handler) # Check to see if the session classes match. next if (session and p.session != session) # Check for matching payload types next if (payload_type and p.payload_type != payload_type) return p end return nil end |
#flush_blob_cache ⇒ Object
Flushes all entries from the blob cache
404 405 406 |
# File 'lib/msf/core/payload_set.rb', line 404 def flush_blob_cache @blob_cache.clear end |
#instance(name) ⇒ Object
Returns a single read-only instance of the supplied payload name such that specific attributes, like compatibility, can be evaluated. The payload instance returned should NOT be used for anything other than reading.
358 359 360 361 362 363 364 |
# File 'lib/msf/core/payload_set.rb', line 358 def instance(name) if (self._instances[name] == nil) self._instances[name] = create(name) end self._instances[name] end |
#on_module_reload(mod) ⇒ Object
When a payload module is reloaded, the blob cache entry associated with it must be removed (if one exists)
377 378 379 380 381 382 383 |
# File 'lib/msf/core/payload_set.rb', line 377 def on_module_reload(mod) @blob_cache.each_key do |key| if key.start_with? mod.refname @blob_cache.delete(key) end end end |
#recalculate ⇒ Object
This method builds the hash of alias names based on all the permutations of singles, stagers, and stages.
68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 |
# File 'lib/msf/core/payload_set.rb', line 68 def recalculate old_keys = self.keys new_keys = [] # Recalculate single payloads _singles.each_pair { |name, op| mod, handler = op # if the payload has a dependency, check # if it is supported on the system payload_dependencies = op[4].dependencies unless payload_dependencies.empty? supported = payload_dependencies.all?(&:available?) elog("Dependency for #{name} is not supported") unless supported next unless supported end # Build the payload dupe using the determined handler # and module p = build_payload(handler, mod) # Add it to the set add_single(p, name, op[5]) new_keys.push name _adapters.each_pair { |adapter_name, ep| adapter_mod, _, adapter_platform, adapter_arch, adapter_inst = ep next unless adapter_inst.compatible?(p.new) ap = build_payload(handler, mod, adapter_mod) combined = build_adapted_name(adapter_name, p.refname) add_single(ap, combined, ep[5]) new_keys.push combined } } # Recalculate staged payloads _stagers.each_pair { |stager_name, op| stager_mod, handler, stager_platform, stager_arch, stager_inst = op # Pass if the stager has a dependency # and doesn't have the dependency installed stager_dependencies = stager_inst.dependencies unless stager_dependencies.empty? supported = stager_dependencies.all?(&:available?) elog("Dependency for #{stager_name} is not supported") unless supported next unless supported end # Walk the array of stages _stages.each_pair { |stage_name, ip| stage_mod, _, stage_platform, stage_arch, stage_inst = ip # # if the stager or stage has a dependency, check # if they are compatible # unless stager_dependencies.empty? && stage_inst.dependencies.empty? next unless stager_dependencies == stage_inst.dependencies end # No intersection between platforms on the payloads? if ((stager_platform) and (stage_platform) and (stager_platform & stage_platform).empty?) dlog("Stager #{stager_name} and stage #{stage_name} have incompatible platforms: #{stager_platform.names} - #{stage_platform.names}", 'core', LEV_2) next end # No intersection between architectures on the payloads? if ((stager_arch) and (stage_arch) and ((stager_arch & stage_arch).empty?)) dlog("Stager #{stager_name} and stage #{stage_name} have incompatible architectures: #{stager_arch.join} - #{stage_arch.join}", 'core', LEV_2) next end # If the stage has a convention, make sure it's compatible with # the stager's if ((stage_inst) and (stage_inst.compatible?(stager_inst) == false)) dlog("Stager #{stager_name} and stage #{stage_name} are incompatible.", 'core', LEV_2) next end # Build the payload dupe using the handler, stager, # and stage p = build_payload(handler, stager_mod, stage_mod) # If the stager has an alias for the handler type (such as is the # case for ordinal based stagers), use it in preference of the # handler's actual type. if (stager_mod.respond_to?('handler_type_alias') == true) handler_type = stager_mod.handler_type_alias else handler_type = handler.handler_type end # Associate the name as a combination of the stager and stage combined = stage_name # If a valid handler exists for this stager, then combine it combined += '/' + handler_type # Sets the modules derived name p.refname = combined # Add the stage add_stage(p, combined, stage_name, handler_type, { 'files' => op[5]['files'] + ip[5]['files'], 'paths' => op[5]['paths'] + ip[5]['paths'], 'type' => op[5]['type']}) new_keys.push combined _adapters.each_pair { |adapter_name, ep| adapter_mod, _, adapter_platform, adapter_arch, adapter_inst = ep next unless adapter_inst.compatible?(p.new) ap = build_payload(handler, stager_mod, stage_mod, adapter_mod) combined = build_adapted_name(adapter_name, p.refname) ap.refname = combined ap.framework = framework ap.file_path = ep[5]['files'][0] self[combined] = ap new_keys.push combined } } } # Blow away anything that was cached but didn't exist during the # recalculation self.delete_if do |k, v| next if v == SymbolicModule !!(old_keys.include?(k) and not new_keys.include?(k)) end flush_blob_cache end |
#stagers ⇒ Object
Returns the hash of payload stagers that have been loaded.
369 370 371 |
# File 'lib/msf/core/payload_set.rb', line 369 def stagers _stagers end |