Overview of Malicious File Upload Attacks
by Jeremy Conley
Posted in Articles, Coders, PHP on
Overview:
Uploading files is a necessity for any web application with advanced functionality. Whether it is a web mail client, a company’s internal Content Management System (CMS), a social networking site, an intranet document sharing portal, or any of the other myriads of options out there, users need a way to share files. Sometimes just typing in a text field is not enough: there must be ways to share pictures or Word files, for example.
While most users will play by the rules and only upload normal pictures or documents, what is to stop a hacker from uploading a virus, malware, or a backdoor? How can these types of attacks be prevented? While it would be easiest (and by extension, safest) to disallow file uploads completely, as we have already seen, file uploads are a must. But how can these malicious files be blocked while allowing legitimate file uploads from regular users?
Defenses:
Before exploring some of the defenses against malicious uploads, let us first look some of the principles behind secure uploads. The first principle is to always assume a user is trying to trick the system. Being suspicious is always the first step towards maintaining a secure system. Therefore, the first step we as developers should take is to make sure that we are in fact dealing with an uploaded file. If a hacker knows we are doing something with an uploaded file such as reading it, then she or he might try to trick the program by calling another file instead of an actual uploaded file. For example, the hacker might try to pass /etc/passwd (the UNIX/Linux password file) and hope the program will blindly read any file specified. If so, we would have a very serious system compromise since the hacker would discover the list of users and passwords on that system.
To protect against “fake uploads,” a developer can use the is_uploaded_file() PHP function which verifies that the variable is indeed an uploaded file. Once the file has been verified as a valid upload, it can be moved from temporary storage into a more permanent location. To do this securely, a developer can use the move_uploaded_file() PHP function to ensure that the file moved to a permanently location was the same as the one uploaded. While there are no known attacks, this adds a layer of safety to the upload system.
Now, we have saved our profile picture to images/ or the document to docs/ and we have verified that it is not a system file like /etc/passwd we can continue processing. Wait! Actually, we have already introduced a major security hole into the system already. Files should never be stored in a public directory where users can directly access them. For example, files should not be stored where they can be reached at example.com/images/uploads/profile-picture.jpg If the file is reachable via a URL, a hacker can send others the link to download the file. If the link is a pirated program that is bad enough, but what if the file is malware and the hacker embeds the link in JavaScript and uses your server to dish out malware?
This is why uploaded files should never be directly reachable. Instead, files should be stored outside of the document root directory then an intermediary script can access the file then perform security checks before outputting it to the user. Let’s look closer to see how this is done. At this point, we have used move_uploaded_file() in our PHP script to safely move the file out of the direct reach of the user, and now we can scan it for potential problems. We might be tempted to check the file’s extension, or if we are feeling especially ambitious, we might even check the file’s Multipurpose Internet Mail Extension (MIME) type and compare them to see if they are valid file types. Being mindful of previous security articles, we will even use a whitelist of allowed file extensions (such as .jpg for images) and MIME types (like image/jpg for images). However, we must resist that urge since the file extension is no guarantee of the file’s real type. For example, while Microsoft Word 2007 and above files have a .docx extension, they are in fact a type of ZIP archive. And while the MIME type may seem safer since the user cannot change this, remember it is sent by the browser and can easily be intercepted and changed with a good proxy tool.
If we can’t rely upon file extensions or MIME types, what can we use then? Actually, there is nothing within the file itself we can reliably use. The safest method now would be to use a good anti-virus program such as Clam AntiVirus to scan the file on the server before allowing the end user access to it. It is vitally important that the server scans it and not the user. A user may not have antivirus or the latest updates, so the file could infect the user’s computer.
This is the best overall solution since we can be reasonably certain that the file is now safe. (We must realize though the file could have zero day exploits that no antivirus would find.) However, if we are just dealing with images exclusively like in a photo app or profile picture, then we could take a bit easier approach by using the imagecreatefromjpg() or imagecreatefrompng() depending on the file type to use PHP to copy the uploaded image into memory then save it again. While this seems like a needless step, actually it adds quite a bit of security by both verifying the file is an actual image (something that the extension or MIME type cannot) and that it does not contain any malicious code in the header or comment section of the binary file. We can be assured that these PHP function will only output safe data for us.
Conclusion:
We as developers must always assume that any file upload contains malware unless it is proven otherwise. If we take this deny first approach, then our systems will be safer since we are aware of the dangers of user submitted files. The next precaution we will take is to make sure that the users cannot access the files, and that we will control how the file gets sent and what security checks are performed before the file is sent to the user. We will also not rely upon any user submitted information like the file extension or type when determining if the file is valid and instead we will either use an antivirus program or resave an image to ensure we have only safe files on the server.
References:
Bezroutchko, A. Secure File Upload in PHP Applications. (2007).
Calin, B. Why File Upload Forms Are a Major Security Threat. (2009).
ClamAV. (n.d.).
Is Uploaded File PHP Function. (n.d.).
Shiflett, C. File Uploads. (2004).
about the author
More about Jeremy Conley:
Jeremy is a student at Western Michigan University where he is dual majoring in Electronic Business Design and Film & Video Studies. When not programming or researching design and security topics, Jeremy enjoys movies and photography and drinking coffee in all the amazing local Kalamazoo coffee shops.
questions or comments?
If you have any questions or comments about this article, feel free to contact us!