##
# $Id: smb_enumshares.rb 9981 2010-08-12 15:00:58Z hdm $
##

##
# This file is part of the Metasploit Framework and may be subject to
# redistribution and commercial restrictions. Please see the Metasploit
# Framework web site for more information on licensing and terms of use.
# http://metasploit.com/framework/
##


require 'msf/core'


class Metasploit3 < Msf::Auxiliary

	# Exploit mixins should be called first
	include Msf::Exploit::Remote::SMB
	include Msf::Exploit::Remote::SMB::Authenticated

	include Msf::Exploit::Remote::DCERPC

	# Scanner mixin should be near last
	include Msf::Auxiliary::Report
	include Msf::Auxiliary::Scanner

	def initialize
		super(
			'Name'        => 'SMB Share Enumeration',
			'Version'     => '$Revision: 9981 $',
			'Description' => 'Determine what shares are provided by the SMB service',
			'Author'      => 'hdm',
			'License'     => MSF_LICENSE,
			'DefaultOptions' => {
				'DCERPC::fake_bind_multi' => false
			}
		)

		deregister_options('RPORT', 'RHOST')
	end

	def share_type(val)
		[
			'DISK',
			'PRINTER',
			'DEVICE',
			'IPC',
			'SPECIAL',
			'TEMPORARY'
		][val]
	end

	def run_host(ip)

		[[139, false], [445, true]].each do |info|

		datastore['RPORT'] = info[0]
		datastore['SMBDirect'] = info[1]

		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]
			end

			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 },
					:update => :unique_data
				)
			end


			disconnect
			return
		rescue ::Timeout::Error
		rescue ::Interrupt
			raise $!
		rescue ::Rex::ConnectionError
		rescue ::Rex::Proto::SMB::Exceptions::LoginError
			next
		rescue ::Exception => e
			print_line("Error: #{ip} #{e.class} #{e}")
		end
		end
	end


end

