@@ -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