The Lair

Do not meddle in the affairs of dragons, for you are crunchy and taste good with ketchup

slippery when wet - Greasemonkey security

From the introductory blurb, Greasemonkey is a Firefox extension which lets a user add bits of DHTML to a page. I’ve waxed lyrical about Greasemonkey before, so I’m not going to go into how big a fan I am of this extension. I use it for a number of sites and it’s made my web experience far better; to say the very least. It sounds pretty innocuous to say that Greasemonkey injects pieces of DHTML into pages. Accurate, but also misleading in a sense that it gives no hint of the awesome power of this extension. When I first heard of Greasemonkey, the only thing I could think of was it’s utility for blocking advertising on select specific pages. Only, adblock fills that niche perfectly. I have Adblock, so I didn’t need Greasemonkey. Or so I thought. Fortunately, I was pushed into revisiting Greasemonkey by a friend and I discovered the script archive. And perhaps inevitably, I went from being a Greasemonkey skeptic to fanatic. In the matter of a few hours.

But the problem is, there was one piece of functionality in Greasemonkey scripts that I never liked or trusted. Perhaps typically, this function is also one of the most useful. I speak of GM_XMLHttpRequest. Read the API reference carefully. This function allows any webpage to be requested from within a Greasemonkey script. Remember, Greasemonkey scripts run on the client, on one’s own machine. GM_XMLHttpRequest allows wonderful things like Rojolicious and DeviantPlus. It also allows a script writer to remotely log any and all sites visited and operations performed while that Greasemonkey script is active. One simple GET or POST to a remote site is all it takes. Writing a malicious spyware like script was never easier.

To be perfectly honest, this dubious capability already exists in HTML 4 aware browsers (which basically means all modern browsers). An iframe is perfectly capable of performing the same remote requesting task, given a bit of clever Javascript embedded into it. This is a technique that many sites already use. But the capability to author custom user scripts (basically, what Greasemonkey facilitates) has also existed in browsers for years. The breakthrough by the Greasemonkey devs was as much to do with packaging, presentation and ease of use as it was with technical aspects. And given how popular Greasemonkey already is; and how other browsers are scrambling to catch up (Opera introduced user Javascript in version 8.0, and Internet Explorer 6 has Turnabout), user side Javascripting can only grow.

And now, we have our first potential security issue. Install a user script without auditing the code. Miss out on the part where it makes a sneaky GM_XMLHttpRequest call to a remote site. Someone just 0wned joo. Possible ? Sure. To my eternal shame, I admit that I only read through all the GM scripts on my machine last week. As far as I can tell, they were all above board. When they made a remote request, it was for a legitimate reason. As Greasemonkey scripts proliferate, will this continue to be the case ? Have you read and understood every GM script running on your machine ? As I said, I didn’t till a few days ago.

However bad it may be, this is a known feature. A dangerous one, but still a known feature. Unfortunately, there are still a few more exploits that are possible with the current version of Greasemonkey (As of writing, 0.3.3) which weren’t exactly planned features. Updated: It appears that GM_XMLHttpRequest is vulnerable in the current release of Greasemonkey. It can be used to request any file on your local hard disk. It can also request directory listings.

Do you have passwords or usernames embedded in your Greasemonkey scripts ? Don’t do that. A remote attacker could, potentially, grab all the scripts installed on your own machine. At the very least, the remote attacker would know which scripts you have running on your machine. Not a big deal. Embed usernames and/or passwords in your Greasemonkey scripts for ease of use, however, and it could be a problem.

It also appears (from the same source) that any value set with GM_setValue can be grabbed by a remote attacker. Again, not a big deal if all your user scripts only cache configuration data. A big problem if any scripts you use currently cache a username/password (or any other sensitive information).

So, what steps can we take to make sure that Greasemonkey exploits don’t start popping up in the wild ? (Sample exploit code already exists).

  1. Audit each and every script that you install carefully to make sure the code is understood. This seems like a no-brainer, but it’s not the easiest thing to do. GM_XMLHttpRequest calls are an obvious target, but perhaps not the only thing to look for.
  2. Make sure that no user scripts in your scripts directory embed usernames, passwords or other sensitive information. In fact, if it’s a Greasemonkey script to a location that you value (for instance, a GM script for your online banking site), I’d suggest removing it altogether. If the UI does not allow you to do this, for some reason, then find your Firefox profile directory, go to extensions, find an extension with the directory name {e4a8a97b-f2ed-450b-b12d-ee082ba24781}. This is your Greasemonkey extension directory.

    e.g:
    My Firefox profile is in C:\Documents and Settings\local\Application Data\Firefox\Profiles\myprofile. (It’s a WinXP machine, my user name on this machine is local and the profile directory is named myprofile).

    The full path to the Greasemonkey scripts directory is:
    C:\Documents and Settings\local\Application Data\Firefox\Profiles\myprofile\extensions\{e4a8a97b-f2ed-450b-b12d-ee082ba24781}\chrome\greasemonkey\content\scripts.
    Find the script which embeds sensitive data and remove it from this directory. Additionally, you can also edit the config.xml file in the same scripts directory and remove the reference to the file.

  3. Inspect the cached values set by Greasemonkey scripts. How ? Open a new tab in Firefox. Type in about:config. Filter the list of keys by the following : greasemonkey.scriptvals. If any of the values seen contain data you consider sensitive, reset the value (right-click->reset) and disable/remove the responsible script.
  4. Be extra careful when running any user script with @include=*. ie: A script which will execute on any visited website. As far as I know, at least some exploits are only possible if a Greasemonkey script executes on that page. Make sure your scripts are confined to specific trusted domains.

All set ? This should, hopefully, make your Greasemonkey experience safer. I need to stress that I don’t know of any exploit code in the wild. Greasemonkey users are a subset of Firefox users (for obvious reasons, duh) and Firefox users are still the minority in the browser stakes. It would require a fairly desperate cracker to make the effort to target such a niche set of users (IMHO, of course). However, it didn’t take that long before various sites started offering to install dubious extensions on my Firefox. When various sites try to exploit Greasemonkey in a similar fashion, I’ll at least be aware of the risks. Forewarned, as someone said a while ago, is forearmed.

Update: It seems that XMLHttpRequest is also vulnerable to leaks and can be used to request any readable file on your hard disk. Ouch. I’ve made revisions to the post above accordingly. Official dev blog is here and the current security update is here

“slippery when wet - Greasemonkey security” has one comments

  1. Gravatar

    cori schlegel wrote:

    Excellent points about the risks of Greasemonkey in general. It’s similar to running your Windows machine as an admin all the time, or logging into *nix as root. Security should be a top concern for GM users and script authors, and running a GM script that written by someone you have no reason to trust is risky.

    Rojolicious (and thanks for the link) actually does maintain a user’s username, but does not capture a password, and del.icio.us usernames are such open secrets that I decided it was a worthwhile risk to take. Take that for what’s it’s worth….

    cori

Just say it

*Required
*Required (This site supports gravatars)