Bash Tricks for File Exfiltration over HTTP/S using Flask

Allen Butler
Maveris Labs
7 min readMar 2, 2022

--

This post is part of a series on data extraction techniques on Linux Systems. If you like what you read here, be sure to stay tuned for additional articles! You can view the released articles here:

Introduction

Receiving command output over HTTP/S is pretty straight forward, but capturing larger files and saving them off to the local disk is a little more complicated. It typically requires a special web server which has the ability to parse multipart/form-data messages in requests. This post will outline the techniques available to not only exfiltrate files using curl, but also how to encode, encrypt, and save captured files using a custom-built Flask web server.

Exfiltrating Files

“Huh? What do you mean? Why not just run cat /etc/passwd and call it a day?". Well, there is so much more we can do to exfiltrate files than just simply calling cat on them. Sure, cat can be useful for small files, but it isn't great for extracting multiple files at the same time, nor does it maintain filenames unless you save it manually on the attack system after receiving output.

Before moving on to the cool stuff, lets take a quick look at what it looks like to exfiltrate /etc/passwd, without cat, using curl:

🤓 will represent the Victim machine

💀 will represent the Attacker machine

As shown, the request uses a multipart/form-data message and sends the file using an encapsulation boundary. This allows web servers to parse multiple "body parts" as their own request and is how many web applications distinguish file upload requests. curl -F is an argument which enables uploading of binary files and forces the content-type to a multipart message. This isn’t always necessary to upload files, as you could just push the file as raw data over a POST request, but many web clients support this functionality and it makes it much easier to use web server libraries to parse files from HTTP requests. The @ symbol signals curl -F to retrieve and attach the content of the provided filepath to the request and apply its content-type.

Receiving Files with a Custom Web server

It’s one thing to upload files using tools like curl, but receiving, parsing, and saving files is a little more involved and requires a web server with a handler for file upload. There are many tools available for handling file uploads including this SimpleHTTPServerWithUpload.py script or perhaps this NGINX Upload Module. Despite these already available tools, I much prefer to build my own when I can, not as a means to "reinvent the wheel" per se, but rather as a learning opportunity. When it comes to web servers, I find myself using Flask for Python often, as it’s easy to learn and write custom web applications. I can have a custom server set up for many use cases in just minutes, and learning this framework has proven to be incredibly useful for ad-hoc needs mid-assessment. For example, the following code is all that is needed to handle file uploads from clients and store them on our attack filesystem in a unique and identifiable way:

This simple example server code will store any file POSTed to it in the directory ./uploads/<request_ip>/<timestamp>.<filename>. Here is an example after uploading /etc/hosts and /etc/passwd from the Victim's system:

Multiple File Exfiltration, Archiving, and Compression using Tar

This method is something I’ve found to be incredibly useful during assessments on Linux systems. It allows for automatic gzip compression and archiving of multiple files at once, and can push data over stdout, meaning that an entire exfiltration command can stay off disk and upload multiple files at once. Additionally, because of the compression tar uses, directory structures, permissions, and modified/created timestamps are maintained in the final archive, meaning that after exfiltration I have a near-exact replication of the directory structure the files were found in. This fact alone makes this method one of the most useful exfiltration techniques for offline analysis.

Let’s see how this works. First, we need to add a handler to our upload server to auto extract tar archives if one is detected.

Notably, we’ve added in the mechanisms necessary to auto extract gzipped tar archives, along with a safety function to confirm that the tar archive does not contain any unsafe members which may overwrite existing files. This new server will extract tar archives containing multiple files into a directory structure replicating the Victim’s.

We are going to change up our file upload command a bit as well to archive and exfiltrate an entire directory of files without touching disk:

This command creates (c) an archive of /var/log, gzips (z) it, and pushes it to curl via stdin. Curl captures the output from stdin using the @- symbol and posts it to the Attack system. Once received, the server validates the tar archive, and extracts it to the uploads/<victim_addr>/ directory like so:

Pretty cool right? To showcase an additional capability we get through this exfiltration method, any archives we create and exfiltrate that reside within an already extracted directory will be added to that directory without removing existing files. This means that as we exfiltrate, the directory structure is maintained for new files, without losing any previously exfiltrated files. Confused? Here is an example:

It should be noted, however, if a file previously exfiltrated is exfiltrated again through this technique, it will be overwritten upon extraction, meaning you will lose the historical record of the files unless otherwise tracked.

Encryption

Encrypting these archives is the next natural progression in my file exfiltration process. We can use the same techniques illustrated in my previous article on Command and Data Exfiltration. Again, encrypting payloads means we don’t have to store unencrypted sensitive data on our infrastructure unless we are analyzing it. In the following example, however, I will implement a feature which allows for auto decryption of encrypted payloads before saving to disk.

Lets once again modify our server to now handle encrypted payloads. We will modify our existing “auto-untar” Flask server to check for a parameter that tells the server that the payload is encrypted. We will then decrypt the payload using a provided password and continue on with our previously built processes. Check out the new server source code here:

This server requires the pycrypto module be installed from pip.

We now have a pretty capable server which can handle base64 encoded, AES encrypted, gzipped tar archives for file exfiltration. All of which can be sent using command line tools found on many Linux-derived operating systems and simultaneously staying off the victim’s disk, living in memory.

See it in action here:

Conclusion

Hopefully, if you’ve gotten to this point, you feel a bit more knowledgeable on how Flask can be an incredible asset in your toolbox for rapidly developing powerful web servers for your ad-hoc needs. In the case of file exfiltration, combined with the Linux bash tricks outlined here, this use case is but one of many ways you can arm yourself in the future by living-off-the-land. Not only are we able to mirror our victim’s filesystem precisely using tar, we are able to do so without writing a single file to their filesystem, using native tools. Now that's pretty awesome!

Maveris is an IT and cybersecurity company committed to helping organizations create secure digital solutions to accelerate their mission. We are Veteran-owned and proud to serve customers across the Federal Government and private sector. Maveris Labs is a space for employees and customers to ask and explore answers to their burning “what if…” questions and to expand the limits of what is possible in IT and cybersecurity. To learn more, go to maveris.com/#maveris-labs.

--

--