Skip to content

ImageMagick Proof Of Concept – Remote Shell

ImageMagick is a server-side image processing engine which is very widely used. Some functions include compressing/resizing submitted images (profile pictures, for instance) to standardize files in the server’s database. Some of the popular image processing plugins in php, ruby’s rmagick, and others use ImageMagick’s platform.

Before going further, here’s a great article on fixing the vulnerability for those of you who are using ImageMagick somewhere in your environment: https://lcamtuf.blogspot.com/2016/05/clearing-up-some-misconceptions-around.html

The core of the vulnerability is based on a lack of properly filtering contents of files which allow for the possibility of remote code execution. In particular there is a certain default behavior/configuration which says “If I don’t understand ‘file.format’, try to run it as a .svg or .mvg”, those are vector graphic formats which can include calls to remote files. The delegates.xml and policy.xml files determine the order and if those formats will get processed.

There is a vulnerability in the call to a remote file which doesn’t properly end/parse the input. The call, essentially, gets processed by curl/wget and the parsing will let you use a different style of quotation to end the wget/curl request and then input your own commands. For example, an uploaded file may get processed with a command like ‘convert’ (this is built in to Kali by default so you can read the manpages on it there).

convert inputfile.png outputfile.jpg

The above is a sample command which ImageMagick would execute – converting an input file which is in the .png format to a file called outputfile.jpg. The vulnerability here is that you can upload a file called ‘inputfile.png’ but actually have it contain the data of a text file in the mvg format. The sample from the ImageTragick website is a text file which looks like this:

push graphic-context
viewbox 0 0 640 480
fill 'url(https://example.com/image.jpg";|ls "-la)'
pop graphic-context

Again, this can be a file written in notepad and saved as a .txt then renamed to a .png. This works because .mvg files are, essentially, a set of text instructions to create vector art. When the program fails to process the file as a .png it will try one of the formats in the policy.xml file we mentioned earlier. When it hits the .mvg type the above text will get executed. The ‘fill’ command calls the ‘url’ function which, essentially, feeds what is inside the parentheses to ‘curl’. As seen in the example above (this may or may not work depending on what version/implementation of ImageMagick is being used) the destination for the url call is provided (so that the curl command does not fail) and then a ‘;’ is provided after “-ing closed the curl url. The ‘;’ allows additional commands to be processed on the same line in the same way that, from a terminal

cat /etc/passwd
cd /opt/someprogram

can be reduced to a single line:

cat /etc/passwd; cd /opt/someprogram

The representation of ‘url(https://example.com/image.jpg”;|ls “-la)’ can be broken down in to it’s separate pieces:

curl https://example.com/image.jpg
ls -la

In getting my variation of the exploit to work I did not need the ” before the -la but, depending on the backend, there will be slight tweaks needed to properly trigger the exploit. In the example above a single quote is needed to end the ‘fill’ statement and the ” ends the curl command. Anything typed after the .jpg without that ” would be processed as another argument to  the url portion of the curl request. By including the ” it ends the curl “url.destination.goes.here(“) argument but continues the command to be interpreted.

In other words, by calling fill ‘url()’ the convert prepares the following data to be sent to the cli:

curl "

Before the clsoing )’ there is an ‘invisibly’ appended quotation mark ” which is intended to close the curl statement, resulting in the following implied structure:

curl "your.url.here"

By including our own ” inside of the curl statement we effectively close off the data before it as being part of the curl command, and everything after it as being part of the command injection to follow. This will then, of course, have a ” appended to the end of what we type. Which does the following:

'url(https://example.com/image.jpg";| ls -la)'
becomes
curl "https://example.com/image.jpg" ; ls -la"

My proof of concept of this was to write a file which would be processed and start a reverse shell to a remote host, as seen here:

Please feel free to leave any questions, comments, or corrections!

Leave a Reply

Your email address will not be published. Required fields are marked *