Skip to content

Commit ce8a6f5

Browse files
committed
Added powershell_import support
1 parent 80e0bbe commit ce8a6f5

File tree

3 files changed

+70
-0
lines changed

3 files changed

+70
-0
lines changed

lib/rex/post/meterpreter/extensions/powershell/powershell.rb

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,30 @@ def initialize(client)
3131
end
3232

3333

34+
def import_file(opts={})
35+
return nil unless opts[:file]
36+
37+
# if it's a script, then we'll just use execute_string
38+
if opts[:file].end_with?('.ps1')
39+
opts[:code] = ::File.read(opts[:file])
40+
return execute_string(opts)
41+
end
42+
43+
# if it's a dll (hopefully a .NET 2.0 one) then do something different
44+
if opts[:file].end_with?('.dll')
45+
# TODO: perhaps do some kind of check to see if the DLL is a .NET assembly?
46+
binary = ::File.read(opts[:file])
47+
48+
request = Packet.create_request('powershell_assembly_load')
49+
request.add_tlv(TLV_TYPE_POWERSHELL_ASSEMBLY_SIZE, binary.length)
50+
request.add_tlv(TLV_TYPE_POWERSHELL_ASSEMBLY, binary)
51+
client.send_request(request)
52+
return true
53+
end
54+
55+
return false
56+
end
57+
3458
def execute_string(opts={})
3559
return nil unless opts[:code]
3660

lib/rex/post/meterpreter/extensions/powershell/tlv.rb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ module Powershell
88
TLV_TYPE_POWERSHELL_SESSIONID = TLV_META_TYPE_STRING | (TLV_EXTENSIONS + 1)
99
TLV_TYPE_POWERSHELL_CODE = TLV_META_TYPE_STRING | (TLV_EXTENSIONS + 2)
1010
TLV_TYPE_POWERSHELL_RESULT = TLV_META_TYPE_STRING | (TLV_EXTENSIONS + 3)
11+
TLV_TYPE_POWERSHELL_ASSEMBLY_SIZE = TLV_META_TYPE_UINT | (TLV_EXTENSIONS + 4)
12+
TLV_TYPE_POWERSHELL_ASSEMBLY = TLV_META_TYPE_RAW | (TLV_EXTENSIONS + 5)
1113

1214
end
1315
end

lib/rex/post/meterpreter/ui/console/command_dispatcher/powershell.rb

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ def name
2929
#
3030
def commands
3131
{
32+
'powershell_import' => 'Import a PS1 script or .NET Assembly DLL',
3233
'powershell_shell' => 'Create an interactive Powershell prompt',
3334
'powershell_execute' => 'Execute a Powershell command string'
3435
}
@@ -68,6 +69,49 @@ def cmd_powershell_shell(*args)
6869
shell.interact_with_channel(channel)
6970
end
7071

72+
@@powershell_import_opts = Rex::Parser::Arguments.new(
73+
'-s' => [true, 'Specify the id/name of the Powershell session to run the command in.'],
74+
'-h' => [false, 'Help banner']
75+
)
76+
77+
def powershell_import_usage
78+
print_line('Usage: powershell_import <path to file> [-s session-id]')
79+
print_line
80+
print_line('Imports a powershell script or assembly into the target.')
81+
print_line('The file must end in ".ps1" or ".dll".')
82+
print_line('Powershell scripts can be loaded into any session (via -s).')
83+
print_line('.NET assemblies are applied to all sessions.')
84+
print_line(@@powershell_import_opts.usage)
85+
end
86+
87+
#
88+
# Import a script or assembly component into the target.
89+
#
90+
def cmd_powershell_import(*args)
91+
if args.length == 0 || args.include?('-h')
92+
powershell_import_usage
93+
return false
94+
end
95+
96+
opts = {
97+
file: args.shift
98+
}
99+
100+
@@powershell_import_opts.parse(args) { |opt, idx, val|
101+
case opt
102+
when '-s'
103+
opts[:session_id] = val
104+
end
105+
}
106+
107+
result = client.powershell.import_file(opts)
108+
if !result.blank? && result != false
109+
print_good("File successfully imported. Result:\n#{result}")
110+
else
111+
print_error("File failed to load.")
112+
end
113+
end
114+
71115
@@powershell_execute_opts = Rex::Parser::Arguments.new(
72116
'-s' => [true, 'Specify the id/name of the Powershell session to run the command in.'],
73117
'-h' => [false, 'Help banner']

0 commit comments

Comments
 (0)