Critical Path Traversal Flaw Leads to Remote Code Execution in parisneo/lollms
Introduction
Hello everyone! I am Nhien Pham, aka nhienit. Today, I would like to share about the CVE-2024-5443 vulnerability that I discovered in a product called parisneo/lollms through huntr (a bug bounty platform for AI/ML). Here’s how I uncovered and reported this vulnerability.
Product Overview
Lord of Large Language Models (LoLLMs) Server is a text generation server based on large language models. It provides a Flask-based API for generating text using various pre-trained language models. This server is designed to be easy to install and use, allowing developers to integrate powerful text generation capabilities into their applications. (Details at: https://github.com/ParisNeo/lollms-webui).
Vulnerability Summary
The security patch for previous vulnerabilities was insufficient, allowing attackers to easily bypass it using empty string to exploit the Path Traversal vulnerability. This enables changing the value of extension_path to any directory within the lollmsElfServer configuration and executing the ExtensionBuilder().build_extension() function to load malicious code uploaded by the attacker.
Background
Even before I discovered this vulnerability, you can see that there have been many Path Traversal vulnerabilities (including mine) reported and listed on Hacktivity on huntr. Below is an illustrative image.
Therefore, the prevention mechanisms for this type of vulnerability are continuously improving and frequently updated.
Among them, the file lollms/security.py contains functions to check and detect malicious inputs received from users.
And this prevention function is implemented in most endpoints within the application to control the input.
We see that all the tricks used for exploitation from previous reports have been patched. Therefore, I decided to delve deeper into this mechanism to find a way to break them and bypass.
Analyzing the Vulnerability in Detail
Bypass the filter Before delving deeper and identifying the actual vulnerability, I first looked at the function at the /get_personality_config endpoint, which is described as follows:
At [1][2], the data.category and data.name values are user-controllable, and these values are passed through the sanitize_path() function filter:
As we can clearly see, the filter tightly controls the use of special characters to prevent escaping from the default path, so inputs starting with payloads like ../ , / , \\ , ... and paths considered as absolute paths are detected. At [3], the two values data.category and data.name are concatenated with a / separator, and the result is appended to the default path that users are allowed to access at [4]. In Python, we can append a Path object with a string to concatenate paths together, for example:
However, if the concatenated string starts with a path separator (or is an absolute path), the preceding path will be ignored.
Therefore, the vulnerability here is that the data.category and data.name values are not checked for empty string, allowing an attacker to exploit the separator between these values to create an absolute path and control the path based on the second value.
Excellent, at this point I can confirm that I have bypassed the filter. However, at the /get_personality_config endpoint, exploiting Path Traversal doesn't seem to create a significant issue, so I need to review other functions.
More impact, more money
After reviewing previously disclosed vulnerabilities, I found a vulnerability with the code CVE-2024-4320 described in great detail by another huntr, retr0reg (see details at: https://huntr.com/bounties/d6564f04-0f59-4686-beb2-11659342279b). The vulnerability describes that at the /install_extension endpoint, an attacker can exploit the Path Traversal vulnerability through the extension_path variable to the path where the attacker has uploaded malicious code and execute the ExtensionBuilder().build_extension() function to load the malicious code.
Upon quick inspection, the vulnerability has been patched at the /install_extension endpoint, but I discovered that I can indirectly execute the ExtensionBuilder().build_extension() function through the lollmsElfServer.rebuild_extensions() function of another endpoint, /mount_extension .
As described above, we can completely bypass and control the value of package_full_path to a path of our choosing. At [5], it checks if the config.yaml file exists in the folder; if it exists, the package_full_path will be added to the list of extensions defined in lollmsElfServer.config["extensions"] . At [7], the lollmsElfServer.rebuild_extensions() function is executed as follows:
Here, it will iterate through all extension_path paths in the config added at [5] to load them through the ExtensionBuilder().build_extension() function.
When the ExtensionBuilder().build_extension() function is executed, it will continue to call the ExtensionBuilder().getExtension() function at [8]. Since extension_path is always the absolute path value that we provide, we can easily control the value of the absolute_path variable as desired. Additionally, at [9], the ExtensionBuilder().getExtension() function will search for the __init__.py file in the path provided by the attacker to load the code inside this file.
Exploit Conditions
- Must know discussion_id
- Must know the path to the personal_data folder
Proof-of-Concept
To exploit this vulnerability, we first need to create any conversation.
Create 2 files called config.yaml and \_\.py as show below:
And then upload the config.yaml and __init__.py files created through the Send file to AI function.
Send the request as shown below to execute OS command.
Where discussion_id can be easily guessed through brute-force attacks because it is an integer value.
The Patch
I quickly reported this vulnerability on huntr, and the vendor promptly acknowledged it.
And the vendor patched the vulnerability by removing these dangerous functions.
Conclusion
Discovering this vulnerability was an exciting process for me, it helped me find new techniques for exploiting vulnerabilities by thoroughly examining application source code, contributing to making applications safer. Additionally, I would like to thank huntr for creating such an interesting platform, which allows those of us who enjoy auditing code to develop our skills and share our findings with the community.
👉 Think you have the skills to discover unique vulnerabilities like our talented community members? Dive into the hunt at huntr.com and show us what you’ve got!