Part 1 — Yet another memory leak

For the past two years vulnerabilities in ImageMagick libraries have been appearing almost every month. Fortunately, many of them are some kind of not applicable DoS, which does not pose serious security problems. But recently we have noticed an interesting CVE-2018–16323.

Sounds easy! But we didn’t find any information about exploit for this vulnerability.

Look at the commit referenced to the CVE:

Commit details

“XBM coder leaves the hex image data uninitialized if hex value of the pixel is negative“

Hmm.. Let’s explore the XBM file format. A common XBM image looks like this:

XBM Image Sample

Which is very similar to C code. This format is very old and was used in X Window System to store cursor and icon bitmaps used in the X GUI. Each value in keyboard16_bits array represents 8 pixels, each pixel is a single bit and encodes one of two colors — black or white. So there are no negative pixels as one pixel has only two possible values. Hereinafter we will call that array as XBM body array.

Let’s look closer at the ImageMagick code and find out what a “pixel is negative” means at commit details. We need a ReadXBMImage() function. This function reads an image and prepares data for image processing. Seems like variable image contains the image data being processed (Line 225).

Next, at lines 344–348 there is a memory allocation and pointer data now points to the allocated memory start address. Also pointer p points to the same address.

Memory allocation

Next 352–360 and 365–371, same code but for different versions of XBM image. As can be seen from the commit both branches are equally vulnerable, so we will consider just one of them. XBM body array reading occurs in the function XBMInteger() which returns an int to variable c . Further at line 358 the value stored in variable c is put to variable by p pointer, then the pointer is incremented.

Allocated memory filling

In the commit we see that in the previous version variable c was checked for negative value, and if it was negative then the loop ended with a break, and that’s why memory leak appeared. If the first value of XBM body array is negative then all allocated memory remains uninitialized and may contain sensitive data from memory, which will be further processed and a new image will be generated from this data. In patched version it was changed, now if value of XBM body array is negative then ImageMagick throws an error.

Commit details again

Now let’s take a closer look at the XBMInteger() function. It takes a pointer image and pointer hex_digits as arguments. The latter is an array which is initilized at line 305. This function maps allowed values to hex values in XBM body array. XBMInteger() reads next byte defined in XBM body array and puts it to unsigned int variable value. There is an interesting moment, this function reads hex-symbols until the stop token appears. This means that we can specify hex values of arbitrary length and so instead of the expected range between 0–255 values for char we can set any unsigned int value which will be stored in variable value. And next fatal fact is that variable value converted to signed int… Bingo!

Convert unsigned int to int is a bad idea

So we just need to set a value to XBM body array which will be converted to negative int. It is any value above 2,147,483,647 or 0x80000000 in hex. That’s the whole PoC:

#define test_width 500

#define test_height 500

static char test_bits[] = {

0x80000001, };

The amount of leaked memory depends on how you set the height and width parameters. If you set 500x500, therefore, 31250 (500*500/8) bytes will leak! But it depends on how application uses ImageMagick, it may be that it cuts the image to a certain height and width.

While we were testing this PoC, we encountered a problem. Not all the ImageMagick versions below 7.0.8–9 appeared to be vulnerable as described at cvedetails. We found another commit that fixed another vulnerability — CVE-2017–14175 which is a DoS vulnerability for XBM Images processing. And as you can see, it was this particular commit that brought the vulnerability into the code.

Okay let’s try the PoC. Let’s install one of the vulnerable versions (e.g. 6.9.9–51). Now, running convert poc.xbm poc.png we will call processing XBM images in xbm.c file. And therefore call vulnerable code.

The resulting image should be like this:

Image contains leaked memory

You can see some noise on the resulting image, this is a leaked memory, each black or white pixel is a bit of information from leaked memory. If you repeat convert, then you will likely get another image, because another memory chunk will be caught.

What do we need to extract leaked memory bytes?

Simply convert it back, convert poc.png leak.xbm, now we see leaked memory bytes in XBM body array and this is very easy to parse format. Extract it and get leaked memory bytes.

So,

Generate a PoC; Upload it to your avatar on vulnerable application; Save resulting png/jpg/gif image; Extract data from image.

ttffdd wrote a simple easy to use tool for this vulnerability called XBadManners. It generates a PoC and recovers leaked data from image.

Notice! That ImageMagick is a smart library and you can upload a poc.png which contains XBM image data to the server and if the image type is not checked properly, then ImageMagick will process poc.png as an XBM image. So if you just check the filetype of the uploaded file for the “*.png” matches, then this will not save you.