Arshan over at Aspect posted something that sounds very familiar indeed over on his blog. Disclaimer: I know this isn’t earth-shattering now when the sandbox isn’t there, but I think it’s cool that using image tags we can create a completely covert channel for bypassing the same origin policy and control browsers remotely. Just to be clear, this is not a traditional same-origin bypass where we’re on http://evil.com/ and we’re talking to http://mybank.com/. We’re talking about a hijacked client who’s in collusion with an evil server that wants to deliver the client some message, be it a code payload, instructions, etc. Can we restrict JavaScript from dynamically loading image tags? No more image pre-loading? I doubt it! Here’s how it works. * Client dynamically creates an Image() and points the source to http://evil.com/evil.cgi?password=somesecret * Server responds with an image that has a 16 pixels tall and 1 pixel wide (16 represents in this phase the total length of the payload) * Client then starts a loop that iterates 16/2 times: o Client dynamically creates a new Image() and points the source to http://evil.com/evil.cgi?password=somesecret&i= o The new image that has height x, width y o Client appends ASCII character value of x onto payload string o Client appends ASCII character value of y onto payload string * Client now has authenticated, 16-length payload to do whatever they want with
Hehe. I was wondering when someone would talk about this! John Terrill and I looked at this back late 2006, early 2007 and took this alittle further than Arshan did. Here is what we came up with: The carry capacity of a side channel is an important factor. Arshan's solution is not very good because of the limited capacity. How can we use dimenstions as a side channel and not have to send tens of kilobytes to transer a few bytes of data in the side channel? Thats the "$1,000,000 and a Monster Truck" question which started John and I researching. Lets take GIF images. According to the spec, length and width are 16 bit integers, giving us 4 bytes of data. However if I need to send 0xFFFFFFFF it would suck to have to transmit an image that is 65535x65535. That would be huge. But GIFs are compressed right? Remember that JavaScript cannot access pixel data of the Image objects it creates, so we really don't care about whats in this picture. What if we make it all white? That should compress well. While it does, you are still sending a massive amount of data to the client just so you can send 4 bytes. PNG does the same thing. Ideally we want something with run length encoding, like PCX (or perhaps BMP) so you would have something like 0:4294836225 as in "white for the next 4294836225 pixels." So far we have been looking at how to try and minimize the size of the graphical data we have to send. What if we don't send any data? Can we use a graphics file whose header specifics a certain length and width without that much graphic data present? Not for all common graphic file formats. Both GIF, PNG, and JPG will fire the onerror event on the image if the length/width does not match the graphical data present. Enter the XBM graphic format. I take extreme joy in finding nasty old crap that really has no business being in a modern browser (HTML+TIME, [sigh] you poor dumb bastards). And you really can't get much older than XBM support. They have been supported pretty much since day one. An XBM is a text file and not a binary file, which has the cool side affect of being the only way JavaScript could dynamically generate images on the client before things like CANVAS, VML, or the data: URI. Yes friends, JavaScript can do Wolfenstein!. Anyway, IE dropped support for XBM with XP SP2 (which I have to give props to Microsoft for doing). I mean, using #defines to tell the browser how much memory to allocate and giving it a character array? What the worse that could happen?. Well it turns out Mozilla does not care if the dimensions in the #define don't match the image data. For those that want to play along at home, point Firefox at this. It seems you can specify a width or height of somewhere between 2^12 and 2^13 without actually needing graphic data there. The browser will gladly fire the onload function for the image and you can access the dimensions. This means you can send a XBM "image" to the client that is ~54 bytes, of which 3 bytes can be arbitrarily set and read by JavaScript. Hello there side channel. You are so cute. Yes you are! You are so so cute with your 5%+ capacity! shmooch shmooch shmooch! I cleaned up the code John and I wrote today and put together a POC. This screen shot help see what is happening in the background. And, keeping with my well earned reputation of being an vile person who arms script kiddies (I also eat childern, BTW), I will share the POC: Download XBM side channel POC. Unfortunately I didn't post an MD5 of the idea showing when John and I worked on it, but this post was written because our code stopped working and I had to figure out why. Not to plant a flag, but we *were* thinking about this a while ago. Anyway, why did John and I abandon this research? Because its (currently) pointless. I can't read content from arbitrary domains. I can only read content from domains that have an XBM serializer thingy on them. Which most likely means I control them. And if thats true, why use an image side channel? I can just use XSS-Proxy or BeeF or whatever awesomeness spewed from PDP's keyboard on any given week. Unless remoting scripting is not an option. Unless someone decides to create some kind of policy to restrict what resources can be referenced by a web page. You know, part of some larger plan to allow for for things like cross domain XHR, etc. Now who is working on stuff like that? Using Image Dimensions as a side channel |