Module: Msf::Exploit::Powershell

Included in:
Post::Windows::Powershell, Post::Windows::Runas
Defined in:
lib/msf/core/exploit/powershell.rb,
lib/msf/core/exploit/powershell/dot_net.rb

Defined Under Namespace

Modules: DotNet, PshMethods

Instance Method Summary collapse

Instance Method Details

#bypass_powershell_protectionsObject


246
247
248
# File 'lib/msf/core/exploit/powershell.rb', line 246

def bypass_powershell_protections
  Rex::Powershell::PshMethods.bypass_powershell_protections
end

#cmd_psh_payload(pay, payload_arch, opts = {}) ⇒ String

Creates a powershell command line string which will execute the payload in a hidden window in the appropriate execution environment for the payload architecture. Opts are passed through to run_hidden_psh, generate_psh_command_line and generate_psh_args

Parameters:

  • pay (String)

    The payload shellcode

  • payload_arch (String)

    The payload architecture 'x86'/'x86_64'

  • opts (Hash) (defaults to: {})

    The options to generate the command

Options Hash (opts):

  • :persist (Boolean)

    Loop the payload to cause re-execution if the shellcode finishes

  • :prepend_sleep (Integer)

    Sleep for the specified time before executing the payload

  • :exec_rc4 (Integer)

    Encrypt payload with RC4

  • :prepend_protections_bypass (Boolean)

    Prepend AMSI/SBL bypass

  • :exec_rc4 (Boolean)

    Encrypt payload with RC4

  • :method (String)

    The powershell injection technique to use: 'net'/'reflection'/'old'

  • :encode_inner_payload (Boolean)

    Encodes the powershell script within the hidden/architecture detection wrapper

  • :encode_final_payload (Boolean)

    Encodes the final powershell script

  • :remove_comspec (Boolean)

    Removes the %COMSPEC% environment variable at the start of the command line

  • :wrap_double_quotes (Boolean)

    Wraps the -Command argument in double quotes unless :encode_final_payload

Returns:

  • (String)

    Powershell command line with payload


229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
# File 'lib/msf/core/exploit/powershell.rb', line 229

def cmd_psh_payload(pay, payload_arch, opts = {})
  %i[persist prepend_sleep prepend_protections_bypass exec_in_place exec_rc4 encode_final_payload encode_inner_payload
  remove_comspec noninteractive wrap_double_quotes no_equals method].map do |opt|
    opts[opt] = datastore["Powershell::#{opt}"] if opts[opt].nil?
  end

  unless opts.key? :shorten
    opts[:shorten] = (datastore['Powershell::method'] != 'old')
  end

  template_path = Rex::Powershell::Templates::TEMPLATE_DIR
  command = Rex::Powershell::Command.cmd_psh_payload(pay, payload_arch, template_path, opts)
  vprint_status("Powershell command length: #{command.length}")

  command
end

#compress_script(script_in, eof = nil) ⇒ String

Return a gzip compressed powershell script Will invoke PSH modifiers as enabled

Parameters:

  • script_in (String)

    Script contents

  • eof (String) (defaults to: nil)

    Marker to indicate the end of file appended to script

Returns:

  • (String)

    Compressed script with decompression stub


102
103
104
105
106
107
108
109
110
# File 'lib/msf/core/exploit/powershell.rb', line 102

def compress_script(script_in, eof = nil)
  opts = {}
  datastore.select { |k, v| k =~ /^Powershell::(strip|sub)/ && v }.keys.map do |k|
    mod_method = k.split('::').last.intern
    opts[mod_method.to_sym] = true
  end

  Rex::Powershell::Command.compress_script(script_in, eof, opts)
end

#decode_script(script_in) ⇒ String

Return an decoded powershell script

Parameters:

  • script_in (String)

    Encoded contents

Returns:

  • (String)

    Decoded script


86
87
88
89
90
91
92
# File 'lib/msf/core/exploit/powershell.rb', line 86

def decode_script(script_in)
  return script_in unless
    script_in.to_s.match(%r{[A-Za-z0-9+/]+={0,3}})[0] == script_in.to_s &&
    (script_in.to_s.length % 4).zero?

  Rex::Powershell::Command.decode_script(script_in)
end

#decompress_script(script_in) ⇒ String

Return a decompressed powershell sript

Parameters:

  • script_in (String)

    Compressed contents with decompression stub

Returns:

  • (String)

    Decompressed script


118
119
120
121
122
# File 'lib/msf/core/exploit/powershell.rb', line 118

def decompress_script(script_in)
  return script_in unless script_in.match?(/FromBase64String/)

  Rex::Powershell::Command.decompress_script(script_in)
end

#encode_script(script_in, eof = nil) ⇒ String

Return an encoded powershell script Will invoke PSH modifiers as enabled

Parameters:

  • script_in (String)

    Script contents

Returns:

  • (String)

    Encoded script


70
71
72
73
74
75
76
77
78
# File 'lib/msf/core/exploit/powershell.rb', line 70

def encode_script(script_in, eof = nil)
  opts = {}
  datastore.select { |k, v| k =~ /^Powershell::(strip|sub)/ && v }.keys.map do |k|
    mod_method = k.split('::').last.intern
    opts[mod_method.to_sym] = true
  end

  Rex::Powershell::Command.encode_script(script_in, eof, opts)
end

#generate_psh_args(opts) ⇒ String

Generate arguments for the powershell command The format will be have no space at the start and have a space afterwards e.g. “-Arg1 x -Arg -Arg x ”

Parameters:

  • opts (Hash)

    The options to generate the command line

Options Hash (opts):

  • :shorten (Boolean)

    Whether to shorten the powershell arguments (v2.0 or greater)

  • :encodedcommand (String)

    Powershell script as an encoded command (-EncodedCommand)

  • :executionpolicy (String)

    The execution policy (-ExecutionPolicy)

  • :inputformat (String)

    The input format (-InputFormat)

  • :file (String)

    The path to a powershell file (-File)

  • :noexit (Boolean)

    Whether to exit powershell after execution (-NoExit)

  • :nologo (Boolean)

    Whether to display the logo (-NoLogo)

  • :noninteractive (Boolean)

    Whether to load a non interactive powershell (-NonInteractive)

  • :mta (Boolean)

    Whether to run as Multi-Threaded Apartment (-Mta)

  • :outputformat (String)

    The output format (-OutputFormat)

  • :sta (Boolean)

    Whether to run as Single-Threaded Apartment (-Sta)

  • :noprofile (Boolean)

    Whether to use the current users powershell profile (-NoProfile)

  • :windowstyle (String)

    The window style to use (-WindowStyle)

Returns:

  • (String)

    Powershell command arguments


169
170
171
172
173
174
175
176
177
# File 'lib/msf/core/exploit/powershell.rb', line 169

def generate_psh_args(opts)
  return '' unless opts

  unless opts.key? :shorten
    opts[:shorten] = (datastore['Powershell::method'] != 'old')
  end

  Rex::Powershell::Command.generate_psh_args(opts)
end

#generate_psh_command_line(opts) ⇒ String

Generate a powershell command line, options are passed on to generate_psh_args

Parameters:

  • opts (Hash)

    The options to generate the command line

Options Hash (opts):

  • :path (String)

    Path to the powershell binary

  • :no_full_stop (Boolean)

    Whether powershell binary should include .exe

Returns:

  • (String)

    Powershell command line with arguments


134
135
136
# File 'lib/msf/core/exploit/powershell.rb', line 134

def generate_psh_command_line(opts)
  Rex::Powershell::Command.generate_psh_command_line(opts)
end

#initialize(info = {}) ⇒ Object


6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
# File 'lib/msf/core/exploit/powershell.rb', line 6

def initialize(info = {})
  super
  register_advanced_options(
    [
      OptBool.new('Powershell::persist', [true, 'Run the payload in a loop', false]),
      OptInt.new('Powershell::prepend_sleep', [false, 'Prepend seconds of sleep']),
      OptBool.new('Powershell::prepend_protections_bypass', [true, 'Prepend AMSI/SBL bypass', false]),
      OptBool.new('Powershell::strip_comments', [true, 'Strip comments', true]),
      OptBool.new('Powershell::strip_whitespace', [true, 'Strip whitespace', false]),
      OptBool.new('Powershell::sub_vars', [true, 'Substitute variable names', false]),
      OptBool.new('Powershell::sub_funcs', [true, 'Substitute function names', false]),
      OptBool.new('Powershell::exec_in_place', [true, 'Produce PSH without executable wrapper', false]),
      OptBool.new('Powershell::exec_rc4', [true, 'Encrypt PSH with RC4', false]),
      OptBool.new('Powershell::remove_comspec', [true, 'Produce script calling powershell directly', false]),
      OptBool.new('Powershell::noninteractive', [true, 'Execute powershell without interaction', true]),
      OptBool.new('Powershell::encode_final_payload', [true, 'Encode final payload for -EncodedCommand', false]),
      OptBool.new('Powershell::encode_inner_payload', [true, 'Encode inner payload for -EncodedCommand', false]),
      OptBool.new('Powershell::wrap_double_quotes', [true, 'Wraps the -Command argument in single quotes', true]),
      OptBool.new('Powershell::no_equals', [true, 'Pad base64 until no "=" remains', false]),
      OptEnum.new('Powershell::method', [true, 'Payload delivery method', 'reflection', %w[net reflection old msil]])
    ]
  )
end

#make_subs(script, subs) ⇒ Object

Insert substitutions into the powershell script If script is a path to a file then read the file otherwise treat it as the contents of a file


55
56
57
58
59
60
61
# File 'lib/msf/core/exploit/powershell.rb', line 55

def make_subs(script, subs)
  subs.each do |set|
    script.gsub!(set[0], set[1])
  end

  script
end

#process_subs(subs) ⇒ Object

Return an array of substitutions for use in make_subs


40
41
42
43
44
45
46
47
48
# File 'lib/msf/core/exploit/powershell.rb', line 40

def process_subs(subs)
  return [] if subs.nil? || subs.empty?
  new_subs = []
  subs.split(';').each do |set|
    new_subs << set.split(',', 2)
  end

  new_subs
end

#read_script(script_path) ⇒ Object

Return a script from path or string


33
34
35
# File 'lib/msf/core/exploit/powershell.rb', line 33

def read_script(script_path)
  Rex::Powershell::Script.new(script_path)
end

#run_hidden_psh(ps_code, payload_arch, encoded) ⇒ String

Wraps the powershell code to launch a hidden window and detect the execution environment and spawn the appropriate powershell executable for the payload architecture.

Parameters:

  • ps_code (String)

    Powershell code

  • payload_arch (String)

    The payload architecture 'x86'/'x86_64'

  • encoded (Boolean)

    Indicates whether ps_code is encoded or not

Returns:

  • (String)

    Wrapped powershell code


188
189
190
191
192
193
194
195
196
197
198
199
# File 'lib/msf/core/exploit/powershell.rb', line 188

def run_hidden_psh(ps_code, payload_arch, encoded)
  arg_opts = {
    noprofile: true,
    windowstyle: 'hidden'
  }

  # Old technique fails if powershell exits..
  arg_opts[:noexit] = (datastore['Powershell::method'] == 'old')
  arg_opts[:shorten] = (datastore['Powershell::method'] != 'old')

  Rex::Powershell::Command.run_hidden_psh(ps_code, payload_arch, encoded, arg_opts)
end