From d68d832c9d861e4cad994b2adc7d740db420a723 Mon Sep 17 00:00:00 2001 From: Alexandre Maloteaux Date: Mon, 30 Apr 2012 17:38:42 -0600 Subject: [PATCH] Squashed commit of the following: commit a0b50c394962fc90afc8d6232e1875588ed7ecb3 Author: Alexandre Maloteaux Date: Fri Apr 20 01:45:06 2012 +0100 enumshare: add srvsvc netshareenum request for compatibility with win 7 / 2008r2 [Closes #346] --- .../auxiliary/scanner/smb/smb_enumshares.rb | 146 +++++++++++++----- 1 file changed, 109 insertions(+), 37 deletions(-) diff --git a/modules/auxiliary/scanner/smb/smb_enumshares.rb b/modules/auxiliary/scanner/smb/smb_enumshares.rb index 7b852b03c7..1eba1e372c 100644 --- a/modules/auxiliary/scanner/smb/smb_enumshares.rb +++ b/modules/auxiliary/scanner/smb/smb_enumshares.rb @@ -37,6 +37,11 @@ class Metasploit3 < Msf::Auxiliary } ) + register_advanced_options( + [ + OptBool.new('USE_SRVSVC_ONLY', [true, "By default a netshareenum request is done on the lanman pipe and if fails a second try is done on srvsvc", false]) + ], self.class) + deregister_options('RPORT', 'RHOST') end @@ -57,8 +62,104 @@ class Metasploit3 < Msf::Auxiliary stypes[val] end + def lanman_netshareenum + begin + res = self.simple.client.trans( + "\\PIPE\\LANMAN", + ( + [0x00].pack('v') + + "WrLeh\x00" + + "B13BWz\x00" + + [0x01, 65406].pack("vv") + ) + ) + rescue ::Rex::Proto::SMB::Exceptions::ErrorCode => e + #STATUS_NOT_SUPPORTED + if( e.error_code == 0xC00000BB ) + srvsvc_netshareenum + return + end + end + + lerror, lconv, lentries, lcount = res['Payload'].to_s[ + res['Payload'].v['ParamOffset'], + res['Payload'].v['ParamCount'] + ].unpack("v4") + + data = res['Payload'].to_s[ + res['Payload'].v['DataOffset'], + res['Payload'].v['DataCount'] + ] + + 0.upto(lentries - 1) do |i| + sname,tmp = data[(i * 20) + 0, 14].split("\x00") + stype = data[(i * 20) + 14, 2].unpack('v')[0] + scoff = data[(i * 20) + 16, 2].unpack('v')[0] + if ( lconv != 0) + scoff -= lconv + end + scomm,tmp = data[scoff, data.length - scoff].split("\x00") + + @shares << [ sname, share_type(stype), scomm] + end + end + + def srvsvc_netshareenum + + simple.connect("IPC$") + handle = dcerpc_handle('4b324fc8-1670-01d3-1278-5a47bf6ee188', '3.0', 'ncacn_np', ["\\srvsvc"]) + dcerpc_bind(handle) + + stubdata = + NDR.uwstring("\\\\#{rhost}") + + NDR.long(1) #level + + ref_id = stubdata[0,4].unpack("V")[0] + ctr = [1, ref_id + 4 , 0, 0].pack("VVVV") + + stubdata << ctr + stubdata << NDR.align(ctr) + stubdata << ["FFFFFFFF"].pack("H*") + stubdata << [ref_id + 8, 0].pack("VV") + response = dcerpc.call(0x0f, stubdata) + res = response.dup + win_error = res.slice!(-4, 4).unpack("V")[0] + if win_error != 0 + raise "DCE/RPC error : Win_error = #{win_error + 0}" + end + #remove some uneeded data + res.slice!(0,12) # level, CTR header, Reference ID of CTR + share_count = res.slice!(0, 4).unpack("V")[0] + res.slice!(0,4) # Reference ID of CTR1 + share_max_count = res.slice!(0, 4).unpack("V")[0] + + raise "Dce/RPC error : Unknow situation encountered count != count max (#{share_count}/#{share_max_count})" if share_max_count != share_count + + types = res.slice!(0, share_count * 12).scan(/.{12}/n).map{|a| a[4,2].unpack("v")[0]} # RerenceID / Type / ReferenceID of Comment + + share_count.times do |t| + length, offset, max_length = res.slice!(0, 12).unpack("VVV") + raise "Dce/RPC error : Unknow situation encountered offset != 0 (#{offset})" if offset != 0 + raise "Dce/RPC error : Unknow situation encountered length !=max_length (#{length}/#{max_length})" if length != max_length + name = res.slice!(0, 2 * length).gsub('\x00','') + res.slice!(0,2) if length % 2 == 1 # pad + + comment_length, comment_offset, comment_max_length = res.slice!(0, 12).unpack("VVV") + raise "Dce/RPC error : Unknow situation encountered comment_offset != 0 (#{comment_offset})" if comment_offset != 0 + if comment_length != comment_max_length + raise "Dce/RPC error : Unknow situation encountered comment_length != comment_max_length (#{comment_length}/#{comment_max_length})" + end + comment = res.slice!(0, 2 * comment_length).gsub('\x00','') + res.slice!(0,2) if comment_length % 2 == 1 # pad + + @shares << [ name, share_type(types[t]), comment] + end + end + def run_host(ip) + @shares = [] + [[139, false], [445, true]].each do |info| datastore['RPORT'] = info[0] @@ -67,54 +168,25 @@ class Metasploit3 < Msf::Auxiliary begin connect smb_login - - res = self.simple.client.trans( - "\\PIPE\\LANMAN", - ( - [0x00].pack('v') + - "WrLeh\x00" + - "B13BWz\x00" + - [0x01, 65406].pack("vv") - ) - ) - - shares = [] - - lerror, lconv, lentries, lcount = res['Payload'].to_s[ - res['Payload'].v['ParamOffset'], - res['Payload'].v['ParamCount'] - ].unpack("v4") - - data = res['Payload'].to_s[ - res['Payload'].v['DataOffset'], - res['Payload'].v['DataCount'] - ] - - 0.upto(lentries - 1) do |i| - sname,tmp = data[(i * 20) + 0, 14].split("\x00") - stype = data[(i * 20) + 14, 2].unpack('v')[0] - scoff = data[(i * 20) + 16, 2].unpack('v')[0] - if ( lconv != 0) - scoff -= lconv - end - scomm,tmp = data[scoff, data.length - scoff].split("\x00") - - shares << [ sname, share_type(stype), scomm] + if datastore['USE_SRVSVC_ONLY'] + srvsvc_netshareenum + else + #If not implemented by target, will fall back to srvsvc_netshareenum + lanman_netshareenum end - if not shares.empty? - print_status("#{ip}:#{rport} #{shares.map{|x| "#{x[0]} - #{x[2]} (#{x[1]})" }.join(", ")}") + if not @shares.empty? + print_status("#{ip}:#{rport} #{@shares.map{|x| "#{x[0]} - #{x[2]} (#{x[1]})" }.join(", ")}") report_note( :host => ip, :proto => 'tcp', :port => rport, :type => 'smb.shares', - :data => { :shares => shares }, + :data => { :shares => @shares }, :update => :unique_data ) end - disconnect return rescue ::Timeout::Error