Last updated
Last updated
This vulnerability was reported on by , this affects the [anything-llm] web application which setups an API on port 8888. This API is built using python and flask and contains a vulnerability allowing any unauthenticated user to delete any arbitrary file by sending a POST request to /process
endpoint.
Taking a quick look at how the API processes this request:
A very high level overview of this is that the application parses the JSON data containing the filename
object and pass it to the process_single
function.
The process_single
function as shown above performs some basic check such as checking if the specified file exists on the system or not. It also checks if any of the requested file is a locked file, if it is just skip the processing. There's a special case that if a requested file is not in the allowed extension it attempt to move the requested file to a different directory i.e. failed
or processed
. As seen below, following piece of code handles the restricted extension in the requested file and call move_source
function with failed
and remove
both set to True
and target_doc
parameter which is the specified file we sent via JSON body i.e. filename
Checking move_source
function, we see that if the remove
and failed
is set to True
it will call os.remove
with new_destination_filename
as parameter which was filename
in the previous code where this function was called.
Coming to the vulnerability, as you may have noticed that the application doesn't have any logic to check for path traversal or input sanitization on the filename
parameter. The thing is there's a limited impact but if done cleverly the impact is high, for instance we cannot trigger the vulnerability if the filename doesn't have an extension or if the extension is in allowed list as it will not trigger the move_source
trigger to perform deletion. So, if we give something like ../../../../../../../etc/passwd
it won't work as the file does not have an extension but giving something like ../../../../../../etc/resolv.conf
as it will trigger the move_source
function because .conf
extension isn't allowed.
The reason we are using
../
is becauseos.remove(f"{working_dir}/{new_destination_filename}")
also takesworking_dir
which ishotdir
into consideration
In this case, I will create a file name resolv.conf
in /tmp
folder and will attempt to delete it:
Checking the API logs:
The file is successfully deleted from the system.
A commit was made to the repository to patch this vulnerability and the patched code now sanitizes the specified parameter for any potential of directory traveral:
If we see how the modified code is dealing with the payloads that was used to traverse:
This vulnerability is a cause of improper input validation although it is important to look into the fact how the application process things like files especially if it can somewhow be controlled. Another thing that makes this vulnerability of higher impact is that /process
action can be perform unauthenticated, it is important to have some form of authentication if a critical action like this is being offered by API. The best way to look for these kind of vulnerabilities is to see all the file-based actions that application is performing and if we can control any aspect of this process. It is better to narrow it down to functions which handle file-based operations, some of them are listed below:
It is not an exhaustive list as anyone can write their own functions which may be a wrapper around following functions or others.
open()
close()
read()
write()
readline()
seek()
tell()
flush()
Modules:
os
shutil
pathlib
io
csv
json