PageRenderTime 38ms CodeModel.GetById 13ms RepoModel.GetById 0ms app.codeStats 0ms

/lib/msf/core/payload/stager.rb

https://gitlab.com/JakenHerman/metasploit-framework
Ruby | 293 lines | 137 code | 45 blank | 111 comment | 20 complexity | 08880f5ec4179129b7c65483abba9957 MD5 | raw file
Possible License(s): Apache-2.0, GPL-3.0, GPL-2.0, LGPL-2.1, BSD-3-Clause
  1. # -*- coding: binary -*-
  2. require 'msf/core'
  3. require 'msf/core/option_container'
  4. ###
  5. #
  6. # Base mixin interface for use by stagers.
  7. #
  8. ###
  9. module Msf::Payload::Stager
  10. def initialize(info={})
  11. super
  12. register_advanced_options(
  13. [
  14. Msf::OptBool.new("EnableStageEncoding", [ false, "Encode the second stage payload", false ]),
  15. Msf::OptString.new("StageEncoder", [ false, "Encoder to use if EnableStageEncoding is set", nil ]),
  16. Msf::OptString.new("StageEncoderSaveRegisters", [ false, "Additional registers to preserve in the staged payload if EnableStageEncoding is set", "" ]),
  17. Msf::OptBool.new("StageEncodingFallback", [ false, "Fallback to default encoders or no encoding if the selected StageEncoder is not compatible", true ])
  18. ], Msf::Payload::Stager)
  19. end
  20. #
  21. # Sets the payload type to a stager.
  22. #
  23. def payload_type
  24. return Msf::Payload::Type::Stager
  25. end
  26. #
  27. # Return the stager payload's raw payload.
  28. #
  29. # Can be nil if the stager is not pre-assembled.
  30. #
  31. # @return [String,nil]
  32. def payload
  33. return module_info['Stager']['Payload']
  34. end
  35. #
  36. # Return the stager payload's assembly text, if any.
  37. #
  38. # @return [String,nil]
  39. def assembly
  40. return module_info['Stager']['Assembly']
  41. end
  42. #
  43. # Return the stager payload's offsets.
  44. #
  45. # These will be used for substitutions during stager generation.
  46. #
  47. # @return [Hash]
  48. def offsets
  49. return module_info['Stager']['Offsets']
  50. end
  51. #
  52. # Returns the raw stage payload.
  53. #
  54. # Can be nil if the final stage is not pre-assembled.
  55. #
  56. # @return [String,nil]
  57. def stage_payload
  58. return module_info['Stage']['Payload']
  59. end
  60. #
  61. # Returns the assembly text of the stage payload.
  62. #
  63. # @return [String]
  64. def stage_assembly
  65. return module_info['Stage']['Assembly']
  66. end
  67. #
  68. # Returns variable offsets within the stage payload.
  69. #
  70. # These will be used for substitutions during generation of the final
  71. # stage.
  72. #
  73. # @return [Hash]
  74. def stage_offsets
  75. return module_info['Stage']['Offsets']
  76. end
  77. #
  78. # Whether or not any stages associated with this stager should be sent over
  79. # the connection that is established.
  80. #
  81. def stage_over_connection?
  82. true
  83. end
  84. #
  85. # Whether to use an Encoder on the second stage
  86. #
  87. # @return [Boolean]
  88. def encode_stage?
  89. !!(datastore['EnableStageEncoding'])
  90. end
  91. #
  92. # Generates the stage payload and substitutes all offsets.
  93. #
  94. # @return [String] The generated payload stage, as a string.
  95. def generate_stage
  96. # XXX: This is nearly identical to Payload#internal_generate
  97. # Compile the stage as necessary
  98. if stage_assembly and !stage_assembly.empty?
  99. raw = build(stage_assembly, stage_offsets)
  100. else
  101. raw = stage_payload.dup
  102. end
  103. # Substitute variables in the stage
  104. substitute_vars(raw, stage_offsets) if (stage_offsets)
  105. return raw
  106. end
  107. #
  108. # Transmit the associated stage.
  109. #
  110. # @param (see handle_connection_stage)
  111. # @return (see handle_connection_stage)
  112. def handle_connection(conn, opts={})
  113. # If the stage should be sent over the client connection that is
  114. # established (which is the default), then go ahead and transmit it.
  115. if (stage_over_connection?)
  116. p = generate_stage
  117. # Encode the stage if stage encoding is enabled
  118. begin
  119. p = encode_stage(p)
  120. rescue ::RuntimeError
  121. warning_msg = "Failed to stage"
  122. warning_msg << " (#{conn.peerhost})" if conn.respond_to? :peerhost
  123. warning_msg << ": #{$!}"
  124. print_warning warning_msg
  125. if conn.respond_to? :close && !conn.closed?
  126. conn.close
  127. end
  128. return
  129. end
  130. # Give derived classes an opportunity to an intermediate state before
  131. # the stage is sent. This gives derived classes an opportunity to
  132. # augment the stage and the process through which it is read on the
  133. # remote machine.
  134. #
  135. # If we don't use an intermediate stage, then we need to prepend the
  136. # stage prefix, such as a tag
  137. if handle_intermediate_stage(conn, p) == false
  138. p = (self.stage_prefix || '') + p
  139. end
  140. sending_msg = "Sending #{encode_stage? ? "encoded ":""}stage"
  141. sending_msg << " (#{p.length} bytes)"
  142. # The connection should always have a peerhost (even if it's a
  143. # tunnel), but if it doesn't, erroring out here means losing the
  144. # session, so make sure it does, just to be safe.
  145. if conn.respond_to? :peerhost
  146. sending_msg << " to #{conn.peerhost}"
  147. end
  148. print_status(sending_msg)
  149. # Send the stage
  150. conn.put(p)
  151. end
  152. # If the stage implements the handle connection method, sleep before
  153. # handling it.
  154. if (derived_implementor?(Msf::Payload::Stager, 'handle_connection_stage'))
  155. print_status("Sleeping before handling stage...")
  156. # Sleep before processing the stage
  157. Rex::ThreadSafe.sleep(1.5)
  158. end
  159. # Give the stages a chance to handle the connection
  160. handle_connection_stage(conn, opts)
  161. end
  162. #
  163. # Allow the stage to process whatever it is it needs to process.
  164. #
  165. # Override to deal with sending the final stage in cases where
  166. # {#generate_stage} is not the whole picture, such as when uploading
  167. # an executable. The default is to simply attempt to create a session
  168. # on the given +conn+ socket with {Msf::Handler#create_session}.
  169. #
  170. # @param (see Handler#create_session)
  171. # @return (see Handler#create_session)
  172. def handle_connection_stage(conn, opts={})
  173. create_session(conn, opts)
  174. end
  175. #
  176. # Gives derived classes an opportunity to alter the stage and/or
  177. # encapsulate its transmission.
  178. #
  179. def handle_intermediate_stage(conn, payload)
  180. false
  181. end
  182. #
  183. # Takes an educated guess at the list of registers an encoded stage
  184. # would need to preserve based on the Convention
  185. #
  186. def encode_stage_preserved_registers
  187. module_info['Convention'].to_s.scan(/\bsock([a-z]{3,}+)\b/).
  188. map {|reg| reg.first }.
  189. join(" ")
  190. end
  191. # Encodes the stage prior to transmission
  192. # @return [String] Encoded version of +stg+
  193. def encode_stage(stg)
  194. return stg unless encode_stage?
  195. stage_enc_mod = []
  196. # Handle StageEncoder if specified by the user
  197. if datastore['StageEncoder'].to_s.length > 0
  198. # Allow multiple encoders separated by commas
  199. stage_enc_mod = datastore["StageEncoder"].split(',').map(&:strip).select{|x| x.to_s.length > 0}.uniq
  200. end
  201. # Add automatic encoding as a fallback if needed
  202. if datastore['StageEncodingFallback']
  203. stage_enc_mod << nil
  204. end
  205. # If fallback has been disabled and no encoder was parsed, exit early and rop the session
  206. if stage_enc_mod.length == 0
  207. raise RuntimeError, "StageEncoder is invalid and StageEncodingFallback is disabled"
  208. end
  209. # Allow the user to specify additional registers to preserve
  210. saved_registers =
  211. datastore['StageEncoderSaveRegisters'].to_s +
  212. " " +
  213. encode_stage_preserved_registers
  214. saved_registers.strip!
  215. estg = nil
  216. stage_enc_mod.each do |encoder_refname_from_user|
  217. # Generate an encoded version of the stage. We tell the encoding system
  218. # to save certain registers to ensure that it does not get clobbered.
  219. encp = Msf::EncodedPayload.create(
  220. self,
  221. 'Raw' => stg,
  222. 'Encoder' => encoder_refname_from_user,
  223. 'EncoderOptions' => { 'SaveRegisters' => saved_registers },
  224. 'ForceSaveRegisters' => true,
  225. 'ForceEncode' => true)
  226. if encp.encoder
  227. print_status("Encoded stage with #{encp.encoder.refname}")
  228. estg = encp.encoded
  229. break
  230. end
  231. end
  232. if datastore['StageEncodingFallback'] && estg.nil?
  233. print_warning("StageEncoder failed, falling back to no encoding")
  234. estg = stg
  235. end
  236. unless estg
  237. raise RuntimeError, "Stage encoding failed and StageEncodingFallback is disabled"
  238. end
  239. estg
  240. end
  241. # Aliases
  242. alias stager_payload payload
  243. alias stager_offsets offsets
  244. #
  245. # A value that should be prefixed to a stage, such as a tag.
  246. #
  247. attr_accessor :stage_prefix
  248. end