Mirror of metasploit
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

payload_set.rb 12KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431
  1. # -*- coding: binary -*-
  2. require 'msf/core'
  3. require 'msf/core/module_manager'
  4. module Msf
  5. ###
  6. #
  7. # This class is a special case of the generic module set class because
  8. # payloads are generated in terms of combinations between various
  9. # components, such as a stager and a stage. As such, the payload set
  10. # needs to be built on the fly and cannot be simply matched one-to-one
  11. # with a payload module. Yeah, the term module is kind of overloaded
  12. # here, but eat it!
  13. #
  14. ###
  15. class PayloadSet < ModuleSet
  16. #
  17. # Creates an instance of a payload set which is just a specialized module
  18. # set class that has custom handling for payloads.
  19. #
  20. def initialize
  21. super(Msf::MODULE_PAYLOAD)
  22. # A hash of each of the payload types that holds an array
  23. # for all of the associated modules
  24. self.payload_type_modules = {}
  25. # Initialize the hash entry for each type to an empty list
  26. [
  27. Payload::Type::Single,
  28. Payload::Type::Stager,
  29. Payload::Type::Stage
  30. ].each { |type|
  31. self.payload_type_modules[type] = {}
  32. }
  33. # Initialize hashes for each of the stages and singles. Stagers
  34. # never exist independent. The stages hash will have entries that
  35. # point to another hash that point to the per-stager implementation
  36. # payload class. For instance:
  37. #
  38. # ['windows/shell']['reverse_tcp']
  39. #
  40. # Singles will simply point to the single payload class.
  41. self.stages = {}
  42. self.singles = {}
  43. # Hash that caches the sizes of payloads
  44. self.sizes = {}
  45. # Single instance cache of modules for use with doing quick referencing
  46. # of attributes that would require an instance.
  47. self._instances = {}
  48. # Initializes an empty blob cache
  49. @blob_cache = {}
  50. end
  51. #
  52. # Performs custom filtering during each_module enumeration. This allows us
  53. # to filter out certain stagers as necessary.
  54. #
  55. def each_module_filter(opts, name, mod)
  56. return false
  57. end
  58. #
  59. # This method builds the hash of alias names based on all the permutations
  60. # of singles, stagers, and stages.
  61. #
  62. def recalculate
  63. old_keys = self.keys
  64. new_keys = []
  65. # Recalculate single payloads
  66. _singles.each_pair { |name, op|
  67. mod, handler = op
  68. # Build the payload dupe using the determined handler
  69. # and module
  70. p = build_payload(handler, mod)
  71. # Add it to the set
  72. add_single(p, name, op[5])
  73. new_keys.push name
  74. # Cache the payload's size
  75. begin
  76. sizes[name] = p.cached_size || p.new.size
  77. # Don't cache generic payload sizes.
  78. rescue NoCompatiblePayloadError
  79. end
  80. }
  81. # Recalculate staged payloads
  82. _stagers.each_pair { |stager_name, op|
  83. stager_mod, handler, stager_platform, stager_arch, stager_inst = op
  84. # Walk the array of stages
  85. _stages.each_pair { |stage_name, ip|
  86. stage_mod, _, stage_platform, stage_arch, stage_inst = ip
  87. # No intersection between platforms on the payloads?
  88. if ((stager_platform) and
  89. (stage_platform) and
  90. (stager_platform & stage_platform).empty?)
  91. dlog("Stager #{stager_name} and stage #{stage_name} have incompatible platforms: #{stager_platform.names} - #{stage_platform.names}", 'core', LEV_2)
  92. next
  93. end
  94. # No intersection between architectures on the payloads?
  95. if ((stager_arch) and
  96. (stage_arch) and
  97. ((stager_arch & stage_arch).empty?))
  98. dlog("Stager #{stager_name} and stage #{stage_name} have incompatible architectures: #{stager_arch.join} - #{stage_arch.join}", 'core', LEV_2)
  99. next
  100. end
  101. # If the stage has a convention, make sure it's compatible with
  102. # the stager's
  103. if ((stage_inst) and (stage_inst.compatible?(stager_inst) == false))
  104. dlog("Stager #{stager_name} and stage #{stage_name} are incompatible.", 'core', LEV_2)
  105. next
  106. end
  107. # Build the payload dupe using the handler, stager,
  108. # and stage
  109. p = build_payload(handler, stager_mod, stage_mod)
  110. # If the stager has an alias for the handler type (such as is the
  111. # case for ordinal based stagers), use it in preference of the
  112. # handler's actual type.
  113. if (stager_mod.respond_to?('handler_type_alias') == true)
  114. handler_type = stager_mod.handler_type_alias
  115. else
  116. handler_type = handler.handler_type
  117. end
  118. # Associate the name as a combination of the stager and stage
  119. combined = stage_name
  120. # If a valid handler exists for this stager, then combine it
  121. combined += '/' + handler_type
  122. # Sets the modules derived name
  123. p.refname = combined
  124. # Add the stage
  125. add_stage(p, combined, stage_name, handler_type, {
  126. 'files' => op[5]['files'] + ip[5]['files'],
  127. 'paths' => op[5]['paths'] + ip[5]['paths'],
  128. 'type' => op[5]['type']})
  129. new_keys.push combined
  130. # Cache the payload's size
  131. sizes[combined] = p.cached_size || p.new.size
  132. }
  133. }
  134. # Blow away anything that was cached but didn't exist during the
  135. # recalculation
  136. self.delete_if do |k, v|
  137. next if v == SymbolicModule
  138. !!(old_keys.include?(k) and not new_keys.include?(k))
  139. end
  140. flush_blob_cache
  141. end
  142. # This method is called when a new payload module class is loaded up. For
  143. # the payload set we simply create an instance of the class and do some
  144. # magic to figure out if it's a single, stager, or stage. Depending on
  145. # which it is, we add it to the appropriate list.
  146. #
  147. # @param payload_module [::Module] The module name.
  148. # @param reference_name [String] The module reference name.
  149. # @param modinfo [Hash{String => Array}] additional information about the
  150. # module.
  151. # @option modinfo [Array<String>] 'files' List of paths to the ruby source
  152. # files where +class_or_module+ is defined.
  153. # @option modinfo [Array<String>] 'paths' List of module reference names.
  154. # @option modinfo [String] 'type' The module type, should match positional
  155. # +type+ argument.
  156. # @return [void]
  157. def add_module(payload_module, reference_name, modinfo={})
  158. if (md = reference_name.match(/^(singles|stagers|stages)#{File::SEPARATOR}(.*)$/))
  159. ptype = md[1]
  160. reference_name = md[2]
  161. end
  162. # Duplicate the Payload base class and extend it with the module
  163. # class that is passed in. This allows us to inspect the actual
  164. # module to see what type it is, and to grab other information for
  165. # our own evil purposes.
  166. instance = build_payload(payload_module).new
  167. # Create an array of information about this payload module
  168. pinfo =
  169. [
  170. payload_module,
  171. instance.handler_klass,
  172. instance.platform,
  173. instance.arch,
  174. instance,
  175. modinfo
  176. ]
  177. # Use the module's preferred alias if it has one
  178. reference_name = instance.alias if (instance.alias)
  179. # Store the module and alias name for this payload. We
  180. # also convey other information about the module, such as
  181. # the platforms and architectures it supports
  182. payload_type_modules[instance.payload_type][reference_name] = pinfo
  183. end
  184. #
  185. # Looks for a payload that matches the specified requirements and
  186. # returns an instance of that payload.
  187. #
  188. def find_payload(platform, arch, handler, session, payload_type)
  189. # Pre-filter based on platform and architecture.
  190. each_module(
  191. 'Platform' => platform,
  192. 'Arch' => arch) { |name, mod|
  193. p = mod.new
  194. # We can't substitute one generic with another one.
  195. next if (p.kind_of?(Msf::Payload::Generic))
  196. # Check to see if the handler classes match.
  197. next if (handler and not p.handler_klass.ancestors.include?(handler))
  198. # Check to see if the session classes match.
  199. next if (session and p.session and not p.session.ancestors.include?(session))
  200. # Check for matching payload types
  201. next if (payload_type and p.payload_type != payload_type)
  202. return p
  203. }
  204. return nil
  205. end
  206. #
  207. # Looks for a payload from a given set that matches the specified requirements and
  208. # returns an instance of that payload.
  209. #
  210. def find_payload_from_set(set, platform, arch, handler, session, payload_type)
  211. set.each do |name, mod|
  212. p = mod.new
  213. # We can't substitute one generic with another one.
  214. next if (p.kind_of?(Msf::Payload::Generic))
  215. # Check to see if the handler classes match.
  216. next if (handler and p.handler_klass != handler)
  217. # Check to see if the session classes match.
  218. next if (session and p.session != session)
  219. # Check for matching payload types
  220. next if (payload_type and p.payload_type != payload_type)
  221. return p
  222. end
  223. return nil
  224. end
  225. #
  226. # This method adds a single payload to the set and adds it to the singles
  227. # hash.
  228. #
  229. def add_single(p, name, modinfo)
  230. p.framework = framework
  231. p.refname = name
  232. p.file_path = modinfo['files'][0]
  233. # Associate this class with the single payload's name
  234. self[name] = p
  235. # Add the singles hash
  236. singles[name] = p
  237. dlog("Built single payload #{name}.", 'core', LEV_2)
  238. end
  239. #
  240. # This method adds a stage payload to the set and adds it to the stages
  241. # hash using the supplied handler type.
  242. #
  243. def add_stage(p, full_name, stage_name, handler_type, modinfo)
  244. p.framework = framework
  245. p.refname = full_name
  246. p.file_path = modinfo['files'][0]
  247. # Associate this stage's full name with the payload class in the set
  248. self[full_name] = p
  249. # Create the hash entry for this stage and then create
  250. # the associated entry for the handler type
  251. stages[stage_name] = {} if (!stages[stage_name])
  252. # Add it to this stage's stager hash
  253. stages[stage_name][handler_type] = p
  254. dlog("Built staged payload #{full_name}.", 'core', LEV_2)
  255. end
  256. #
  257. # Returns a single read-only instance of the supplied payload name such
  258. # that specific attributes, like compatibility, can be evaluated. The
  259. # payload instance returned should NOT be used for anything other than
  260. # reading.
  261. #
  262. def instance(name)
  263. if (self._instances[name] == nil)
  264. self._instances[name] = create(name)
  265. end
  266. self._instances[name]
  267. end
  268. #
  269. # Returns the hash of payload stagers that have been loaded.
  270. #
  271. def stagers
  272. _stagers
  273. end
  274. #
  275. # When a payload module is reloaded, the blob cache entry associated with
  276. # it must be removed (if one exists)
  277. #
  278. def on_module_reload(mod)
  279. @blob_cache.each_key do |key|
  280. if key.start_with? mod.refname
  281. @blob_cache.delete(key)
  282. end
  283. end
  284. end
  285. #
  286. # Adds a blob to the blob cache so that the payload does not have to be
  287. # recompiled in the future
  288. #
  289. def add_blob_cache(key, blob, offsets)
  290. @blob_cache[key] = [ blob, offsets ]
  291. end
  292. #
  293. # Checks to see if a payload has a blob cache entry. If it does, the blob
  294. # is returned to the caller.
  295. #
  296. def check_blob_cache(key)
  297. @blob_cache[key]
  298. end
  299. #
  300. # Flushes all entries from the blob cache
  301. #
  302. def flush_blob_cache
  303. @blob_cache.clear
  304. end
  305. #
  306. # The list of stages that have been loaded.
  307. #
  308. attr_reader :stages
  309. #
  310. # The list of singles that have been loaded.
  311. #
  312. attr_reader :singles
  313. #
  314. # The sizes of all the built payloads thus far.
  315. #
  316. attr_reader :sizes
  317. protected
  318. #
  319. # Return the hash of single payloads
  320. #
  321. def _singles
  322. return payload_type_modules[Payload::Type::Single] || {}
  323. end
  324. #
  325. # Return the hash of stager payloads
  326. #
  327. def _stagers
  328. return payload_type_modules[Payload::Type::Stager] || {}
  329. end
  330. #
  331. # Return the hash of stage payloads
  332. #
  333. def _stages
  334. return payload_type_modules[Payload::Type::Stage] || {}
  335. end
  336. #
  337. # Builds a duplicate, extended version of the Payload base
  338. # class using the supplied modules.
  339. #
  340. def build_payload(*modules)
  341. klass = Class.new(Payload)
  342. # Remove nil modules
  343. modules.compact!
  344. # Include the modules supplied to us with the mad skillz
  345. # spoonfu style
  346. klass.include(*modules.reverse)
  347. return klass
  348. end
  349. attr_accessor :payload_type_modules # :nodoc:
  350. attr_writer :stages, :singles, :sizes # :nodoc:
  351. attr_accessor :_instances # :nodoc:
  352. end
  353. end