CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
rapid7

Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.

GitHub Repository: rapid7/metasploit-framework
Path: blob/master/lib/msf/core/exploit/cacti.rb
Views: 11784
1
# -*- coding: binary -*-
2
###
3
#
4
# This mixin provides helper methods for Cacti
5
#
6
###
7
8
module Msf
9
module Exploit::Cacti
10
11
include Msf::Exploit::Remote::HttpClient
12
13
class CactiError < StandardError; end
14
class CactiNotFoundError < CactiError; end
15
class CactiVersionNotFoundError < CactiError; end
16
class CactiNoAccessError < CactiError; end
17
class CactiCsrfNotFoundError < CactiError; end
18
class CactiLoginError < CactiError; end
19
20
# Extract the version number from an HTML response
21
#
22
# @param html [Nokogiri::HTML::Document] The HTML response
23
# @return [String] The version number
24
# @raise [CactiNotFoundError] If the web server is not running Cacti
25
# @raise [CactiVersionNotFoundError] If the version string was not found
26
def parse_version(html)
27
# This will return an empty string if there is no match
28
version_str = html.xpath('//div[@class="versionInfo"]').text
29
unless version_str.include?('The Cacti Group')
30
raise CactiNotFoundError, 'The web server is not running Cacti'
31
end
32
unless version_str.match(/Version (?<version>\d{1,2}[.]\d{1,2}[.]\d{1,2})/)
33
raise CactiVersionNotFoundError, 'Could not detect the version'
34
end
35
36
Regexp.last_match[:version]
37
end
38
39
# Extract the CSRF token from an HTML response
40
#
41
# @param html [Nokogiri::HTML::Document] The HTML response to parse
42
# @return [String] The CSRF token
43
def parse_csrf_token(html)
44
html.xpath('//form/input[@name="__csrf_magic"]/@value').text
45
end
46
47
# Get the CSRF token by querying the `index.php` web page and extracting it
48
# from the response.
49
#
50
# @return [String] The CSRF token
51
# @raise [CactiNoAccessError] If the server is unreachable
52
# @raise [CactiCsrfNotFoundError] If it was not possible to get the CSRF token
53
def get_csrf_token
54
res = send_request_cgi(
55
'uri' => normalize_uri(target_uri.path, 'index.php'),
56
'method' => 'GET',
57
'keep_cookies' => true
58
)
59
raise CactiNoAccessError, 'Could not access `index.php` - no response' if res.nil?
60
61
html = res.get_html_document
62
csrf_token = parse_csrf_token(html)
63
raise CactiCsrfNotFoundError, 'Unable to get the CSRF token' if csrf_token.empty?
64
65
csrf_token
66
end
67
68
# Log in to Cacti. It will take care of grabbing the CSRF token if not provided.
69
#
70
# @param username [String] The username
71
# @param password [String] The password
72
# @raise [CactiNoAccessError] If the server is unreachable
73
# @raise [CactiCsrfNotFoundError] If the CSRF token was not provided and it was not possible to retrieve it
74
# @raise [CactiLoginError] If the login failed
75
def do_login(username, password, csrf_token: nil)
76
if csrf_token.blank?
77
print_status('Getting the CSRF token to login')
78
begin
79
csrf_token = get_csrf_token
80
rescue CactiError => e
81
raise CactiLoginError, "Unable to login: #{e.class} - #{e}"
82
end
83
84
vprint_good("CSRF token: #{csrf_token}")
85
end
86
87
print_status("Attempting login with user `#{username}` and password `#{password}`")
88
res = send_request_cgi(
89
'uri' => normalize_uri(target_uri.path, 'index.php'),
90
'method' => 'POST',
91
'keep_cookies' => true,
92
'vars_post' => {
93
'__csrf_magic' => csrf_token,
94
'action' => 'login',
95
'login_username' => username,
96
'login_password' => password
97
}
98
)
99
raise CactiNoAccessError, 'Could not login - no response' if res.nil?
100
raise CactiLoginError, "Login failure - unexpected HTTP response code: #{res.code}" unless res.code == 302
101
102
print_good('Logged in')
103
104
nil
105
end
106
107
end
108
end
109
110