This is a personal blog. My other stuff: book | home page | Twitter | G+ | CNC robotics | electronics

March 06, 2011

The other reason to beware ExternalInterface.call()

Adobe Flash has a function called ExternalInterface.call(...), which implements a JavaScript bridge to the hosting page. It takes two parameters: the first one is the name of the JavaScript function to call. The second one is a string to pass to this function.

It is understood that the first parameter should not be attacker-controlled (of course, mistakes happen :-). It is also understood that there is no inherent harm in putting user input in the second parameter, if the callback function itself is not behaving stupidly; in fact, Adobe documentation gives an example that follows this very pattern:

  ...
  ExternalInterface.call("sendToJavaScript", input.text);
  ...

Such a call would be translated to an eval(...) statement injected on the embedding page. This statement looks roughly the following way:

  try {
    __flash__toXML(sendToJavaScript, "value of input.text"));
  } catch (e) {
    "<undefined/>";
  }

When writing the supporting code behind this call, the authors remembered to use backslash escaping when outputting the second parameter: hello"world becomes hello\"world. Unfortunately, they overlooked the need to escape any stray backslash characters, too.

So, try to figure out what happens if the value of input.text is set to the following string:

  Hello world!\"+alert(1)); } catch(e) {} //

I reported this problem to Adobe in March 2010. In March 2011, after following up, I received the following response:

"We have not made any change to this behavior for backwards compatibility reasons."

Caveat emptor :-)

8 comments:

  1. I really thought they fixed this.. :'(

    I wonder.. how many security patches go out every Flash update? I just have the feeling that the Flash bugs list keeps on growing and growing.. and the updates keep coming, but the bugs list is just longer and longer.

    If this continues like this, Flash will end up in the same state Java is today, and that makes me sad, specially because youtube html5 player kinda sucks.. =/

    Related: http://goo.gl/WfsZJ

    ReplyDelete
  2. whats __flashToXML__ ? Is it window.call ?

    ReplyDelete
  3. It's just some sort of a wrapper that just calls the provided function, and then then turns the returned object into an XML string (so that Flash can parse it internally without getting too intimate with JavaScript).

    ReplyDelete
  4. Interesting that on Monday Microsoft published a post on the MMPC blog about a piece of SWF malware that abuses exactly this function.

    http://bit.ly/fScnQZ

    ReplyDelete
  5. Well, it's a coincidence. It happens ;-)

    ReplyDelete
  6. Just got bitten by this bug. It's absolutely ridiculous that Adobe won't fix it. I don't see how doing so could break backwards compatibility unless there are actually Flash applications that depend on being able to execute JavaScript this way -- and if that's the issue, Adobe needs to deprecate ExternalInterface.call and provide a new method that isn't insecure.

    ReplyDelete
  7. The most reliable workaround I've used, which isn't too computationally intense, is to base-64 encode all data crossing the bridge. Whatever string gets passed to ExternalInterface.call is base-64 encoded in Flash first, then decoded on the JavaScript side to a normal string, and vice versa. This ensures that only base-64 characters traverse the bridge and avoids any potential mangling of character data due to inconsistent escaping. I actually use the bridge to access a WebSocket in the JavaScript, so all the incoming data is base-64 encoded before being forwarded to Flash. It works fine. As for the backward compatibility excuse, they should have fixed this issue, because it's incorrectly functioning. If people worked around it, too bad, fix it, let their stuff break, and let them fix it. It should have been fixed immediately... all they did was give more people problems by leaving it broken for what... old broken software that's probably no longer in use anyway, at the expense of leaving new software broken? Terrible.

    ReplyDelete
  8. I've just rediscovered this bug and wrote a small PoC code that is exactly the same as yours! The only problem is that I'm 3 years late with this :)

    If Adobe would fix it, they would break backward compatibility, because one of the workarounds (escaping the backslashes yourself) would break. And this is a workaround that is in use in many places, including the youtube player.

    ReplyDelete