Class: Rex::Post::SMB::Ui::Console::CommandDispatcher::Shares
Overview
Constant Summary
collapse
- @@shares_opts =
Rex::Parser::Arguments.new(
['-h', '--help'] => [false, 'Help menu' ],
['-l', '--list'] => [ false, 'List all shares'],
['-i', '--interact'] => [ true, 'Interact with the supplied share ID', '<id>']
)
- @@ls_opts =
Rex::Parser::Arguments.new(
['-h', '--help'] => [false, 'Help menu' ]
)
- @@pwd_opts =
Rex::Parser::Arguments.new(
['-h', '--help'] => [false, 'Help menu' ]
)
- @@cd_opts =
Rex::Parser::Arguments.new(
['-h', '--help'] => [false, 'Help menu' ]
)
- @@cat_opts =
Rex::Parser::Arguments.new(
['-h', '--help'] => [false, 'Help menu' ]
)
- @@upload_opts =
Rex::Parser::Arguments.new(
['-h', '--help'] => [false, 'Help menu' ]
)
- @@download_opts =
Rex::Parser::Arguments.new(
['-h', '--help'] => [false, 'Help menu' ]
)
- @@delete_opts =
Rex::Parser::Arguments.new(
['-h', '--help'] => [false, 'Help menu' ]
)
- @@mkdir_opts =
Rex::Parser::Arguments.new(
['-h', '--help'] => [false, 'Help menu' ]
)
- @@rmdir_opts =
Rex::Parser::Arguments.new(
['-h', '--help'] => [false, 'Help menu' ]
)
Instance Attribute Summary
#shell, #tab_complete_items
Instance Method Summary
collapse
#active_share, #client, #docs_dir, #filter_commands, #log_error, #msf_loaded?, #session, #simple_client, #unknown_command
#cmd_background, #cmd_background_help, #cmd_exit, #cmd_irb, #cmd_irb_help, #cmd_irb_tabs, #cmd_pry, #cmd_pry_help, #cmd_resource, #cmd_resource_help, #cmd_resource_tabs, #cmd_sessions, #cmd_sessions_help
#cmd_help, #cmd_help_help, #cmd_help_tabs, #deprecated_cmd, #deprecated_commands, #deprecated_help, #docs_dir, #help_to_s, included, #print, #print_error, #print_good, #print_line, #print_status, #print_warning, #tab_complete_directory, #tab_complete_filenames, #tab_complete_generic, #tab_complete_source_address, #unknown_command, #update_prompt
Constructor Details
#initialize(console) ⇒ Shares
Initializes an instance of the shares command set using the supplied console for interactivity.
25
26
27
28
29
|
# File 'lib/rex/post/smb/ui/console/command_dispatcher/shares.rb', line 25
def initialize(console)
super
@share_search_results = []
end
|
Instance Method Details
#cmd_cat(*args) ⇒ Object
Print the contents of a file
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
|
# File 'lib/rex/post/smb/ui/console/command_dispatcher/shares.rb', line 335
def cmd_cat(*args)
if args.include?('-h') || args.include?('--help') || args.length != 1
cmd_cd_help
return
end
return print_no_share_selected unless active_share
path = args[0]
new_path = Rex::Ntpath.as_ntpath(Pathname.new(shell.cwd).join(path).to_s)
begin
file = simple_client.open(new_path, 'o')
result = file.read
print_line(result)
rescue StandardError => e
print_error("#{e.class} #{e}")
return
ensure
begin
file.close if file
rescue StandardError => e
elog(e)
end
end
end
|
#cmd_cat_help ⇒ Object
325
326
327
328
329
330
|
# File 'lib/rex/post/smb/ui/console/command_dispatcher/shares.rb', line 325
def cmd_cat_help
print_line 'Usage: cat <path>'
print_line
print_line 'Read the file at the given path.'
print_line
end
|
#cmd_cd(*args) ⇒ Object
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
|
# File 'lib/rex/post/smb/ui/console/command_dispatcher/shares.rb', line 291
def cmd_cd(*args)
if args.include?('-h') || args.include?('--help') || args.length != 1
cmd_cd_help
return
end
return print_no_share_selected unless active_share
path = args[0]
native_path = Pathname.new(shell.cwd).join(path).to_s
new_path = Rex::Ntpath.as_ntpath(native_path)
begin
response = active_share.open_directory(directory: new_path)
directory = RubySMB::SMB2::File.new(name: new_path, tree: active_share, response: response, encrypt: @tree_connect_encrypt_data)
rescue RubySMB::Error::UnexpectedStatusCode => e
if e.status_code == WindowsError::NTStatus::STATUS_OBJECT_NAME_NOT_FOUND
print_error("The path `#{new_path}` is not a valid directory")
end
print_error(e.message)
elog(e)
return
rescue StandardError => e
print_error('Unknown error occurred while trying to change directory')
elog(e)
return
ensure
directory.close if directory
end
shell.cwd = native_path
end
|
#cmd_cd_help ⇒ Object
281
282
283
284
285
286
|
# File 'lib/rex/post/smb/ui/console/command_dispatcher/shares.rb', line 281
def cmd_cd_help
print_line 'Usage: cd <path>'
print_line
print_line 'Change the current remote working directory.'
print_line
end
|
#cmd_cd_tabs(_str, words) ⇒ Object
363
364
365
366
367
|
# File 'lib/rex/post/smb/ui/console/command_dispatcher/shares.rb', line 363
def cmd_cd_tabs(_str, words)
return [] if words.length > 1
@@cd_opts.option_keys
end
|
#cmd_delete(*args) ⇒ Object
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
|
# File 'lib/rex/post/smb/ui/console/command_dispatcher/shares.rb', line 461
def cmd_delete(*args)
if args.include?('-h') || args.include?('--help')
cmd_delete_help
return
end
remote_path = nil
@@delete_opts.parse(args) do |_opt, idx, val|
case idx
when 0
remote_path = val
else
print_warning('Too many parameters')
cmd_delete_help
return
end
end
full_path = Rex::Ntpath.as_ntpath(Pathname.new(shell.cwd).join(remote_path).to_s)
fd = simple_client.open(full_path, 'o')
fd.delete
print_good("Deleted #{full_path}")
end
|
#cmd_delete_help ⇒ Object
485
486
487
488
489
490
|
# File 'lib/rex/post/smb/ui/console/command_dispatcher/shares.rb', line 485
def cmd_delete_help
print_line 'Usage: delete <remote_path>'
print_line
print_line 'Delete a file from the remote target.'
print @@delete_opts.usage
end
|
#cmd_download(*args) ⇒ Object
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
|
# File 'lib/rex/post/smb/ui/console/command_dispatcher/shares.rb', line 417
def cmd_download(*args)
if args.include?('-h') || args.include?('--help')
cmd_download_help
return
end
return print_no_share_selected unless active_share
remote_path = nil
local_path = nil
@@download_opts.parse(args) do |_opt, idx, val|
case idx
when 0
remote_path = val
when 1
local_path = val
else
print_warning('Too many parameters')
cmd_download_help
return
end
end
if remote_path.blank?
print_error('No remote path given')
return
end
local_path = Rex::Post::File.basename(remote_path) if local_path.nil?
full_path = Rex::Ntpath.as_ntpath(Pathname.new(shell.cwd).join(remote_path).to_s)
download_file(local_path, full_path)
print_good("Downloaded #{full_path} to #{local_path}")
end
|
#cmd_download_help ⇒ Object
454
455
456
457
458
459
|
# File 'lib/rex/post/smb/ui/console/command_dispatcher/shares.rb', line 454
def cmd_download_help
print_line 'Usage: download <remote_path> <local_path>'
print_line
print_line 'Download a file from the remote target.'
print @@download_opts.usage
end
|
#cmd_ls(*args) ⇒ Object
Also known as:
cmd_dir
Display the contents of your current working directory
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
|
# File 'lib/rex/post/smb/ui/console/command_dispatcher/shares.rb', line 179
def cmd_ls(*args)
if args.include?('-h') || args.include?('--help')
cmd_ls_help
return
end
return print_no_share_selected unless active_share
remote_path = ''
@@delete_opts.parse(args) do |_opt, idx, val|
case idx
when 0
remote_path = val
else
print_warning('Too many parameters')
cmd_ls_help
return
end
end
full_path = Rex::Ntpath.as_ntpath(Pathname.new(shell.cwd).join(remote_path).to_s)
files = active_share.list(directory: full_path)
table = Rex::Text::Table.new(
'Header' => "ls #{full_path}",
'Indent' => 4,
'Columns' => [ '#', 'Type', 'Name', 'Created', 'Accessed', 'Written', 'Changed', 'Size'],
'Rows' => files.map.with_index do |file, i|
name = file.file_name.encode('UTF-8')
create_time = file.create_time.to_datetime
last_access = file.last_access.to_datetime
last_write = file.last_write.to_datetime
last_change = file.last_change.to_datetime
if (file[:file_attributes]&.directory == 1) || (file[:ext_file_attributes]&.directory == 1)
type = 'DIR'
else
type = 'FILE'
size = file.end_of_file
end
[i, type || 'Unknown', name, create_time, last_access, last_write, last_change, size]
end
)
print_line table.to_s
end
|
#cmd_ls_help ⇒ Object
Also known as:
cmd_dir_help
227
228
229
230
231
232
233
234
235
236
237
|
# File 'lib/rex/post/smb/ui/console/command_dispatcher/shares.rb', line 227
def cmd_ls_help
print_line 'Usage:'
print_line 'ls [options] [path]'
print_line
print_line 'COMMAND ALIASES:'
print_line
print_line ' dir'
print_line
print_line 'Lists contents of directory or file info'
print_line @@ls_opts.usage
end
|
#cmd_ls_tabs(_str, words) ⇒ Object
Also known as:
cmd_dir_tabs
239
240
241
242
243
|
# File 'lib/rex/post/smb/ui/console/command_dispatcher/shares.rb', line 239
def cmd_ls_tabs(_str, words)
return [] if words.length > 1
@@ls_opts.option_keys
end
|
#cmd_mkdir(*args) ⇒ Object
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
|
# File 'lib/rex/post/smb/ui/console/command_dispatcher/shares.rb', line 492
def cmd_mkdir(*args)
if args.include?('-h') || args.include?('--help')
cmd_mkdir_help
return
end
return print_no_share_selected unless active_share
remote_path = nil
@@mkdir_opts.parse(args) do |_opt, idx, val|
case idx
when 0
remote_path = val
else
print_warning('Too many parameters')
cmd_mkdir_help
return
end
end
full_path = Rex::Ntpath.as_ntpath(Pathname.new(shell.cwd).join(remote_path).to_s)
response = active_share.open_directory(directory: full_path, disposition: RubySMB::Dispositions::FILE_CREATE)
directory = RubySMB::SMB2::File.new(name: full_path, tree: active_share, response: response, encrypt: @tree_connect_encrypt_data)
print_good("Directory #{full_path} created")
ensure
directory.close if directory
end
|
#cmd_mkdir_help ⇒ Object
522
523
524
525
526
527
|
# File 'lib/rex/post/smb/ui/console/command_dispatcher/shares.rb', line 522
def cmd_mkdir_help
print_line 'Usage: mkdir <remote_path>'
print_line
print_line 'Create a directory on the remote target.'
print @@mkdir_opts.usage
end
|
#cmd_pwd(*args) ⇒ Object
Print the current working directory
262
263
264
265
266
267
268
269
270
271
272
273
|
# File 'lib/rex/post/smb/ui/console/command_dispatcher/shares.rb', line 262
def cmd_pwd(*args)
if args.include?('-h') || args.include?('--help')
cmd_pwd_help
return
end
return print_no_share_selected unless active_share
share_name = active_share.share[/[^\\].*$/, 0]
cwd = shell.cwd.blank? ? '' : "\\#{shell.cwd}"
print_line "Current directory is \\\\#{share_name}#{cwd}\\"
end
|
#cmd_pwd_help ⇒ Object
252
253
254
255
256
257
|
# File 'lib/rex/post/smb/ui/console/command_dispatcher/shares.rb', line 252
def cmd_pwd_help
print_line 'Usage: pwd'
print_line
print_line 'Print the current remote working directory.'
print_line
end
|
#cmd_pwd_tabs(_str, words) ⇒ Object
275
276
277
278
279
|
# File 'lib/rex/post/smb/ui/console/command_dispatcher/shares.rb', line 275
def cmd_pwd_tabs(_str, words)
return [] if words.length > 1
@@pwd_opts.option_keys
end
|
#cmd_rmdir(*args) ⇒ Object
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
|
# File 'lib/rex/post/smb/ui/console/command_dispatcher/shares.rb', line 529
def cmd_rmdir(*args)
if args.include?('-h') || args.include?('--help')
cmd_rmdir_help
return
end
return print_no_share_selected unless active_share
remote_path = nil
@@rmdir_opts.parse(args) do |_opt, idx, val|
case idx
when 0
remote_path = val
else
print_warning('Too many parameters')
cmd_rmdir_help
return
end
end
full_path = Rex::Ntpath.as_ntpath(Pathname.new(shell.cwd).join(remote_path).to_s)
response = active_share.open_directory(directory: full_path, write: true, delete: true, desired_delete: true)
directory = RubySMB::SMB2::File.new(name: full_path, tree: active_share, response: response, encrypt: @tree_connect_encrypt_data)
status = directory.delete
if status == WindowsError::NTStatus::STATUS_SUCCESS
print_good("Deleted #{full_path}")
else
print_error("Error deleting #{full_path}: #{status.name}, #{status.description}")
end
ensure
directory.close if directory
end
|
#cmd_rmdir_help ⇒ Object
564
565
566
567
568
569
|
# File 'lib/rex/post/smb/ui/console/command_dispatcher/shares.rb', line 564
def cmd_rmdir_help
print_line 'Usage: rmdir <remote_path>'
print_line
print_line 'Delete a directory from the remote target.'
print @@rmdir_opts.usage
end
|
#cmd_shares(*args) ⇒ Object
View and interact with shares
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
|
# File 'lib/rex/post/smb/ui/console/command_dispatcher/shares.rb', line 106
def cmd_shares(*args)
if args.include?('-h') || args.include?('--help')
cmd_shares_help
return
end
method = :list
share_name = nil
@@shares_opts.parse(args) do |opt, _idx, val|
case opt
when '-l', '--list'
when '-i', '--interact'
share_name = val
method = :interact
end
end
case method
when :list
populate_shares
table = Rex::Text::Table.new(
'Header' => 'Shares',
'Indent' => 4,
'Columns' => %w[# Name Type comment],
'Rows' => @share_search_results.map.with_index do |share, i|
[i, share[:name], share[:type], share[:comment]]
end
)
print_line table.to_s
when :interact
populate_shares if @valid_share_names.nil?
if share_name.match?(/\A\d+\z/) && !@valid_share_names.include?(share_name)
share_name = (@share_search_results[share_name.to_i] || {})[:name]
end
if share_name.nil?
print_error('Invalid share name')
return
end
path = "\\\\#{session.address}\\#{share_name}"
begin
shell.active_share = client.tree_connect(path)
shell.cwd = ''
print_good "Successfully connected to #{share_name}"
rescue StandardError => e
log_error("Error running action #{method}: #{e.class} #{e}")
end
end
end
|
#cmd_shares_help ⇒ Object
169
170
171
172
173
174
|
# File 'lib/rex/post/smb/ui/console/command_dispatcher/shares.rb', line 169
def cmd_shares_help
print_line 'Usage: shares'
print_line
print_line 'View the shares available on the remote target.'
print @@shares_opts.usage
end
|
#cmd_shares_tabs(_str, words) ⇒ Object
163
164
165
166
167
|
# File 'lib/rex/post/smb/ui/console/command_dispatcher/shares.rb', line 163
def cmd_shares_tabs(_str, words)
return [] if words.length > 1
@@shares_opts.option_keys
end
|
#cmd_upload(*args) ⇒ Object
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
|
# File 'lib/rex/post/smb/ui/console/command_dispatcher/shares.rb', line 369
def cmd_upload(*args)
if args.include?('-h') || args.include?('--help')
cmd_upload_help
return
end
return print_no_share_selected unless active_share
local_path = nil
remote_path = nil
@@upload_opts.parse(args) do |_opt, idx, val|
case idx
when 0
local_path = val
when 1
remote_path = val
else
print_warning('Too many parameters')
cmd_upload_help
return
end
end
if local_path.blank?
print_error('No local path given')
return
end
remote_path = Rex::Post::File.basename(local_path) if remote_path.nil?
full_path = Rex::Ntpath.as_ntpath(Pathname.new(shell.cwd).join(remote_path).to_s)
upload_file(full_path, local_path)
print_good("#{local_path} uploaded to #{full_path}")
end
|
#cmd_upload_help ⇒ Object
410
411
412
413
414
415
|
# File 'lib/rex/post/smb/ui/console/command_dispatcher/shares.rb', line 410
def cmd_upload_help
print_line 'Usage: upload <local_path> <remote_path>'
print_line
print_line 'Upload a file to the remote target.'
print @@upload_opts.usage
end
|
#cmd_upload_tabs(str, words) ⇒ Object
406
407
408
|
# File 'lib/rex/post/smb/ui/console/command_dispatcher/shares.rb', line 406
def cmd_upload_tabs(str, words)
tab_complete_filenames(str, words)
end
|
#commands ⇒ Object
List of supported commands.
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
|
# File 'lib/rex/post/smb/ui/console/command_dispatcher/shares.rb', line 76
def commands
cmds = {
'shares' => 'View the available shares and interact with one',
'ls' => 'List all files in the current directory',
'dir' => 'List all files in the current directory (alias for ls)',
'pwd' => 'Print the current remote working directory',
'cd' => 'Change the current remote working directory',
'cat' => 'Read the file at the given path',
'upload' => 'Upload a file',
'download' => 'Download a file',
'delete' => 'Delete a file',
'mkdir' => 'Make a new directory',
'rmdir' => 'Delete a directory'
}
reqs = {}
filter_commands(cmds, reqs)
end
|
#download_file(dest_file, src_file) ⇒ Object
Download a remote file from the target
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
|
# File 'lib/rex/post/smb/ui/console/command_dispatcher/shares.rb', line 604
def download_file(dest_file, src_file)
buf_size = 8 * 1024 * 1024
src_fd = simple_client.open(src_file, 'o')
dir = ::File.dirname(dest_file)
::FileUtils.mkdir_p(dir) if dir && !::File.directory?(dir)
dst_fd = ::File.new(dest_file, "wb")
offset = 0
src_size = client.open_files[src_fd.file_id].size
begin
while offset < src_size
data = src_fd.read(buf_size, offset)
dst_fd.write(data)
offset += data.length
percent = offset / src_size.to_f * 100.0
msg = "Downloaded #{Filesize.new(offset).pretty} of " \
"#{Filesize.new(src_size).pretty} (#{percent.round(2)}%)"
print_status(msg)
end
ensure
src_fd.close unless src_fd.nil?
dst_fd.close unless dst_fd.nil?
end
end
|
#name ⇒ Object
99
100
101
|
# File 'lib/rex/post/smb/ui/console/command_dispatcher/shares.rb', line 99
def name
'Shares'
end
|
#print_no_share_selected ⇒ Object
573
574
575
576
|
# File 'lib/rex/post/smb/ui/console/command_dispatcher/shares.rb', line 573
def print_no_share_selected
print_error('No active share selected. Use the %grnshares%clr command to view available shares, and %grnshares -i <id>%clr to interact with one')
nil
end
|
#upload_file(dest_file, src_file) ⇒ Object
Upload a local file to the target
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
|
# File 'lib/rex/post/smb/ui/console/command_dispatcher/shares.rb', line 581
def upload_file(dest_file, src_file)
buf_size = 8 * 1024 * 1024
begin
dest_fd = simple_client.open(dest_file, 'wct', write: true)
src_fd = ::File.open(src_file, "rb")
src_size = src_fd.stat.size
offset = 0
while (buf = src_fd.read(buf_size))
offset = dest_fd.write(buf, offset)
percent = offset / src_size.to_f * 100.0
msg = "Uploaded #{Filesize.new(offset).pretty} of " \
"#{Filesize.new(src_size).pretty} (#{percent.round(2)}%)"
print_status(msg)
end
ensure
src_fd.close unless src_fd.nil?
dest_fd.close unless dest_fd.nil?
end
end
|