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/lib/metasploit/framework/login_scanner/glassfish.rb
Views: 1904
1
2
require 'metasploit/framework/login_scanner/http'
3
4
module Metasploit
5
module Framework
6
module LoginScanner
7
8
# The Glassfish HTTP LoginScanner class provides methods to do login routines
9
# for Glassfish 2, 3 and 4.
10
class Glassfish < HTTP
11
12
DEFAULT_PORT = 4848
13
PRIVATE_TYPES = [ :password ]
14
15
# @!attribute [r] version
16
# @return [String] Glassfish version
17
attr_accessor :version
18
19
# @!attribute jsession
20
# @return [String] Cookie session
21
attr_accessor :jsession
22
23
# @!attribute http_username
24
attr_accessor :http_username
25
# @return [String] HTTP username
26
27
# @!attribute http_password
28
attr_accessor :http_password
29
30
# (see Base#check_setup)
31
def check_setup
32
begin
33
res = send_request({
34
'uri' => '/common/index.jsf',
35
})
36
return "Connection failed" if res.nil?
37
if !([200, 302].include?(res.code))
38
return "Unexpected HTTP response code #{res.code} (is this really Glassfish?)"
39
end
40
41
# If remote login is enabled on 4.x, it redirects to https on the
42
# same port.
43
if !self.ssl && res.headers['Location'] =~ /^https:/
44
self.ssl = true
45
res = send_request({
46
'uri' => '/common/index.jsf',
47
'cgi' => false
48
})
49
if res.nil?
50
return "Connection failed after SSL redirection"
51
end
52
if res.code != 200
53
return "Unexpected HTTP response code #{res.code} after SSL redirection (is this really Glassfish?)"
54
end
55
end
56
57
res = send_request({
58
'uri' => '/login.jsf',
59
'cgi' => false
60
})
61
return "Connection failed" if res.nil?
62
extract_version(res.headers['Server'])
63
64
if @version.nil? || @version !~ /^[2349]/
65
return "Unsupported version ('#{@version}')"
66
end
67
rescue ::EOFError, Errno::ETIMEDOUT, OpenSSL::SSL::SSLError, Rex::ConnectionError, ::Timeout::Error
68
return "Unable to connect to target"
69
end
70
71
false
72
end
73
74
# Sends a HTTP request with Rex
75
#
76
# @param (see Rex::Proto::Http::Request#request_raw)
77
# @return [Rex::Proto::Http::Response] The HTTP response
78
def send_request(opts)
79
res = super(opts)
80
81
# Found a cookie? Set it. We're going to need it.
82
if res && res.get_cookies =~ /JSESSIONID=(\w*);/i
83
self.jsession = $1
84
end
85
86
res
87
end
88
89
90
# As of Sep 2014, if Secure Admin is disabled, it simply means the admin isn't allowed
91
# to login remotely. However, the authentication will still run and hint whether the
92
# password is correct or not.
93
#
94
# @param res [Rex::Proto::Http::Response] The HTTP auth response
95
# @return [boolean] True if disabled, otherwise false
96
def is_secure_admin_disabled?(res)
97
return (res.body =~ /Secure Admin must be enabled/i) ? true : false
98
end
99
100
101
# Sends a login request
102
#
103
# @param credential [Metasploit::Framework::Credential] The credential object
104
# @return [Rex::Proto::Http::Response] The HTTP auth response
105
def try_login(credential)
106
data = "j_username=#{Rex::Text.uri_encode(credential.public)}&"
107
data << "j_password=#{Rex::Text.uri_encode(credential.private)}&"
108
data << 'loginButton=Login'
109
110
opts = {
111
'uri' => '/j_security_check',
112
'method' => 'POST',
113
'data' => data,
114
'headers' => {
115
'Content-Type' => 'application/x-www-form-urlencoded',
116
'Cookie' => "JSESSIONID=#{self.jsession}",
117
},
118
'cgi' => false
119
}
120
121
send_request(opts)
122
end
123
124
125
# Tries to login to Glassfish version 2
126
#
127
# @param credential [Metasploit::Framework::Credential] The credential object
128
# @return [Hash]
129
# * :status [Metasploit::Model::Login::Status]
130
# * :proof [String] the HTTP response body
131
def try_glassfish_2(credential)
132
res = try_login(credential)
133
if res && res.code == 302
134
opts = {
135
'uri' => '/applications/upload.jsf',
136
'method' => 'GET',
137
'headers' => {
138
'Cookie' => "JSESSIONID=#{self.jsession}"
139
},
140
'cgi' => false
141
}
142
res = send_request(opts)
143
p = /<title>Deploy Enterprise Applications\/Modules/
144
if (res && res.code.to_i == 200 && res.body.match(p) != nil)
145
return {:status => Metasploit::Model::Login::Status::SUCCESSFUL, :proof => res.body}
146
end
147
end
148
149
{:status => Metasploit::Model::Login::Status::INCORRECT, :proof => res.body}
150
end
151
152
153
# Tries to login to Glassfish version 9
154
#
155
# @param credential [Metasploit::Framework::Credential] The credential object
156
# @return [Hash]
157
# * :status [Metasploit::Model::Login::Status]
158
# * :proof [String] the HTTP response body
159
def try_glassfish_9(credential)
160
res = try_login(credential)
161
162
if res && res.code.to_i == 302 && res.headers['Location'].to_s !~ /loginError\.jsf$/
163
return {:status => Metasploit::Model::Login::Status::SUCCESSFUL, :proof => res.body}
164
end
165
166
{:status => Metasploit::Model::Login::Status::INCORRECT, :proof => res.body}
167
end
168
169
170
# Tries to login to Glassfish version 3 or 4 (as of now it's the latest)
171
#
172
# @param (see #try_glassfish_2)
173
# @return (see #try_glassfish_2)
174
def try_glassfish_3(credential)
175
res = try_login(credential)
176
if res && res.code == 302
177
opts = {
178
'uri' => '/common/applications/uploadFrame.jsf',
179
'method' => 'GET',
180
'headers' => {
181
'Cookie' => "JSESSIONID=#{self.jsession}"
182
},
183
'cgi' => false
184
}
185
res = send_request(opts)
186
187
p = /<title>Deploy Applications or Modules/
188
if (res && res.code.to_i == 200 && res.body.match(p) != nil)
189
return {:status => Metasploit::Model::Login::Status::SUCCESSFUL, :proof => res.body}
190
end
191
elsif res && is_secure_admin_disabled?(res)
192
return {:status => Metasploit::Model::Login::Status::DENIED_ACCESS, :proof => res.body}
193
elsif res && res.code == 400
194
return {:status => Metasploit::Model::Login::Status::UNABLE_TO_CONNECT, :proof => res.body}
195
end
196
197
{:status => Metasploit::Model::Login::Status::INCORRECT, :proof => res.body}
198
end
199
200
201
# Decides which login routine and returns the results
202
#
203
# @param credential [Metasploit::Framework::Credential] The credential object
204
# @return [Result]
205
def attempt_login(credential)
206
result_opts = { credential: credential }
207
208
begin
209
case self.version
210
when /^2\.x$/
211
status = try_glassfish_2(credential)
212
result_opts.merge!(status)
213
when /^[34]\./
214
status = try_glassfish_3(credential)
215
result_opts.merge!(status)
216
when /^9\.x$/
217
status = try_glassfish_9(credential)
218
result_opts.merge!(status)
219
end
220
rescue ::EOFError, Errno::ECONNRESET, Rex::ConnectionError, OpenSSL::SSL::SSLError, ::Timeout::Error => e
221
result_opts.merge!(status: Metasploit::Model::Login::Status::UNABLE_TO_CONNECT, proof: e)
222
end
223
224
Result.new(result_opts)
225
end
226
227
228
# Extract the target's glassfish version from the HTTP Server Sun Java System Application Server 9.1header
229
# (ex: Sun Java System Application Server 9.x)
230
#
231
# @param banner [String] `Server` header from a Glassfish service response
232
# @return [String] version string, e.g. '2.x'
233
# @return [nil] If the banner did not match any of the expected values
234
def extract_version(banner)
235
# Set version. Some GlassFish servers return banner "GlassFish v3".
236
if banner =~ /(GlassFish Server|Open Source Edition)[[:blank:]]*(\d\.\d)/
237
@version = $2
238
elsif banner =~ /GlassFish v(\d)/
239
@version = $1
240
elsif banner =~ /Sun GlassFish Enterprise Server v2/
241
@version = '2.x'
242
elsif banner =~ /Sun Java System Application Server 9/
243
@version = '9.x'
244
else
245
@version = nil
246
end
247
248
return @version
249
end
250
251
252
end
253
end
254
end
255
end
256
257
258