Skip to content

Commit ec26a5c

Browse files
committed
smb_enumshares: Allow for SMB1 ruby_smb & rex backends
1 parent 17f7f4d commit ec26a5c

1 file changed

Lines changed: 38 additions & 20 deletions

File tree

modules/auxiliary/scanner/smb/smb_enumshares.rb

Lines changed: 38 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ def initialize(info = {})
2727
directories, files, time stamps, etc.
2828
2929
By default, a RubySMB net_share_enum_all request is done in order to retrieve share information,
30-
which uses SRVSVC.
30+
which uses SRVSVC, otherwise will use Rex SMB.
3131
},
3232
'Author' => [
3333
'hdm',
@@ -298,18 +298,23 @@ def run_host(ip)
298298
self.simple = session.simple_client
299299
enum_shares(session.address)
300300
else
301-
[{ port: SMB1_PORT }, { port: SMB2_3_PORT } ].each do |info|
302-
vprint_status("Connecting to the server...")
301+
[
302+
# Force RubySMB library for SMB1 mode otherwise `Rex::Proto::SMB::Client` does not supply `net_share_enum_all`
303+
{ port: SMB1_PORT, versions: [1], backend: :ruby_smb, label: 'SMB v1' },
304+
# @smcintyre-r7: The Rex client doesn't support SMB versions 2 and 3, so this would realistically just be the same as the next line.
305+
# I think what we need here long term is to just give it Ruby SMB and have an abstract method to enumerate the shares regardless of the underlying SMB version that was negotiated.
306+
#{ port: SMB2_3_PORT, versions: [1, 2, 3], backend: :rex, label: 'SMB v1/2/3' },
307+
# Use Rex SMB library fallback for SMB1 mode, as it can handle when NtCreateAndxResponse missing fields
308+
# (Windows server 2019 has issues, but Samba 3.0.20 (metasploitable2) is fine with SMB1 & RubySMB)
309+
{ port: SMB1_PORT, versions: [1], backend: :rex, label: 'SMB v1' },
310+
].each do |info|
311+
# Update line prefix, as port changes
312+
remove_instance_variable(:@print_prefix) if instance_variable_defined?(:@print_prefix)
303313
# Assign @rport so that it is accessible via the rport method in this module,
304314
# as well as making it accessible to the module mixins
305315
@rport = info[:port]
306-
if rport == SMB1_PORT
307-
# force library in smb1 mode otherwise simple.client is a
308-
# `Rex::Proto::SMB::Client` that does not supply `net_share_enum_all`
309-
connect(versions: [1], backend: :ruby_smb)
310-
else
311-
connect(versions: [1, 2, 3])
312-
end
316+
vprint_status("Connecting using #{info[:label]} via #{info[:backend]}")
317+
connect(versions: info[:versions], backend: info[:backend])
313318
smb_login
314319
shares = enum_shares(ip)
315320
next if shares.nil? || shares.empty?
@@ -342,22 +347,31 @@ def enum_shares(ip)
342347
shares = []
343348

344349
begin
345-
# Return all shares if `Shares` option has not been set
346-
if datastore['Share'].nil?
347-
shares = simple.client.net_share_enum_all(ip)
348-
else
350+
# RubySMB
351+
if simple.client.respond_to?(:net_share_enum_all)
352+
# Return all shares if `Shares` option has not been set
353+
if datastore['Share'].nil?
354+
shares = simple.client.net_share_enum_all(ip)
349355
# Return specific share if the `Share` option has been set
350-
simple.client.net_share_enum_all(ip).each { |share| shares = [share] if share[:name] == datastore['Share'] }
351-
# Return an error if `Share` option has been set but no matches were found
352-
if shares.empty?
353-
print_error("No shares match #{datastore['Share']}")
356+
else
357+
simple.client.net_share_enum_all(ip).each { |share| shares = [share] if share[:name] == datastore['Share'] }
354358
end
359+
# Rex SMB: smb_netshareenumall tries SRVSVC then falls back to LANMAN
360+
else
361+
raw = smb_netshareenumall
362+
shares = raw.map { |s| { name: s[0], type: s[1], comment: s[2] } }
363+
shares = shares.select { |s| s[:name] == datastore['Share'] } if datastore['Share']
355364
end
365+
# Return an error if `Share` option has been set but no matches were found
366+
print_error("No shares match #{datastore['Share']}") if shares.empty?
356367
rescue RubySMB::Error::UnexpectedStatusCode => e
357368
print_error("Error when trying to enumerate shares - #{e.status_code.name}")
358369
return
359370
rescue RubySMB::Error::InvalidPacket => e
360-
print_error("Invalid packet received when trying to enumerate shares - #{e}")
371+
vprint_error("Invalid packet received when trying to enumerate shares - #{e}")
372+
return
373+
rescue Rex::Proto::SMB::Exceptions::ErrorCode => e
374+
print_error("Error when trying to enumerate shares - #{e.message}")
361375
return
362376
end
363377

@@ -383,7 +397,11 @@ def enum_shares(ip)
383397
)
384398

385399
if datastore['SpiderShares']
386-
get_files_info(ip, shares)
400+
if simple.client.is_a?(RubySMB::Client)
401+
get_files_info(ip, shares)
402+
else
403+
print_warning('This is not available for this server (unable to use RubySMB)')
404+
end
387405
end
388406
end
389407

0 commit comments

Comments
 (0)