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