4

I'm developing a scripting extension, similar to Greasemonkey or Chrome's content-script engine. This extension will allow script writers to do very dangerous things like access local files.

If I ever release this extension to the public, I would like it to be able to warn novice users if a script will use a "dangerous" function. I'd like this warning to be as hard to circumvent as possible.

For example, the extension can search for the protected string GM_openSQL_Connection and warn the user -- maybe like this:
Bad script warning

Assume that the base web page will never be able to access GM_openSQL_Connection thanks to sandboxing mechanisms. Likewise, no <script> node will be able to.

But, the script writer could still circumvent the simple search, from above, with something like:

eval (decodeURI ("GM_op%65nSQL_Connection (...);") )


So the question is what are the kinds of ways in which an evil scripter can fool the check for restricted function usage, and how might I prevent such mischief?


Note: false warnings can be okay. For example if the script author uses the text "GM_openSQL_Connection" in an otherwise static string, then he will just have to put up with the (false) warning.

Brock Adams
  • 90,639
  • 22
  • 233
  • 295
  • 2
    Completely unrelated, but I like your example warning. :) – seeming.amusing Mar 06 '12 at 07:26
  • You cannot say it danger only cause function's name. It is only possible for action, not for names blacklisting. Functions which uses direct access to the cookies and remote accessing to 3-rd party hosts are most commonly recognized as dangerous (does not mean they are, but this is could be a warning they are). Some other patterns could be also interpreted as non-welcome. – YuS Mar 06 '12 at 07:37
  • I would suggest using the same approach as [JavaScript Deobfuscator](https://addons.mozilla.org/addon/javascript-deobfuscator/) (use the debugging interface to get all function calls, no matter how they are compiled) but that won't help. Consider `var foo = window["GM_op" + "enSQL_Connection"];foo(...)`. You cannot go by function name because the function name can change too easily. – Wladimir Palant Mar 06 '12 at 07:42
  • @Yuri, I can and will say that these functions are dangerous. And, they are; there's a reason that they are forbidden to ordinary javascript in all browsers and most extensions. ... The user is expected to know (and the warning might state) that just because it is dangerous does not mean it is necessarily being used for evil. (Otherwise, why would I create the function in the first place?) – Brock Adams Mar 06 '12 at 07:47
  • @WladimirPalant, this is an extension/add-on environment, not browser-page javascript/DOM. I don't see how the script writer could rename my functions but I'm not an expert extension writer. "Compile time" or "install time" checks I will use, but they don't guard against run-time ` exploits like `eval`. – Brock Adams Mar 06 '12 at 07:52
  • @BrockAdams: I don't see how the environment matters here. The script writer can still call any function indirectly, by assigning it to a local variable and without "mentioning" its name in the clear. Maybe there isn't a `window` variable but then `this` can be used instead. Frankly, I think that the only proper way to control the use of "dangerous" APIs is not exposing these APIs in the first place - maybe expose placeholders instead that will display a warning. – Wladimir Palant Mar 06 '12 at 08:08

2 Answers2

4

What are the ways in which an evil scripter can fool the check for restricted function us[age]?

There are thousands of combinations, for example, with eval(), new Function(), combinations of String.fromCharCode() and decodeURI() (like in your example).

How might I prevent such mischief?

Could you overload/shadow specific bad functions/objects/variables?

GM_openSQL_Connection = function() {
   warnUser();
};

To set a flag if the extension attempts to access a forbidden function or variable, simply have a var isDangerous = false which is set to true if a forbidden function is called or the get/set on a forbidden property is accessed/modified.

If the isDangerous is true, then you can mark that extension as potentially having dangerous function/property calls/accesses.

alex
  • 479,566
  • 201
  • 878
  • 984
  • Hmm. That shadowing has potential. I could require developers to self-report what dangerous functions they use in the code. The user would get install-time warnings as indicated and the run-time warnings would be deactivated for that script. Any functions that were not declared would still trigger the run-time warnings and it would be even more damning evidence of subterfuge or careless coding. – Brock Adams Mar 06 '12 at 07:41
  • Well, shadowing specific bad functions is blacklisting, which is a little concerning. Odds are that your blacklist will be incomplete. Blacklists tend to be fragile. – D.W. Mar 07 '12 at 06:52
  • 1
    @D.W., I don't follow you. I'm making these functions and have full control over their run-time behavior (barring security exploits that I don't know about). How could a script writer bypass that? – Brock Adams Mar 07 '12 at 08:19
  • @BrockAdams, if you only expose known-good functions, you're good (whitelisting). If you expose everything, but then shadow the known-bad ones, that is fragile (blacklisting). Normally, in Javascript, everything is accessible by default and you can't prevent untrusted code from getting access to everything (via the global object). Firefox extensions are allowed to use `evalInSandbox`, which lets the caller specify a different global object. If you use `evalInSandbox` to specify a global object that only exposes known-good functions, you're in good shape -- but then you don't need shadowing. – D.W. Mar 08 '12 at 20:17
  • Maybe "shadowing" isn't the correct term for it, but this answer inspired what looks to be the best approach so far... That is, the function itself warns the user (and maybe aborts the script) unless pre-indicated in a "manifest" (In which case the user will only get a milder install-time warning). – Brock Adams Mar 08 '12 at 22:14
  • @BrockAdams I call it shadowing when done on purpose and clobbering when it's not deliberate :) – alex Mar 09 '12 at 00:42
2

Trying to scan the script to detect whether it uses any of these interfaces is the wrong approach. It is too easy to evade through obfuscation, as you seem to be discovering. It's fundamentally insecure: there's no way to make it work.

Here is a better approach. Require the script-writer to include a manifest that declares what special APIs it needs access to. Then, run the script in a secure Javascript sandbox which only exposes the allowed APIs and APIs it has requested, but nothing more. If the script doesn't request GM_openSQL_Connection in its manifest, don't expose that API to the script.

Because Javascript is a dynamic language that allows monkey-patching and unrestricted access to the global object, it takes some doing to build a secure sandbox that restricts what APIs the script can access. Therefore, I recommend that you use an existing sandboxing solution. One approach is to run the user script in a sandbox, and give the sandboxed code a library that's full of stubs for the sensitive APIs, where the stubs just use postMessage to send a RPC request to your extension code. This avoids having references that cross the sandbox boundary, which is good as (depending upon sandboxing technology) those kind of references typically carry a substantial potential for security vulnerabilities.

Then, you can drive your user warnings based upon the contents of the manifest. Important: please think carefully about this from a user's perspective. Will ordinary users be able to make sense of the warnings? Will they be able to make sensible decisions? Will users be in a better position to make good decisions than you will? Will users be overwhelmed by constant warnings, and just start ignoring them and clicking 'ok' (the cry-wolf effect)?

For information on technology for Javascript sandboxing, please read the following question on IT Security: How to scan Javascript for malicious code?. In the future, you might get answers on the IT Security site for this kind of question.

Community
  • 1
  • 1
D.W.
  • 3,382
  • 7
  • 44
  • 110
  • That defies everything I've experienced or read so far. Please supply a reference, or an example, for/of script code being able to access extension code (**not** content-script code) outside of the API that the extension may supply. – Brock Adams Mar 07 '12 at 21:35
  • That is not quite the architecture and not quite how Greasemonkey operates. The user script is installed once, never downloaded on the fly (with updates turned off, anyway). And it is not quite just `eval`ed. It is run using `evalInSandbox`, after some security restrictions are applied. Chrome uses a similar mechanism, if I understand it correctly. Your comments may still apply, but I've yet to see documentation or an example. – Brock Adams Mar 08 '12 at 00:45
  • @BrockAdams, Good point! My error. I retract my statements about the need for special sandboxing technology (like Caja). I completely forgot about `evalInSandbox`, so I am obviously not as well-informed as I thought. My apologies for my errors. – D.W. Mar 08 '12 at 05:55