4 minutes
CVE-2024-55187: Remote Code Execution in phpIPAM
Introduction
This CVE was discovered together with mallo-m. Their repository (with screenshots and extra context) is available here: https://github.com/mallo-m/CVE-2024-55187/tree/main
CVE-2024-55187 is a critical vulnerability affecting phpIPAM. In short, an authenticated attacker with administrative privileges can achieve remote code execution by combining (1) a configurable path to a system binary and (2) a file upload feature that can leave attacker-controlled files on disk.
Summary
Sensitive administrative parameters are not sufficiently sanitized, allowing an attacker to poison paths to system binaries.
The attacker can then upload dangerous CSV files that can be treated as PHAR archives holding shell metacharacters that will be evaluated by PHP’s exec() call, resulting in remote code execution.
Impact
- Server takeover
- Denial of Service
- Loss of data
CVSS score
Critical - 9.1 - CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:C/C:H/I:H/A:H
Details
This issue is a chain that combines a command injection primitive (unsanitized exec() input) with a bypass of the path validation logic using PHP stream wrappers.
1) User-controlled ping path reaches exec()
In functions/classes/class.Scan.php, a ping command string is assembled from configuration and then executed. The important points (as shown in the screenshots) are:
$ping_pathcomes from an administrative setting (“Ping path”).ping_verify_path($ping_path)is called, but it only checks existence (see next section).- The command string is built by concatenating
$ping_pathand other arguments. - The final string is executed via
exec($cmd, $output, $retval).
Screenshot reference:

The first parameter of the exec() call is directly dependent on the $ping_path parameter, which can be modified from the Admin Settings panel:

Note: in the Admin UI, the input field for the ping binary path (ping / fping / etc.) is limited to 64 characters. This does not prevent exploitation here, because a short phar://... path is sufficient to reach exec().
2) Validation can be bypassed with file_exists() + phar://
The only condition the attacker must fulfill is to make ping_verify_path return true. The screenshots show that this function relies on file_exists().
Screenshot reference:

The key detail is that file_exists() supports the phar:// stream wrapper. That wrapper can point inside an archive (PHAR, and also ZIP-like archives) even if the uploaded file has a misleading extension (for example .csv). In other words, file_exists('phar:///path/to/archive.csv/some/entry') can return true if the entry exists inside the archive.
Concrete example: if the attacker uploads a ZIP/PHAR archive named csv (or archive.csv) and it contains an entry literally named `id` (i.e., the backticks are part of the filename), then the path phar:///path/to/archive.csv/`id` is something that can satisfy file_exists(). The “execution” part only happens later, when that same string is embedded into a shell command and passed to PHP’s exec() (in this CVE, via the poisoned ping path).
Screenshot reference:

Therefore, if an attacker can upload a valid archive on the server that contains an entry whose name includes shell metacharacters (for example ;, |, backticks, $(), etc.), then:
file_exists()is satisfied (because the path points to a real entry inside the archive)- the same string is later embedded into
$cmdand passed toexec() - the shell interprets the metacharacters, leading to command execution
3) Upload primitive via XLS/CSV subnet import
An authenticated attacker can upload files through the “XLS / CSV subnet import” functionality:

The uploaded file does not have to be a valid CSV file. If the import fails, the file will not be deleted from the server. We also know where it will be stored from the import-verify.php script:

At this point, the attacker knows all the prerequisites to execute a remote code execution attack:
- Craft a PHAR archive named “something.csv”, containing 1 file whose name contains shell metacharacters
- Upload the archive through the “Import subnet” functionality
- Modify the “ping path” parameter through the Admin Panel
- Trigger the RCE by requesting a ping scan
The malicious archive can be crafted like so:

Notes based on the screenshots:
- The Linux code path constructs
$cmdfrom$ping_pathand then callsexec($cmd, ...). - The verification logic is effectively “does it exist” (via
file_exists()), not “is it a safe binary path”. - The exploit uses
phar://to make a malicious archive entry look like a valid path.
Practical exploitation detail: the archive entry name is where the payload lives. Using shell metacharacters is what turns this from “bad path” into RCE.
If you want to keep an example in the post without overfitting to a single payload, you can describe it generically (“entry name contains shell metacharacters”) as above.
Proof of concept
https://www.youtube.com/watch?v=oMvyfFrlRAs
Discovery credits
- mallo-m (https://github.com/mallo-m)
- LeTeazer (https://github.com/LeTeazer)
Timeline
- Dec 13th 2024: CVE ID requested
- Jan 10th 2025: First reach out and advisory sent to phpIpam team
- Mar 13th 2025: Second reach out
- Nov 11th 2025: Final reach out to phpIpam team
- Dec 24th 2025: Advisory published