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:
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:
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.
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!
(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.
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.