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/jenkins.rb
Views: 1904
1
require 'metasploit/framework/login_scanner/http'
2
3
module Metasploit
4
module Framework
5
module LoginScanner
6
# Jenkins login scanner
7
class Jenkins < HTTP
8
# Inherit LIKELY_PORTS,LIKELY_SERVICE_NAMES, and REALM_KEY from HTTP
9
CAN_GET_SESSION = true
10
DEFAULT_HTTP_NOT_AUTHED_CODES = [403]
11
DEFAULT_PORT = 8080
12
PRIVATE_TYPES = [:password].freeze
13
LOGIN_PATH_REGEX = /action="(j_([a-z0-9_]+))"/
14
15
# Checks the setup for the Jenkins Login scanner.
16
#
17
# @return [String, false] Always returns false.
18
def check_setup
19
login_uri = jenkins_login_url
20
21
return 'Unable to locate the Jenkins login path' if login_uri.nil?
22
23
self.uri = normalize_uri(login_uri)
24
25
false
26
end
27
28
# (see Base#set_sane_defaults)
29
def set_sane_defaults
30
self.uri ||= '/'
31
32
unless uri.to_s.start_with?('/')
33
self.uri = "/#{uri}"
34
end
35
36
super
37
end
38
39
def attempt_login(credential)
40
result_opts = {
41
credential: credential,
42
host: host,
43
port: port,
44
protocol: 'tcp'
45
}
46
47
if ssl
48
result_opts[:service_name] = 'https'
49
else
50
result_opts[:service_name] = 'http'
51
end
52
53
status, proof = jenkins_login(credential.public, credential.private)
54
55
result_opts.merge!(status: status, proof: proof)
56
57
Result.new(result_opts)
58
end
59
60
protected
61
62
# Returns a boolean value indicating whether the request requires authentication or not.
63
#
64
# @param [Rex::Proto::Http::Response] response The response received from the HTTP endpoint
65
# @return [Boolean] True if the request required authentication; otherwise false.
66
def authentication_required?(response)
67
return false unless response
68
69
self.class::DEFAULT_HTTP_NOT_AUTHED_CODES.include?(response.code)
70
end
71
72
private
73
74
# This method takes a username and password and a target URI
75
# then attempts to login to Jenkins and will either fail with appropriate errors
76
#
77
# @param [String] username The username for login credentials
78
# @param [String] password The password for login credentials
79
# @return [Array] [status, proof] The result of the login attempt
80
def jenkins_login(username, password)
81
begin
82
res = send_request(
83
'method' => 'POST',
84
'uri' => self.uri,
85
'vars_post' => {
86
'j_username' => username,
87
'j_password' => password,
88
'Submit' => 'log in'
89
}
90
)
91
92
if res && res.headers['Location'] && !res.headers['Location'].include?('loginError')
93
status = Metasploit::Model::Login::Status::SUCCESSFUL
94
proof = res.headers
95
else
96
status = Metasploit::Model::Login::Status::INCORRECT
97
proof = res
98
end
99
rescue ::EOFError, Errno::ETIMEDOUT, Errno::ECONNRESET, Rex::ConnectionError, OpenSSL::SSL::SSLError, ::Timeout::Error => e
100
status = Metasploit::Model::Login::Status::UNABLE_TO_CONNECT
101
proof = e
102
end
103
104
[status, proof]
105
end
106
107
# This method uses the provided URI to determine whether login is possible for Jenkins.
108
# Based on the contents of the provided URI, the method looks for the login form and
109
# extracts the endpoint used to authenticate against.
110
#
111
# @return [String, nil] URI for successful login
112
def jenkins_login_url
113
response = send_request({ 'uri' => normalize_uri('login') })
114
115
if response&.code == 200 && response&.body =~ LOGIN_PATH_REGEX
116
return Regexp.last_match(1)
117
end
118
119
nil
120
end
121
122
# Determines whether the provided response is considered valid or not.
123
#
124
# @param [Rex::Proto::Http::Response, nil] response The response received from the HTTP request.
125
# @return [Boolean] True if the response if valid; otherwise false.
126
def valid_response?(response)
127
http_success_codes.include?(response&.code)
128
end
129
end
130
end
131
end
132
end
133
134