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/chef_webui.rb
Views: 1904
1
2
require 'metasploit/framework/login_scanner/http'
3
4
module Metasploit
5
module Framework
6
module LoginScanner
7
8
# The ChefWebUI HTTP LoginScanner class provides methods to authenticate to Chef WebUI
9
class ChefWebUI < HTTP
10
11
DEFAULT_PORT = 80
12
PRIVATE_TYPES = [ :password ]
13
14
# @!attribute session_name
15
# @return [String] Cookie name for session_id
16
attr_accessor :session_name
17
18
# @!attribute session_id
19
# @return [String] Cookie value
20
attr_accessor :session_id
21
22
# Decides which login routine and returns the results
23
#
24
# @param credential [Metasploit::Framework::Credential] The credential object
25
# @return [Result]
26
def attempt_login(credential)
27
result_opts = {
28
credential: credential,
29
status: Metasploit::Model::Login::Status::INCORRECT,
30
proof: nil,
31
host: host,
32
port: port,
33
protocol: 'tcp'
34
}
35
36
begin
37
status = try_login(credential)
38
result_opts.merge!(status)
39
rescue ::EOFError, Errno::ECONNRESET, Rex::ConnectionError, OpenSSL::SSL::SSLError, ::Timeout::Error => e
40
result_opts.merge!(status: Metasploit::Model::Login::Status::UNABLE_TO_CONNECT, proof: e)
41
end
42
43
Result.new(result_opts)
44
end
45
46
# (see Base#check_setup)
47
def check_setup
48
begin
49
res = send_request({
50
'uri' => normalize_uri('/users/login')
51
})
52
return "Connection failed" if res.nil?
53
54
if res.code != 200
55
return "Unexpected HTTP response code #{res.code} (is this really Chef WebUI?)"
56
end
57
58
if res.body.to_s !~ /<title>Chef Server<\/title>/
59
return "Unexpected HTTP body (is this really Chef WebUI?)"
60
end
61
62
rescue ::EOFError, Errno::ETIMEDOUT, OpenSSL::SSL::SSLError, Rex::ConnectionError, ::Timeout::Error
63
return "Unable to connect to target"
64
end
65
66
false
67
end
68
69
# Sends a HTTP request with Rex
70
#
71
# @param (see Rex::Proto::Http::Request#request_raw)
72
# @return [Rex::Proto::Http::Response] The HTTP response
73
def send_request(opts)
74
res = super(opts)
75
76
# Save the session ID cookie
77
if res && res.get_cookies =~ /(_\w+_session)=([^;$]+)/i
78
self.session_name = $1
79
self.session_id = $2
80
end
81
82
res
83
end
84
85
# Sends a login request
86
#
87
# @param credential [Metasploit::Framework::Credential] The credential object
88
# @return [Rex::Proto::Http::Response] The HTTP auth response
89
def try_credential(csrf_token, credential)
90
91
data = "utf8=%E2%9C%93" # ✓
92
data << "&authenticity_token=#{Rex::Text.uri_encode(csrf_token)}"
93
data << "&name=#{Rex::Text.uri_encode(credential.public)}"
94
data << "&password=#{Rex::Text.uri_encode(credential.private)}"
95
data << "&commit=login"
96
97
opts = {
98
'uri' => normalize_uri('/users/login_exec'),
99
'method' => 'POST',
100
'data' => data,
101
'headers' => {
102
'Content-Type' => 'application/x-www-form-urlencoded',
103
'Cookie' => "#{self.session_name}=#{self.session_id}"
104
}
105
}
106
107
send_request(opts)
108
end
109
110
111
# Tries to login to Chef WebUI
112
#
113
# @param credential [Metasploit::Framework::Credential] The credential object
114
# @return [Hash]
115
# * :status [Metasploit::Model::Login::Status]
116
# * :proof [String] the HTTP response body
117
def try_login(credential)
118
119
# Obtain a CSRF token first
120
res = send_request({
121
'uri' => normalize_uri('/users/login')
122
})
123
unless (res && res.code == 200 && res.body =~ /input name="authenticity_token" type="hidden" value="([^"]+)"/m)
124
return {:status => Metasploit::Model::Login::Status::UNTRIED, :proof => res.body}
125
end
126
127
csrf_token = $1
128
129
res = try_credential(csrf_token, credential)
130
if res && res.code == 302
131
opts = {
132
'uri' => normalize_uri("/users/#{credential.public}/edit"),
133
'method' => 'GET',
134
'headers' => {
135
'Cookie' => "#{self.session_name}=#{self.session_id}"
136
}
137
}
138
res = send_request(opts)
139
if (res && res.code == 200 && res.body.to_s =~ /New password for the User/)
140
return {:status => Metasploit::Model::Login::Status::SUCCESSFUL, :proof => res.body}
141
end
142
end
143
144
{:status => Metasploit::Model::Login::Status::INCORRECT, :proof => res.body}
145
end
146
147
end
148
end
149
end
150
end
151
152
153