We recently received a responsible disclosure from a security researcher, demonstrating an RCE exploit leveraging image uploads which were being processed by ImageMagick. Read on to understand more about the exploit, if you are vulnerable and how to mitigate.

Introduction

Most web developers take security very seriously. It is such an essential aspect of the final product that is practically baked into every decision that we make. So when someone hands you a proof-of-concept (PoC) that demonstrates a remote-code execution (RCE) vulnerability, those long-suppressed feelings of inadequacy, buried deep under decades of experience, suddenly burst forth once more. This was my initial emotional response when security researcher Jens Muller reached out to share his PoC showing how a simple image upload feature could be exploited to execute arbitrary commands on the server. Ouch.

The Problem: Unpatched software

As always, the moral of the story is going to be keep your flipping software up-to-date. But let's not waste time beating ourselves up about why we are running out-of-date software, let's try to understand the nature of the vulnerability and, more importantly, how we can plug the hole.

The particular vulnerability exploited in our case was CVE-2019-14811, which applies to Ghostscript versions before 9.50. Ghostscript is an interpreter for Postscript (PS) and PDF files. This vulnerability allows specially crafted Postscript files to disable the sandbox protections to which the Ghostscript interpreter is usually subject. With these security protections disabled the script then has access to the file system, or can execute arbitrary commands.

On Linux-based systems you can determine what version of Ghostscript you are running as follows:

  
> gs -v
GPL Ghostscript 9.15 (2014-09-22)
Copyright (C) 2014 Artifex Software, Inc.  All rights reserved.
  

We don't process Postscript files. Do we?

In our case we did not intentionally process Postscript files. This ability was baked into ImageMagick (IM), and for the old version of ImageMagick which we were running, this delegation to the Ghostscript interpreter was available by default. Newer versions of ImageMagick included in modern distributions will disable this functionality out of the box, but if you are running on an old version (or depending on where you have installed from) this Ghostscript delegation may still be enabled.

To exploit the vulnerability in this unpatched software we just need to trick the application into passing a Postscript file over to ImageMagick for processing.

Proof-of-concept

We do not intend to publish the actual PoC file in this article. However, we will look at a stripped back example which should illustrate some of the principles, and will allow you to check if you are potentially at risk.

By masquerading a Postscript file as a PNG we can trick any simple file-uploader that relies on an extension filter. After being uploaded, if this file is passed over to ImageMagick then it, instead, will see the magic bytes at the start of the file and will recognise this as a Postscript file. As such it will delegate to Ghostscript, provided this has not been disabled. If Ghostscript is running on a version < 9.50 then you will be susceptible to CVE-2019-14811. As a simple demonstration, consider a file named poc.png as follows:

      
%!PS-Adobe-2.0 EPSF-1.2
/outf (/tmp/ouch.txt) (w) file def
outf (This is NOT good news) writestring
outf closefile 
showpage
quit
%%EOF
      
    
Let's suppose this file bypasses our file-upload filter, due to it's .png extension, and that the file is passed off to ImageMagick where we intend to do some image manipulation. If we run our vulnerable version of ImageMagick, and try to convert this faux PNG file, the by-product will be a new file created at /tmp/ouch.txt. Go ahead and do this now, if a new file is created in your /tmp/ folder there is a good chance you have a problem:
  
> convert poc.png poc.gif
  

The Solution: policy.xml

If you can upgrade to the most recent versions of ImageMagick and Ghostscript the vulnerability being discussed here will likely disappear. Go ahead and do that now if you can. But even if you can upgrade, it may still be prudent to read on.

Vulnerabilities in your dependencies will come and go; as soon as one vulnerability is buried, a new one will arise. Keeping our dependencies up-to-date is how we keep ourselves safe. But as we have seen, this can be difficult, exhausting and a real time-sink. The best way to reduce this workload is to reduce the number of dependencies. As an application developer this is a real practical step towards reducing the attack surface of your application. Just ripping out a dependency is not always easy (or possible), but in this case reducing our attack surface is pretty straightforward, with the help of some ImageMagick configuration.

As ImageMagick offers a ton of functionality, it is pretty common that people only want to expose a subset of that functionality, or to restrict the operation of ImageMagick in other ways, including its memory allocation and file access rights. The policy.xml file is used to configure the functionality that ImageMagick exposes, and to apply limits to help manage its impact on the system upon which it runs. For example,

  
<policymap>
    <policy domain="resource" name="area" value="100MP"></policy>
    <policy domain="resource" name="width" value="8KP"></policy>
    <policy domain="resource" name="time" value="300"></policy>
</policymap>
  
The first policy declaration will limit the maximum image size in memory to 100MP, larger images are cached to disk. The width policy specifies a max image width in pixels, if this is exceeded an exception is thrown. The time policy sets a maximum time for a given task to run.

In our case we are interested in restricting the coders that ImageMagick will employ. To prevent any delegation to Ghostscript we can add the following policy directives:

  
<policymap>
  …
  <policy domain="coder" rights="none" pattern="PS"></policy>
  <policy domain="coder" rights="none" pattern="PS2"></policy>
  <policy domain="coder" rights="none" pattern="PS3"></policy>
  <policy domain="coder" rights="none" pattern="EPS"></policy>
  <policy domain="coder" rights="none" pattern="PDF"></policy>
  <policy domain="coder" rights="none" pattern="XPS"></policy>
  …
</policymap>
  

Finding the policy.xml

OK so now we know what we want to add, how do we find this policy.xml file? There may be other ways, but here is one recipe that worked for us. Run the following command and inspect the output:

  
> convert -debug configure logo: null:
…
2022-02-23T11:29:21+00:00 0:00.110 0.000u 6.9.6 Configure convert[10650]: configure.c/GetConfigureOptions/685/Configure
  Searching for configure file: "/home/deploy/.magick/magic.xml"
2022-02-23T11:29:21+00:00 0:00.110 0.000u 6.9.6 Configure convert[10650]: magic.c/LoadMagicCache/794/Configure
  Loading magic configure file "/etc/ImageMagick-6/magic.xml"
  
If you then inspect each of the paths where ImageMagick is looking for the magic.xml file and you should find your policy.xml file. Once you have identified a candidate file you can run the following command to list the active policy directives:
  
> convert -list policy

Path: [built-in]
  Policy: Undefined
    rights: None 
  
Now make your changes to the candidate policy.xml file and re-run the convert -list policy command:
  
> convert -list policy

Path: /etc/ImageMagick-6/policy.xml
  …
  Policy: Coder
    rights: None 
    pattern: PS
  Policy: Coder
    rights: None 
    pattern: PS2
  Policy: Coder
    rights: None 
    pattern: PS3
  Policy: Coder
    rights: None 
    pattern: EPS
  Policy: Coder
    rights: None 
    pattern: PDF
  Policy: Coder
    rights: None 
    pattern: XPS

Path: [built-in]
  Policy: Undefined
    rights: None 
  
If you see your changes listed here, then you have updated the correct file and you are good to go.

One final note before we wrap up. If, like us, you have been running with this vulnerability for some time then, after patching, it is recommended that you check your system for backdoors in the event that the vulnerability has already been exploited.

Summary

By running old versions of ImageMagick and Ghostscript we left ourselves open to an RCE vulnerability through file uploads. Experience would suggest that we are probably not alone in this. If you are processing image uploads through ImageMagick, and your policy.xml has not explicitly disabled delegation to Ghostscript, there is a possibility that you may be vulnerable to RCE from specially crafted fileuploads. Asides from this particular vulnerability, taking the time to review your policy.xml is a simple action that could very well save you some serious headaches down the line.

Thanks

A very special work of thanks to Jens Muller for the responsible disclosure of this issue, and subsequent help in identfying, recreating and resolving the vulnerability.

References

  1. https://nvd.nist.gov/vuln/detail/CVE-2019-14811
  2. ImageMagick policy.xml
  3. Playing with ImageTragic like it's 2016

Comments

There are no existing comments

Got your own view or feedback? Share it with us below …

×

Subscribe

Join our mailing list to hear when new content is published to the VectorLogic blog.
We promise not to spam you, and you can unsubscribe at any time.