Skip to content

Commit cc72850

Browse files
author
Brent Cook
committed
Land rapid7#8369, add PSH decompressor & decoder convenience methods
2 parents 8be51bb + 8ac5d2d commit cc72850

File tree

1 file changed

+40
-17
lines changed

1 file changed

+40
-17
lines changed

lib/msf/core/exploit/powershell.rb

Lines changed: 40 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -18,22 +18,23 @@ def initialize(info = {})
1818
OptBool.new('Powershell::encode_inner_payload', [true, 'Encode inner payload for -EncodedCommand', false]),
1919
OptBool.new('Powershell::use_single_quotes', [true, 'Wraps the -Command argument in single quotes', false]),
2020
OptBool.new('Powershell::no_equals', [true, 'Pad base64 until no "=" remains', false]),
21-
OptEnum.new('Powershell::method', [true, 'Payload delivery method', 'reflection', %w(net reflection old msil)]),
22-
], self.class)
21+
OptEnum.new('Powershell::method', [true, 'Payload delivery method', 'reflection', %w[net reflection old msil]])
22+
]
23+
)
2324
end
2425

2526
#
2627
# Return a script from path or string
2728
#
2829
def read_script(script_path)
29-
return Rex::Powershell::Script.new(script_path)
30+
Rex::Powershell::Script.new(script_path)
3031
end
3132

3233
#
3334
# Return an array of substitutions for use in make_subs
3435
#
3536
def process_subs(subs)
36-
return [] if subs.nil? or subs.empty?
37+
return [] if subs.nil? || subs.empty?
3738
new_subs = []
3839
subs.split(';').each do |set|
3940
new_subs << set.split(',', 2)
@@ -49,11 +50,12 @@ def process_subs(subs)
4950
#
5051
def make_subs(script, subs)
5152
subs.each do |set|
52-
script.gsub!(set[0],set[1])
53+
script.gsub!(set[0], set[1])
5354
end
5455

5556
script
5657
end
58+
5759
#
5860
# Return an encoded powershell script
5961
# Will invoke PSH modifiers as enabled
@@ -71,6 +73,20 @@ def encode_script(script_in, eof = nil)
7173
Rex::Powershell::Command.encode_script(script_in, eof, opts)
7274
end
7375

76+
#
77+
# Return an decoded powershell script
78+
#
79+
# @param script_in [String] Encoded contents
80+
#
81+
# @return [String] Decoded script
82+
def decode_script(script_in)
83+
return script_in unless
84+
script_in.to_s.match(%r{[A-Za-z0-9+/]+={0,3}})[0] == script_in.to_s &&
85+
(script_in.to_s.length % 4).zero?
86+
87+
Rex::Powershell::Command.decode_script(script_in)
88+
end
89+
7490
#
7591
# Return a gzip compressed powershell script
7692
# Will invoke PSH modifiers as enabled
@@ -79,7 +95,7 @@ def encode_script(script_in, eof = nil)
7995
# @param eof [String] Marker to indicate the end of file appended to script
8096
#
8197
# @return [String] Compressed script with decompression stub
82-
def compress_script(script_in, eof=nil)
98+
def compress_script(script_in, eof = nil)
8399
opts = {}
84100
datastore.select { |k, v| k =~ /^Powershell::(strip|sub)/ && v }.keys.map do |k|
85101
mod_method = k.split('::').last.intern
@@ -89,6 +105,18 @@ def compress_script(script_in, eof=nil)
89105
Rex::Powershell::Command.compress_script(script_in, eof, opts)
90106
end
91107

108+
#
109+
# Return a decompressed powershell sript
110+
#
111+
# @param script_in [String] Compressed contents with decompression stub
112+
#
113+
# @return [String] Decompressed script
114+
def decompress_script(script_in)
115+
return script_in unless script_in.match?(/FromBase64String/)
116+
117+
Rex::Powershell::Command.decompress_script(script_in)
118+
end
119+
92120
#
93121
# Generate a powershell command line, options are passed on to
94122
# generate_psh_args
@@ -155,8 +183,8 @@ def generate_psh_args(opts)
155183
# @return [String] Wrapped powershell code
156184
def run_hidden_psh(ps_code, payload_arch, encoded)
157185
arg_opts = {
158-
noprofile: true,
159-
windowstyle: 'hidden',
186+
noprofile: true,
187+
windowstyle: 'hidden'
160188
}
161189

162190
# Old technique fails if powershell exits..
@@ -194,26 +222,21 @@ def run_hidden_psh(ps_code, payload_arch, encoded)
194222
def cmd_psh_payload(pay, payload_arch, opts = {})
195223
options.validate(datastore)
196224

197-
[ :persist, :prepend_sleep, :exec_in_place, :encode_final_payload,
198-
:encode_inner_payload, :use_single_quotes, :no_equals, :method ].map { |opt|
225+
%i[persist prepend_sleep exec_in_place encode_final_payload encode_inner_payload use_single_quotes no_equals method].map do |opt|
199226
opts[opt] ||= datastore["Powershell::#{opt}"]
200-
}
227+
end
201228

202229
unless opts.key? :shorten
203230
opts[:shorten] = (datastore['Powershell::method'] != 'old')
204231
end
205-
template_path = Rex::Powershell::Templates::TEMPLATE_DIR
206232

207-
command = Rex::Powershell::Command.cmd_psh_payload(pay,
208-
payload_arch,
209-
template_path,
210-
opts)
233+
template_path = Rex::Powershell::Templates::TEMPLATE_DIR
234+
command = Rex::Powershell::Command.cmd_psh_payload(pay, payload_arch, template_path, opts)
211235
vprint_status("Powershell command length: #{command.length}")
212236

213237
command
214238
end
215239

216-
217240
#
218241
# Useful method cache
219242
#

0 commit comments

Comments
 (0)