Skip to content

Commit 71d2d8e

Browse files
committed
smb_enumshares: Allow for SMB1 ruby_smb & rex backends
1 parent e5bdc50 commit 71d2d8e

1 file changed

Lines changed: 37 additions & 21 deletions

File tree

modules/auxiliary/scanner/smb/smb_enumshares.rb

Lines changed: 37 additions & 21 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,20 +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+
{ port: SMB2_3_PORT, versions: [1, 2, 3], backend: :rex, label: 'SMB v1/2/3' },
305+
# Use Rex SMB library fallback for SMB1 mode, as it can handle when NtCreateAndxResponse missing fields
306+
# (Windows server 2019 has issues, but Samba 3.0.20 (metasploitable2) is fine with SMB1 & RubySMB)
307+
{ port: SMB1_PORT, versions: [1], backend: :rex, label: 'SMB v1' },
308+
].each do |info|
309+
# Update line prefix, as port changes
310+
remove_instance_variable(:@print_prefix) if instance_variable_defined?(:@print_prefix)
303311
# Assign @rport so that it is accessible via the rport method in this module,
304312
# as well as making it accessible to the module mixins
305313
@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
314+
vprint_status("Connecting using #{info[:label]} via #{info[:backend]}")
315+
connect(versions: info[:versions], backend: info[:backend])
313316
smb_login
314-
break unless enum_shares(ip).empty?
317+
break if enum_shares(ip)&.any?
315318
rescue ::Interrupt
316319
raise $ERROR_INFO
317320
rescue Errno::ECONNRESET => e
@@ -340,22 +343,31 @@ def enum_shares(ip)
340343
shares = []
341344

342345
begin
343-
# Return all shares if `Shares` option has not been set
344-
if datastore['Share'].nil?
345-
shares = simple.client.net_share_enum_all(ip)
346-
else
346+
# RubySMB
347+
if simple.client.respond_to?(:net_share_enum_all)
348+
# Return all shares if `Shares` option has not been set
349+
if datastore['Share'].nil?
350+
shares = simple.client.net_share_enum_all(ip)
347351
# Return specific share if the `Share` option has been set
348-
simple.client.net_share_enum_all(ip).each { |share| shares = [share] if share[:name] == datastore['Share'] }
349-
# Return an error if `Share` option has been set but no matches were found
350-
if shares.empty?
351-
print_error("No shares match #{datastore['Share']}")
352+
else
353+
simple.client.net_share_enum_all(ip).each { |share| shares = [share] if share[:name] == datastore['Share'] }
352354
end
355+
# Rex SMB: smb_netshareenumall tries SRVSVC then falls back to LANMAN
356+
else
357+
raw = smb_netshareenumall
358+
shares = raw.map { |s| { name: s[0], type: s[1], comment: s[2] } }
359+
shares = shares.select { |s| s[:name] == datastore['Share'] } if datastore['Share']
353360
end
361+
# Return an error if `Share` option has been set but no matches were found
362+
print_error("No shares match #{datastore['Share']}") if shares.empty?
354363
rescue RubySMB::Error::UnexpectedStatusCode => e
355364
print_error("Error when trying to enumerate shares - #{e.status_code.name}")
356365
return
357366
rescue RubySMB::Error::InvalidPacket => e
358-
print_error("Invalid packet received when trying to enumerate shares - #{e}")
367+
vprint_error("Invalid packet received when trying to enumerate shares - #{e}")
368+
return
369+
rescue Rex::Proto::SMB::Exceptions::ErrorCode => e
370+
print_error("Error when trying to enumerate shares - #{e.message}")
359371
return
360372
end
361373

@@ -381,7 +393,11 @@ def enum_shares(ip)
381393
)
382394

383395
if datastore['SpiderShares']
384-
get_files_info(ip, shares)
396+
if simple.client.is_a?(RubySMB::Client)
397+
get_files_info(ip, shares)
398+
else
399+
print_warning('This is not available for this server (unable to use RubySMB)')
400+
end
385401
end
386402
end
387403

0 commit comments

Comments
 (0)