Security: GMail vulnerability: Arbitrary script execution with SVG

Note: this vulnerability has long been fixed. I was just waiting for the confirmation from Google.

I could now tell a story of magic and wonder, how I spent day and night analyzing GMail and finally after weeks of hard work found this vulnerability. But the truth is that I was simply using GMail as I usually do when I came across this vulnerability.

GMail has had the “View Image” functionality for a while and I’ve often lamented that it doesn’t extend to SVG documents, which are eventually viewed through Firefox anyway. So when I finally noticed the “View Image” link next to an SVG that I had sent to my address for quick access on another computer, I happily clicked on it and was more than a little surprised when it opened on the mail.google.com domain.

You see, hosting any kind of unknown document on your own domain is extremely risky. Even a seemingly harmless PNG or JPEG can be a threat unless you really verify that it is what it claims to be and/or serve it from an unpredictable location. If it’s not and you didn’t notice, then all it takes is a browser trying to act smart and ignoring the MIME type for an attacker to take complete control of the user’s account. SVG is especially dangerous since, just like HTML, it can contain or link in script code. So, seeing the SVG open on mail.google.com was worrying.

On the other hand, GMail also displays HTML on mail.google.com by preprocessing it and removing anything that is not text or formatting-related (which is also an extremely dangerous task since every new release of a web browser includes new ways to load remote data, but apparently Google feels that it’s worth the risk: even allowing the loading of CSS can cause code execution), so there was some hope.

The problem is that in difference to HTML it is nearly impossible to preserve the majority of information in an SVG document if you strip it of tags that can be used to include data, since a lot of SVG’s core functionality relies on linking in fragments that can either be part of the local or any other document.

I started throwing some slightly obfuscated SVGs at it and was surprised to find that it didn’t filter any code at all, no matter how it was included. Using this knowledge and another attack vector (that I’m not going to describe yet since it’s still being worked on) I was able to deliver a harmful mail and open it by leading the user onto a specifically created webpage. With a bit of other black magic I was able to read the address book and all mails from there and have them delivered to my doorstep.

There’s not much more to this story. I reported it, the “View Image” link got disabled for SVG documents and we’re safe once again. But how can such a big issue ever slip through the cracks of Google’s testing and could this happen elsewhere? Well, I can only guess, but this is what it looks like from my perspective:

When you create any kind of software that may be an attack target, you define how potentially dangerous each component is. This may happen informally by people simply watching changes in certain files more closely or through a dedicated process that requires additional reviews for files marked “critical”, but it always happens.

So, how would you rate a file containing a list of image file formats, especially when there are only non-interactive formats like GIF, JPEG or PNG around (as was the case when GMail was initially created)? You’d probably mark it as “safe” and allow patches with minimal or no reviewing. Now, someone learns about this new “image format” SVG, not realizing that it is in fact a document format and adds it to the list of image files and voilà, you’ve got a class A untrusted code execution vulnerability.

What can we learn from this?

  1. Anything that ends up serving untrusted content from your servers really is security relevant
  2. Any assumption on the danger of a particular action should be rechecked regularly, to see if it still applies
  3. A little knowledge is a dangerous thing when it comes to file formats
  4. When in doubt, serve untrusted content from a separate domain.

Thanks to Adam from the Google Security Team for the good cooperation and being an all-around nice guy 🙂

Javascript Object Notation is a strange beast

I’m never quite sure whether the Javascript Object Notation is a blessing or a curse. Of course, it does allow for quick creation of lists, but the way it is implemented I always find myself adding a few extra brackets just to make sure it is really treated as an object definition, not a code block.

Take his for example:

{title:'Hello World'}['title'];

Looks an awful lot like an object definition with an immediate access to the title property, doesn’t it? Well try to run it.

Huh? “title”? The problem is that this statement is ambiguous: It could either mean “Create object title set to Hello World” or “Code block with label title and string Hello World”. The meaning of [‘title’] then would mean “Access title property” for the first interpretation and “Create new Array with string title”. In this case, the second meaning is chosen and [‘title’] turns into the string “title” during output.

Now, this doesn’t happen nearly as often outside javascript: urls since the code grammar usually dictates how to interpret the block, but it still occasionally pops up.

What do we learn from this? Don’t forget to quote the identifiers, don’t hold back on brackets and don’t forget the semicolon:

({'title':'Hello World'})['title'];

Flash 3D – a welcome fallback

Apparently Adobe is getting more and more comfortable with being a fallback for modern standards in out-of-date browsers. After adding VP8 to the list of supported codecs, they are apparently now working on 3D support. While we can be reasonably certain that Adobe wants to sell their approach to 3D as “unique” and will offer a proprietary 3D scene DOM to prove it, I would be very surprised if they blocked low-level access to that DOM entirely, since that would make WebGL more powerful and that’s a headline they definitely don’t want to see.

And where there’s low level-access there’s always a way to use it to emulate another API. So maybe in a not too far-away future we’ll see WebGL, SVG, WOFF, Canvas emulated via Flash in legacy browsers, so we can stop focusing on fallbacks and just let the dominant plugin (Flash) deal with the dominant legacy platform (InternetExplorer) while we are finally free to focus on content.

Update on the simplistic 3D renderer for Canvas 2D: TinyDim

Demo

You control the demo mainly by left/right dragging the mouse, but some basic, unoptimized support for keyboard navigation is in there as well (Arrow Key/PgUp/PgDn). If you click on a face it will light up briefly and you can now enter a new color in the fields below the canvas.

A guy named Luke recently posted a comment on a three year old post that I honestly had mostly forgotten about: “Canvas 3D Renderer updated“. It was about one of the first Javascript programs capable of rendering a file exported from a 3D program without a plugin.

There are by now several such engines using Canvas 2D, a good deal of them more advanced, faster and better supported. However: TinyDim, which was the name I used when I compiled that sample into a sort of generic Javascript library has its advantages in being small, simple, easy to understand and therefore easy to hack and extend.

So this is a sort of update what has happened since then: I’ve actually used TinyDim sometimes and it has received some level of basic optimization at the code level (it’s still missing any structural optimizations like caching or viz-areas), but I never got around to post about it. It now has support for one global light and has its own mouse navigation class for when you just want to view a static 3D model. Support for colored faces is still only hacked in with a proprietary format (although that would be easy to change, you just have to write a MAT file parser) and It can return the face you’ve clicked on.

So, if you want to hack in texture support using this technique or anything else, be my guest 🙂

Dock-style zooming icon bar in pure HTML+CSS

Update: The initial post mentioned transforms, which were used in the initial version, but later replaced by simple absolute positioning.

Demo

An OSX-style icon bar in pure CSS, without any Javascript. Not much to say except: Enjoy 🙂

This sample uses CSS transitions, meaning that it requires a Firefox 4 preview build.

Webkit manages to do … something (Webkit tries to do some transitions in sequence instead of simultanously). Opera apparently has no support for pointer-events in HTML yet.

Try to disable the stylesheet (View/Page Style/No Style in Firefox): The document remains usable. Ugly, but usable.

Fixing HTML5 YouTube’s fullscreen playback with AdBlock+

I haven’t used AdBlock+ for quite a while… ever since I entered the realm of Flash-less web browsing thanks to Adobe’s inability to produce a 64 bit Windows version of the Flash plugin. However when Beta 1 of Firefox 4 was released I had to answer the question “Does AdBlock+ work?” quite often (the nightly does), so I more or less had to install it.

I used the opportunity to get rid of the biggest annoyance of YouTube’s HTML5 player: the broken full screen mode. YouTube overlays the video with a transparent div in order to block users from right-clicking on a video, since this offers the option to save the video (YouTube’s videos may be free, but they are still copyrighted and you don’t automatically get the right to distribute them).

Getting rid of this overlay with AdBlock+ is easy since it has a unique class attribute: “video-blocker”. Just Go to AdBlock+ preferences window (Tools -> Adblock Plus Preferences…), click “Add filter…” in the lower right and enter the selector “youtube.com##.video-blocker” (without quotes). This hides the overlay and you’re now free to right click on any YouTube HTML5 video to access the fullscreen option.

Here’s a link to the Coraline trailer: Try it. Link.

Using the real full screen mode instead of YouTube’s normal pseudo full-screen mode also means that Firefox can now use hardware acceleration (via OpenGL and Direct3D), even if you don’t have Direct2D enabled. Even my old laptop can play HD WebM video this way.

Texturing with Transform, without WebGL or Canvas

Update: I’ve checked it in Firefox 3.6.6 and to my surprise it works perfectly.

Demo

With the maturing of Direct2D support in Firefox I feel that it’s time to revisit transformations. Transformations let you rotate, skew and so on arbitrary elements on a page. They are relatively slow to do in software but really fast in hardware.

After a long discussion that I had recently, I should point out that this is a DEMO, meaning that it’s supposed to show what you CAN do with HTML+Transformations, rather than what you SHOULD do. A demo is not useful on it’s own, it’s just meant to illustrate a concept.

In this case, it shows a very simple approach to doing free-form deformation of bitmaps. I tried it in pure HTML+JS+CSS here, but the concept and quickly and easily be applied to other drawing systems like Canvas2D, where it could be used to provide a fallback for WebGL.

Aaah, the web in its purest form

I don’t know about you, but right now, I’m having a blast using the web. Even more than I used to have. The reason:

Mozilla has started releasing x64 builds of Firefox. And I’m having a lot of fun using it, but probably not for the reasons you’d imagine.

First off, the x64 builds are not really any faster yet than the standard x32 builds, due to some optimizations not working on x64 yet. And even then, the speed difference would probably be negligible. X64 is no magic bullet that suddenly makes an application twice as fast.

So why am I having so much fun? Because my plugin list is EMPTY. ZIP. NADA. For the last two months or so I’ve been surfing on pure Firefox goodness. There simply are no plugins for Firefox x64 builds available yet. I’ve been using Flashblock before, but even with Flashblock, the Flash plugin still gets loaded… it’s just removed immediately afterwards.

Now, I like watching a YouTube video every once in a while as much as the next guy and I’m glad that I still have x32 builds available for when YouTube has no WebM available (hint: create a link to your x32 firefox.exe and an empty directory somewhere on your HDD, then modify the link to read “firefox.exe -no-remote -profile c:\my\directory”, so you can start it without having to close your normal Firefox first) , but separating video browsing from my main browsing experience has increased the quality of my browsing experience tremendously, to the point where it outweighs the inconvenience of launching another Firefox instance by a wide margin.

(Yes, I could have disabled Flash before, but just like the rest of the world I never imagined that it would have such an impact on my browsing experience).

You can find current Firefox x64 trunk builds at ftp://ftp.mozilla.org/pub/mozilla.org/firefox/nightly/latest-mozilla-central/ , labeled win64-x86_64

SVG Animation Stick Demo

Not much to say about it other than I needed a quick, simple and working little thing to demonstrate SVG animations … I made a simple little stick man that leverages SVG’s tree structure to create a simplistic bone model and animated it so that it worked in Firefox (which means leaving out anything fancy like animations with more than just a start and an end value).

It’s not much, but I thought I’d post it in case somebody else wants to illustrate the same thing:

http://tapper-ware.net/data/devel/web/apps/SMIL.Stickman/index.svg

A shorter way to do Math.floor – A little known trick

Nothing groundbreaking, but someone just handed me code that was filled with Math.floor calls. While this doesn’t automatically slow down your code the way it used to, thanks to better Javascript engines, it’s still ugly as hell to look at.

Now, those people who like to put wavy brackets on individual lines will probably start shouting again, but once you’ve gotten used to it, this is actually a good deal more readable, since it shortens the code considerably, while still having a “unique look” that you’ll be able to identify quickly

Instead of
Math.floor(foo)

You can simply do a bitwise OR with 0:
0|(foo)

The reason this works is that any bit operation causes the number to be converted to a signed 32 bit integer. While this isn’t strictly the same as what Math.floor does, it will give you the same result at least for positive 31 bit integers. For negative ones you get something a little different (but typically far more useful), namely the integer part (-3 for -3.7) instead of the the highest integer smaller or equal to the given number (-4 for -3.7).