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.

powershell.rb 7.7KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218
  1. # -*- coding: binary -*-
  2. require 'rex/powershell'
  3. module Msf
  4. module Exploit::Powershell
  5. def initialize(info = {})
  6. super
  7. register_advanced_options(
  8. [
  9. OptBool.new('Powershell::persist', [true, 'Run the payload in a loop', false]),
  10. OptInt.new('Powershell::prepend_sleep', [false, 'Prepend seconds of sleep']),
  11. OptBool.new('Powershell::strip_comments', [true, 'Strip comments', true]),
  12. OptBool.new('Powershell::strip_whitespace', [true, 'Strip whitespace', false]),
  13. OptBool.new('Powershell::sub_vars', [true, 'Substitute variable names', false]),
  14. OptBool.new('Powershell::sub_funcs', [true, 'Substitute function names', false]),
  15. OptEnum.new('Powershell::method', [true, 'Payload delivery method', 'reflection', %w(net reflection old msil)]),
  16. ], self.class)
  17. end
  18. #
  19. # Return a script from path or string
  20. #
  21. def read_script(script_path)
  22. return Rex::Powershell::Script.new(script_path)
  23. end
  24. #
  25. # Return an array of substitutions for use in make_subs
  26. #
  27. def process_subs(subs)
  28. return [] if subs.nil? or subs.empty?
  29. new_subs = []
  30. subs.split(';').each do |set|
  31. new_subs << set.split(',', 2)
  32. end
  33. new_subs
  34. end
  35. #
  36. # Insert substitutions into the powershell script
  37. # If script is a path to a file then read the file
  38. # otherwise treat it as the contents of a file
  39. #
  40. def make_subs(script, subs)
  41. subs.each do |set|
  42. script.gsub!(set[0],set[1])
  43. end
  44. script
  45. end
  46. #
  47. # Return an encoded powershell script
  48. # Will invoke PSH modifiers as enabled
  49. #
  50. # @param script_in [String] Script contents
  51. #
  52. # @return [String] Encoded script
  53. def encode_script(script_in, eof = nil)
  54. opts = {}
  55. datastore.select { |k, v| k =~ /^Powershell::(strip|sub)/ && v }.keys.map do |k|
  56. mod_method = k.split('::').last.intern
  57. opts[mod_method.to_sym] = true
  58. end
  59. Rex::Powershell::Command.encode_script(script_in, eof, opts)
  60. end
  61. #
  62. # Return a gzip compressed powershell script
  63. # Will invoke PSH modifiers as enabled
  64. #
  65. # @param script_in [String] Script contents
  66. # @param eof [String] Marker to indicate the end of file appended to script
  67. #
  68. # @return [String] Compressed script with decompression stub
  69. def compress_script(script_in, eof=nil)
  70. opts = {}
  71. datastore.select { |k, v| k =~ /^Powershell::(strip|sub)/ && v }.keys.map do |k|
  72. mod_method = k.split('::').last.intern
  73. opts[mod_method.to_sym] = true
  74. end
  75. Rex::Powershell::Command.compress_script(script_in, eof, opts)
  76. end
  77. #
  78. # Generate a powershell command line, options are passed on to
  79. # generate_psh_args
  80. #
  81. # @param opts [Hash] The options to generate the command line
  82. # @option opts [String] :path Path to the powershell binary
  83. # @option opts [Boolean] :no_full_stop Whether powershell binary
  84. # should include .exe
  85. #
  86. # @return [String] Powershell command line with arguments
  87. def generate_psh_command_line(opts)
  88. Rex::Powershell::Command.generate_psh_command_line(opts)
  89. end
  90. #
  91. # Generate arguments for the powershell command
  92. # The format will be have no space at the start and have a space
  93. # afterwards e.g. "-Arg1 x -Arg -Arg x "
  94. #
  95. # @param opts [Hash] The options to generate the command line
  96. # @option opts [Boolean] :shorten Whether to shorten the powershell
  97. # arguments (v2.0 or greater)
  98. # @option opts [String] :encodedcommand Powershell script as an
  99. # encoded command (-EncodedCommand)
  100. # @option opts [String] :executionpolicy The execution policy
  101. # (-ExecutionPolicy)
  102. # @option opts [String] :inputformat The input format (-InputFormat)
  103. # @option opts [String] :file The path to a powershell file (-File)
  104. # @option opts [Boolean] :noexit Whether to exit powershell after
  105. # execution (-NoExit)
  106. # @option opts [Boolean] :nologo Whether to display the logo (-NoLogo)
  107. # @option opts [Boolean] :noninteractive Whether to load a non
  108. # interactive powershell (-NonInteractive)
  109. # @option opts [Boolean] :mta Whether to run as Multi-Threaded
  110. # Apartment (-Mta)
  111. # @option opts [String] :outputformat The output format
  112. # (-OutputFormat)
  113. # @option opts [Boolean] :sta Whether to run as Single-Threaded
  114. # Apartment (-Sta)
  115. # @option opts [Boolean] :noprofile Whether to use the current users
  116. # powershell profile (-NoProfile)
  117. # @option opts [String] :windowstyle The window style to use
  118. # (-WindowStyle)
  119. #
  120. # @return [String] Powershell command arguments
  121. def generate_psh_args(opts)
  122. return '' unless opts
  123. unless opts.key? :shorten
  124. opts[:shorten] = (datastore['Powershell::method'] != 'old')
  125. end
  126. Rex::Powershell::Command.generate_psh_args(opts)
  127. end
  128. #
  129. # Wraps the powershell code to launch a hidden window and
  130. # detect the execution environment and spawn the appropriate
  131. # powershell executable for the payload architecture.
  132. #
  133. # @param ps_code [String] Powershell code
  134. # @param payload_arch [String] The payload architecture 'x86'/'x86_64'
  135. # @param encoded [Boolean] Indicates whether ps_code is encoded or not
  136. # @return [String] Wrapped powershell code
  137. def run_hidden_psh(ps_code, payload_arch, encoded)
  138. arg_opts = {
  139. noprofile: true,
  140. windowstyle: 'hidden',
  141. }
  142. # Old technique fails if powershell exits..
  143. arg_opts[:noexit] = (datastore['Powershell::method'] == 'old')
  144. arg_opts[:shorten] = (datastore['Powershell::method'] != 'old')
  145. Rex::Powershell::Command.run_hidden_psh(ps_code, payload_arch, encoded, arg_opts)
  146. end
  147. #
  148. # Creates a powershell command line string which will execute the
  149. # payload in a hidden window in the appropriate execution environment
  150. # for the payload architecture. Opts are passed through to
  151. # run_hidden_psh, generate_psh_command_line and generate_psh_args
  152. #
  153. # @param pay [String] The payload shellcode
  154. # @param payload_arch [String] The payload architecture 'x86'/'x86_64'
  155. # @param opts [Hash] The options to generate the command
  156. # @option opts [Boolean] :persist Loop the payload to cause
  157. # re-execution if the shellcode finishes
  158. # @option opts [Integer] :prepend_sleep Sleep for the specified time
  159. # before executing the payload
  160. # @option opts [String] :method The powershell injection technique to
  161. # use: 'net'/'reflection'/'old'
  162. # @option opts [Boolean] :encode_inner_payload Encodes the powershell
  163. # script within the hidden/architecture detection wrapper
  164. # @option opts [Boolean] :encode_final_payload Encodes the final
  165. # powershell script
  166. # @option opts [Boolean] :remove_comspec Removes the %COMSPEC%
  167. # environment variable at the start of the command line
  168. # @option opts [Boolean] :use_single_quotes Wraps the -Command
  169. # argument in single quotes unless :encode_final_payload
  170. #
  171. # @return [String] Powershell command line with payload
  172. def cmd_psh_payload(pay, payload_arch, opts = {})
  173. opts[:persist] ||= datastore['Powershell::persist']
  174. opts[:prepend_sleep] ||= datastore['Powershell::prepend_sleep']
  175. opts[:method] ||= datastore['Powershell::method']
  176. unless opts.key? :shorten
  177. opts[:shorten] = (datastore['Powershell::method'] != 'old')
  178. end
  179. template_path = File.join(Msf::Config.data_directory,
  180. "templates",
  181. "scripts")
  182. command = Rex::Powershell::Command.cmd_psh_payload(pay,
  183. payload_arch,
  184. template_path,
  185. opts)
  186. vprint_status("Powershell command length: #{command.length}")
  187. command
  188. end
  189. #
  190. # Useful method cache
  191. #
  192. module PshMethods
  193. include Rex::Powershell::PshMethods
  194. end
  195. end
  196. end