A real case study of XSS through EXIF headers

Recently I found and reported a cross site scripting vulnerability to Tencent, which was a real case of XSS attack in EXIF headers.

The vulerability was found in an image cache service for optimizing image size in mobile devices:

http://read.html5.qq.com/image?imageUrl=http://XXX

It grabs image content from untrusted sources (the imageUrl param), reduces their size and then sends it to user. At first I was trying to make a SSRF attack, but when casually inputted a svg url I got the following funny result:

svg-content-type-spoofing

The vector image has been rendered as bitmap and compressed to jpeg, but my browser still parsed it as XML and raised the error. Soon I realized that there must be some misconfiguration so it sends wrong Content-Type header. Looks like it was directly taken from original url, so we can simply spoof it to cheat the browser.

But how can we insert our attack vectors? Since it returns the wrong Content-Type, any valid HTML code in response body will be parsed and renderered. According to binary comparation, images are always encoded so it’s impossible to directly append ascii chars to the image. Does EXIF work? Let’s have a try.

exif-xss

I put some evil html in the image through EXIFTool:

exiftool ‘-Make=<script>alert(/xss/)</script>’ test.jpg

Then renamed its extention to .html (for Content-Type), uploaded to my server and here we got a popup!

qq-xss-alert

(Vulnerability now patched, so nothing would happen :) )

Additionally there’s a HAProxy for load balance, the vulerability is not always triggered. I guess there must be some nodes misconfigurated while others are not. It still has a great chance of success.

correct-mime

Since scripts under this domain have access to sensitive cookies that can control victim’s Tencent account, this vulnerability is considered harmful.

To fix the bug, simply wipe out the EXIF headers should be the easist and most effecient solution. Responding with the correct Content-Type is also a key point. Besides, I think cache services like this should better be served in separated domain to keep harmful content away from user credits.

The vulnervility was reported on 2015–01–11 and got fixed at 2015–01–22 16:00:20.

One clap, two clap, three clap, forty?

By clapping more or less, you can signal to us which stories really stand out.