JSON + eval(): Owning the Dashboard
Twitter has been all the rage for a while; I'll admit that I've been a late adopter (I've had an account since yesterday). It seems useful as a quick news agregator (with feeds like the NY Times and Heise) -- in particular when coupled to a dashboard widget on the Mac.
There are two dashboard widgets that let you both post and follow: Twitterlex and Twitgit. In plain English, both of these are huge security risks that create an easy way for an attacker on your network to take over your Mac. Uninstall them till there are new versions.
In technical terms, both are relatively simple pieces of JavaScript. Both use JSON to retrieve their data through the Twitter API. Both use eval()
to evaluate the JSON data.
And that's a pretty big deal: JSON is short for JavaScript Object Notation. That means that data are encoded in a subset of the JavaScript programming language, the same language that these two widgets are written in. eval()
, then, is the simplest way to parse that information: Instead of doing anything fancy, the data are fed to the JavaScript interpreter. Which will do its thing, and duly interpret whatever it is given.
And, for these Widgets, there is no sandbox to the rescue: While bad (and unsafe) JavaScript is a matter that affects just the perpetrator when it happens on an ordinary Web page, the sandbox for Dashboad widgets is actually configurable, Needless to say, both widgets are using that configurability: They both have the AllowSystem
option set, to enable the widget.system()
function. That method is used to execute arbitrary command line utilities, i.e., it grants as full control over the system as the user has -- and that often includes control over the /Applications
folder.
Twitterlex, incidentally, at least has a reason to open the sandbox, using Growl for notifications. Quickly looking through Twidgit, I couldn't find any there, except that there was probably an example somewhere with the same code in it. Twitterlex makes up for this slight advantage by having an update notification mechanism that calls eval()
on data retrieved from some URI on the programmer's Web server. What's currently returned from there looks benign; still, this would make for a marvelous backdoor.
How realistic are attacks against this kind of code? Very much so. Both widgets check Twitter regularly. Risks -- leaving malice on the side of one of the "legitimate" data providers aside for a moment -- include a subverted Twitter server (cross-site scripting will be enough, even though Twitter fortunately appears to be quite paranoid about that), a subverted server on the author's side in the case of Twitterlex, and a man-in-the-middle attack against the data retrieval. The latter is quite easy to launch, as no cryptographic protection is used at all: Either ettercap or a subverted captive portal will do nicely.
All this illustrates some security fundamentals: When there are easy, but insecure, options, people will exercise them. If they can use eval()
instead of JSON.parse()
, they will do that. If they can break out of a sandbox, they"ll do that. In particular if that doesn't keep the widgets from being installed. And if these two things can be done in one widget to make life more interesting, then that will happen, too.
Finally, if the same programming platform can be used locally that is known from the Web, then we'll see the same programming style (and mistakes), and we'll see local and Web vulnerabilities blur into each other.