Enterprice File Sharing

Description

For security reasons we only use enterprice grade cloud storage.

2KB
Open

Solution

Code Review

This, for the most part, seems like a standard file hosting site. Let's take a look at the validation.

First, uploaded files must have one of the allowed extensions.

# We only allow files for serious business use-cases
ALLOWED_EXTENSIONS = {'txt', 'pdf', 'doc', 'docx', 'xls', 'xlsx'}


def allowed_file(filename):
    return '.' in filename and \
           filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS

We also see that steps have been taken to normalize the file paths, to prevent directory traversal attacks using ../.

What seems out of the ordinary, though, is the use of os.system() to execute a tar command when the user requests to download all uploaded files. Surely there's a library for that!

Wildcard Injection

I decided to pay closer attention to the system command: cd {sess_dir} && tar czf /tmp/{sess_id}.tgz *.

A bit of research led me to a few very interesting papers, one of which was this. Apparently, this is a class of Unix vulnerabilities where wildcards in commands can be abused to inject arguments!

For instance, if you have a file named -rf, and you execute rm *, the wildcard gets substituted with -rf, which is interpreted as a command line argument!

Now, how can we abuse this in our use case? In tar, there is a --checkpoint-action option that will specify which program will be executed when a "checkpoint" is reached.

A common payload to exploit this would be two files:

  • --checkpoint-action=exec=sh shell.sh

  • --checkpoint=1

Now, the first file and the script are no problem - we can use --checkpoint-action=exec=sh shell.txt to perform argument pollution, which works because this ends with .txt.

We cannot use checkpoint=1 , though, because this won’t pass the extension check.

Looking a bit more into the Tar manual, I saw that the default checkpoint number is 10, which means that the checkpoint action is performed every 10 records.

But how big is each record? Apparently, it's 20 512-byte blocks.

So if we upload enough bytes, our tar archive will eventually exceed 10 records * 20 blocks * 512 bytes = 102400 bytes. Once that happens, we would have 10 records within the tar archive and the checkpoint action will be executed.

Once we request /download_all and the tar command is run, we get a shell.

Last updated

Was this helpful?