Fortify’s Announcement About Jeremiah’s Attack, Decoded

Thomas Ptacek | April 2nd, 2007 | Filed Under: New Findings, Uncategorized

Thing 1.

Javascript is a dynamic language. You can redefine or override core features of the language or the API. When your browser evaluates a Javascript program, that program can set up functions to get called when all sorts of things happen, such as when object attributes are changed or accessed or arrays are modified.

Thing 2.

Many (perhaps most) modern web apps are vulnerable to XSRF: they have HTTP GET or POST URLs which, if you can trick a victim into following a link (or loading an image, or following a SCRIPT tag), will “do things” inside of the application: delete your mail, change your Google language, Digg a story, etc.

We’re all working on smoking these URLs out because it is very easy to trick browsers into hitting them, even if they’re POST-only. We’re nowhere close to done.

Thing 3.

AJAX applications often hook your browser and the application server up using JSON, which is simply Javascript describing arrays and tables. The important detail here: the data itself is described directly in Javascript, not as a data format that the AJAX code in the browser parses.

Thing 1 and Thing 2 and Thing 3.

You get a victim to visit a web page you control. It contains Javascript code that redefines methods on Object, or arrays, or callback functions, or whatever.

It also contains, say, a SCRIPT tag aimed at an XSRF-able URL in your target application (say, your banking site).

The result of the XSRF-able URL is a JSON “document” (really, “script”). It’s got sensitive stuff in it (say, your account numbers or balances or whatever).

You can’t directly read this document. But the browser executes it, because that’s how you “parse” JSON documents: you eval them as a script and take the results, neatly packaged as Javascript objects.

But you don’t have to read the document directly. You redefined key Javascript functions before loading the script, setting up code that gets called as the JSON script is evaluated. The Javascript engine feeds you the data from the document as it’s loaded.

You win.

The Moral Of This Story

Cross-Site Request Forgery (XSRF) is bad.

You can monkeywrench this particular instance of XSRF by booby-trapping your JSON documents. Just make sure they won’t evaluate properly without some pre-processing step. For instance, your bank can stick an infinite loop at the top of the JSON doc. Your bank’s own legitimate AJAX Javascript code can strip it out. Your oblivious attacker’s Javascript can’t.

You can make sure sensitive JSON data only goes out via POST. The SCRIPT tag uses GET.

You can fix XSRF vulnerabilities: validate incoming requests with a nonce value, which ensures that requests for data are tied to actual legitimate application code.

You can stop using JSON. You’re unlikely to do so; JSON is extremely convenient (rich data types, no parsing). But if you had used XML, there might not have been a trivial way to snoop the documents.

5 Comments so far

  • Jeremiah Blatz

    April 2nd, 2007 3:03 pm

    Speaking of code injection, I learned today that one of the encoding types that flickr supports is php. As in, they give you a block of PHP code to execute and Good Things Happen(tm). JSON is bad enough, having a 3rd party (over plaintext http or non-certificate-verifying https, no less) hand you code to execute is madness.

    Really, parsing isn’t that hard.

  • Matt

    April 2nd, 2007 4:33 pm

    Dynamic languages are awesome. They’re also freakin’ scary for us security folks — I remember reading about Obj-C method swizzling for the first time, and thinking “Oh dear god…”.

    Maybe there’s a middle ground in language design, somewhere with (most of) the benefits of dynamism, but without fear-inducing “features” like being able to redefine the guts of the runtime. Not that I’ve given this idea any deep thought, though; am I completely out in left field with that suggestion? Or, better yet, has somebody already designed a language like that?

  • Thomas Ptacek

    April 2nd, 2007 5:02 pm

    Think of all the code written in C and PHP, and ask yourself whether people are going to pick a language because it is more or less secure.

    The problem with Javascript isn’t the language. It’s the setting. The idea of executing code controlled by hostile content in any programming environment is sort of insane.

  • Phil Groce

    April 2nd, 2007 5:12 pm

    As I understand what you’re saying, the vuln isn’t JSON’s fault, per se. If you’re hooking into an AJAX app that uses XML to move data around, you can still proxy the XMLHTTPRequest and get that nice, sensitive data from a DOM tree.

    That doesn’t make the rest of what you say any less true, but it sounds like you’re accusing JSON of being inherently insecure, when the problem is Javascript and how it’s deployed in the browser. It’s a very trusting (and trusted) language in a hostile environment.

    As an aside, I hope web developers are at least being told never to just eval JSON data. Just because you can doesn’t mean you should.

  • Thomas Ptacek

    April 2nd, 2007 5:25 pm

    It’s definitely NOT JSON’s fault. I personally don’t even think it has anything to do with AJAX.

    What’s happening here is this:

    There was a belief that XSRF attacks — follow a link and, without requiring confirmation, cause an action in a target application — only allowed you to “create”, “update”, or “delete”, but not “read”.

    It turns out there’s at least one major scenario in which that isn’t true: when the data you want to read is embedded in Javascript, you can hijack prototypes to get at it.

    However, if we never find a way to do something similar with XML, I’ll be surprised.

    XSRF-able UI actions shouldn’t provide sensitive data. If you audit your application for XSRF flaws, you’ve defeated this attack. Moreover, the well-known preexisting exploits for XSRF are actually worse than this attack. I think it’s much ado over not much, though I think Jeremiah’s attack is very clever.

  • Leave a reply