Skip to content

Commit 53b66f3

Browse files
committed
Land rapid7#2075, Powershell Improvements
2 parents 4ed085d + b0a596b commit 53b66f3

32 files changed

+2430
-203
lines changed

lib/msf/core/exploit/powershell.rb

Lines changed: 324 additions & 122 deletions
Large diffs are not rendered by default.

lib/msf/util/exe.rb

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1084,17 +1084,18 @@ def self.to_mem_aspx(framework, code, exeopts={})
10841084
end
10851085

10861086
def self.to_win32pe_psh_net(framework, code, opts={})
1087-
hash_sub = {}
1088-
hash_sub[:var_code] = Rex::Text.rand_text_alpha(rand(8)+8)
1089-
hash_sub[:var_kernel32] = Rex::Text.rand_text_alpha(rand(8)+8)
1090-
hash_sub[:var_baseaddr] = Rex::Text.rand_text_alpha(rand(8)+8)
1091-
hash_sub[:var_threadHandle] = Rex::Text.rand_text_alpha(rand(8)+8)
1092-
hash_sub[:var_output] = Rex::Text.rand_text_alpha(rand(8)+8)
1093-
hash_sub[:var_temp] = Rex::Text.rand_text_alpha(rand(8)+8)
1094-
hash_sub[:var_codeProvider] = Rex::Text.rand_text_alpha(rand(8)+8)
1095-
hash_sub[:var_compileParams] = Rex::Text.rand_text_alpha(rand(8)+8)
1096-
hash_sub[:var_syscode] = Rex::Text.rand_text_alpha(rand(8)+8)
1087+
rig = Rex::RandomIdentifierGenerator.new()
1088+
rig.init_var(:var_code)
1089+
rig.init_var(:var_kernel32)
1090+
rig.init_var(:var_baseaddr)
1091+
rig.init_var(:var_threadHandle)
1092+
rig.init_var(:var_output)
1093+
rig.init_var(:var_codeProvider)
1094+
rig.init_var(:var_compileParams)
1095+
rig.init_var(:var_syscode)
1096+
rig.init_var(:var_temp)
10971097

1098+
hash_sub = rig.to_h
10981099
hash_sub[:b64shellcode] = Rex::Text.encode_base64(code)
10991100

11001101
return read_replace_script_template("to_mem_dotnet.ps1.template", hash_sub).gsub(/(?<!\r)\n/, "\r\n")

lib/rex/exploitation/powershell.rb

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
# -*- coding: binary -*-
2+
3+
require 'rex/exploitation/powershell/output'
4+
require 'rex/exploitation/powershell/parser'
5+
require 'rex/exploitation/powershell/obfu'
6+
require 'rex/exploitation/powershell/param'
7+
require 'rex/exploitation/powershell/function'
8+
require 'rex/exploitation/powershell/script'
9+
require 'rex/exploitation/powershell/psh_methods'
10+
11+
module Rex
12+
module Exploitation
13+
module Powershell
14+
#
15+
# Reads script into a PowershellScript
16+
#
17+
# @param script_path [String] Path to the Script File
18+
#
19+
# @return [Script] Powershell Script object
20+
def self.read_script(script_path)
21+
Rex::Exploitation::Powershell::Script.new(script_path)
22+
end
23+
24+
#
25+
# Insert substitutions into the powershell script
26+
# If script is a path to a file then read the file
27+
# otherwise treat it as the contents of a file
28+
#
29+
# @param script [String] Script file or path to script
30+
# @param subs [Array] Substitutions to insert
31+
#
32+
# @return [String] Modified script file
33+
def self.make_subs(script, subs)
34+
if ::File.file?(script)
35+
script = ::File.read(script)
36+
end
37+
38+
subs.each do |set|
39+
script.gsub!(set[0], set[1])
40+
end
41+
42+
script
43+
end
44+
45+
#
46+
# Return an array of substitutions for use in make_subs
47+
#
48+
# @param subs [String] A ; seperated list of substitutions
49+
#
50+
# @return [Array] An array of substitutions
51+
def self.process_subs(subs)
52+
return [] if subs.nil? or subs.empty?
53+
new_subs = []
54+
subs.split(';').each do |set|
55+
new_subs << set.split(',', 2)
56+
end
57+
58+
new_subs
59+
end
60+
end
61+
end
62+
end
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
# -*- coding: binary -*-
2+
3+
module Rex
4+
module Exploitation
5+
module Powershell
6+
class Function
7+
FUNCTION_REGEX = Regexp.new(/\[(\w+\[\])\]\$(\w+)\s?=|\[(\w+)\]\$(\w+)\s?=|\[(\w+\[\])\]\s+?\$(\w+)\s+=|\[(\w+)\]\s+\$(\w+)\s?=/i)
8+
PARAMETER_REGEX = Regexp.new(/param\s+\(|param\(/im)
9+
attr_accessor :code, :name, :params
10+
11+
include Output
12+
include Parser
13+
include Obfu
14+
15+
def initialize(name, code)
16+
@name = name
17+
@code = code
18+
populate_params
19+
end
20+
21+
#
22+
# To String
23+
#
24+
# @return [String] Powershell function
25+
def to_s
26+
"function #{name} #{code}"
27+
end
28+
29+
#
30+
# Identify the parameters from the code and
31+
# store as Param in @params
32+
#
33+
def populate_params
34+
@params = []
35+
start = code.index(PARAMETER_REGEX)
36+
return unless start
37+
# Get start of our block
38+
idx = scan_with_index('(', code[start..-1]).first.last + start
39+
pclause = block_extract(idx)
40+
41+
matches = pclause.scan(FUNCTION_REGEX)
42+
43+
# Ignore assignment, create params with class and variable names
44+
matches.each do |param|
45+
klass = nil
46+
name = nil
47+
param.each do |value|
48+
if value
49+
if klass
50+
name = value
51+
@params << Param.new(klass, name)
52+
break
53+
else
54+
klass = value
55+
end
56+
end
57+
end
58+
end
59+
end
60+
end
61+
end
62+
end
63+
end
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
# -*- coding: binary -*-
2+
3+
require 'rex/text'
4+
5+
module Rex
6+
module Exploitation
7+
module Powershell
8+
module Obfu
9+
MULTI_LINE_COMMENTS_REGEX = Regexp.new(/<#(.*?)#>/m)
10+
SINGLE_LINE_COMMENTS_REGEX = Regexp.new(/^\s*#(?!.*region)(.*$)/i)
11+
WINDOWS_EOL_REGEX = Regexp.new(/[\r\n]+/)
12+
UNIX_EOL_REGEX = Regexp.new(/[\n]+/)
13+
WHITESPACE_REGEX = Regexp.new(/\s+/)
14+
EMPTY_LINE_REGEX = Regexp.new(/^$|^\s+$/)
15+
16+
#
17+
# Remove comments
18+
#
19+
# @return [String] code without comments
20+
def strip_comments
21+
# Multi line
22+
code.gsub!(MULTI_LINE_COMMENTS_REGEX, '')
23+
# Single line
24+
code.gsub!(SINGLE_LINE_COMMENTS_REGEX, '')
25+
26+
code
27+
end
28+
29+
#
30+
# Remove empty lines
31+
#
32+
# @return [String] code without empty lines
33+
def strip_empty_lines
34+
# Windows EOL
35+
code.gsub!(WINDOWS_EOL_REGEX, "\r\n")
36+
# UNIX EOL
37+
code.gsub!(UNIX_EOL_REGEX, "\n")
38+
39+
code
40+
end
41+
42+
#
43+
# Remove whitespace
44+
# This can break some codes using inline .NET
45+
#
46+
# @return [String] code with whitespace stripped
47+
def strip_whitespace
48+
code.gsub!(WHITESPACE_REGEX, ' ')
49+
50+
code
51+
end
52+
53+
#
54+
# Identify variables and replace them
55+
#
56+
# @return [String] code with variable names replaced with unique values
57+
def sub_vars
58+
# Get list of variables, remove reserved
59+
get_var_names.each do |var, _sub|
60+
code.gsub!(var, "$#{@rig.init_var(var)}")
61+
end
62+
63+
code
64+
end
65+
66+
#
67+
# Identify function names and replace them
68+
#
69+
# @return [String] code with function names replaced with unique
70+
# values
71+
def sub_funcs
72+
# Find out function names, make map
73+
get_func_names.each do |var, _sub|
74+
code.gsub!(var, @rig.init_var(var))
75+
end
76+
77+
code
78+
end
79+
80+
#
81+
# Perform standard substitutions
82+
#
83+
# @return [String] code with standard substitution methods applied
84+
def standard_subs(subs = %w(strip_comments strip_whitespace sub_funcs sub_vars))
85+
# Save us the trouble of breaking injected .NET and such
86+
subs.delete('strip_whitespace') unless get_string_literals.empty?
87+
# Run selected modifiers
88+
subs.each do |modifier|
89+
send(modifier)
90+
end
91+
code.gsub!(EMPTY_LINE_REGEX, '')
92+
93+
code
94+
end
95+
end # Obfu
96+
end
97+
end
98+
end

0 commit comments

Comments
 (0)