phpimagemagickimage-resizingimagickimagemagick-identify

How to prevent image bombs with ImageMagick?


I currently use Imagick library on PHP and use the resizing functionality of Image Magick. I've just learned about decompression bombs and how ImageMagick is vulnerable to it.

I have checked how we can ping the image and verify the dimensions of the image without actually loading it into memory/disk. It's also safer to limit the memory and disk limits of ImageMagick so it wouldn't just write a huge file on disk.

I've read and I can do that with setResourceLimit(). http://php.net/manual/en/imagick.setresourcelimit.php

IMagick::setResourceLimit(IMagick::RESOURCETYPE_MEMORY , 100);
IMagick::setResourceLimit(IMagick::RESOURCETYPE_DISK , 100);

$thumb = new Imagick('image.png');
$thumb->resizeImage(320,240,Imagick::FILTER_LANCZOS,1);

However, what happens is that after setting the limit of disk and memory, if an image does hit this limit, all I get is a segmentation fault error, no exceptions are thrown. This makes it impossible for me to handle it properly.

Update:

Here are the package versions I'm using:

dpkg -l | grep magick
ii  imagemagick-common                    8:6.6.9.7-5ubuntu3.3              image manipulation programs -- infrastructure
ii  libmagickcore4                        8:6.6.9.7-5ubuntu3.3              low-level image manipulation library
ii  libmagickwand4                        8:6.6.9.7-5ubuntu3.3              image manipulation library
ii  php5-imagick                          3.1.0~rc1-1                       ImageMagick module for php5

Solution

  • Setting the 'Resource Area' limit only sets the size at which images are not held in memory, and instead are paged to disk. If you want to use that setting to actually restrict the maximum size image that can be openend, you also need to set the 'Resource Disk' limit.

    The code below correctly gives a memory allocation error for the image bombs taken from here.

    try {
        Imagick::setResourceLimit(Imagick::RESOURCETYPE_AREA, 2000 * 2000);
        Imagick::setResourceLimit(Imagick::RESOURCETYPE_DISK, 2000 * 2000);
    
        $imagick = new Imagick("./picture-100M-6000x6000.png");
        $imagick->modulateImage(100, 50, 120);
        $imagick->writeImage("./output.png");
    
        echo "Complete";
    }
    catch(\Exception $e) {
        echo "Exception: ".$e->getMessage()."\n";
    }
    

    Output is:

    Exception: Memory allocation failed `./picture-100M-6000x6000.png' @ error/png.c/MagickPNGErrorHandler/1630

    If you want to set the width and height resource, and have a version of ImageMagick >= 6.9.0-1 you should be able to using the values directly of WidthResource = 9, HeightResource = 10

    //Set max image width of 2000
    Imagick::setResourceLimit(9, 2000);
    //Set max image height of 1000
    Imagick::setResourceLimit(10, 1000);
    

    These don't have to be set programmatically, you can set them through the policy.xml file installed with ImageMagick. ImageMagick reads that file and uses those settings if none are set in a program - which may be a more convenient way of setting them, as you can change them per machine.

    This makes it impossible for me to handle it properly.

    It makes it impossible for you to handle it in the same process. You can handle it just fine by running the image processing in a background task.

    Personally I think anyway that uses Imagick in a server that is accessed directly by web-browsers is nuts. It is far safer to run it in as a background task (managed by something like http://supervisord.org/) and communicating with that background task via a queue of jobs that need to be processed.

    Not only does that solve the 'bad images can bring down my website' problem, it also makes it far easier to monitor resource usage, or shift the image processing to a machine with a faster CPU than a web-front end server needs.

    Source - I'm the maintainer of the Imagick extension and I recently added this to the Imagick readme:

    Security

    The PHP extension Imagick works by calling the ImageMagick library. Although the ImageMagick developers take good care in avoiding bugs it is inevitable that some bugs will be present in the code. ImageMagick also uses a lot of third party libraries to open, read and manipulate files. The writers of these libraries also take care when writing their code. However everyone makes mistakes and there will inevitably be some bugs present.

    Because ImageMagick is used to process images it is feasibly possible for hackers to create images that contain invalid data to attempt to exploit these bugs. Because of this we recommend the following:

    1) Do not run Imagick in a server that is directly accessible from outside your network. It is better to either use it as a background task using something like SupervisorD or to run it in a separate server that is not directly access on the internet.

    Doing this will make it difficult for hackers to exploit a bug, even if one should exist in the libraries that ImageMagick is using.

    2) Run it as a very low privileged process. As much as possible the files and system resources accessible to the PHP script that Imagick is being called from should be locked down.

    3) Check the result of the image processing is a valid image file before displaying it to the user. In the extremely unlikely event that a hacker is able to pipe arbitrary files to the output of Imagick, checking that it is an image file, and not the source code of your application that is being sent, is a sensible precaution.