Rootkits for JavaScript Environments Intro
manipulate the JavaScript environment to interpose undetectable attacker code between a site's scripts and the native JavaScript objects;
very narrow target: bookmarklet-based password managers
bookmarklet: bookmarked JavaScript code. Click the bookmark, execute the code
example: javascript:'hello, world' The Players & the Game
web page = attacker bookmarklet = victim
1. user navigates to evil.com, is prompted to log in 2. user clicks bookmarklet 3. bookmarklet asks page "who are you? " to determine what username and pass to use 4. evil.com answers "bank.com please, thank you " 5. ☠,$,☹ What Makes this Attack Possible
Additionally: page always loads first, bookmarklet second; some pass managers store all the data on the client side, in the bookmarklet itself. I know. Attack Techniques
Shadowing
Emulation
Prototype Poisoning
Reflection
Global Variable Hijacking
Caller Shadowing
replace native JavaScript objects with global objects with the same name Example (works in IE and Google Chrome):
Rootkit Code Bookmarklet Code
var window = { if (window.location.host == "bank. location: { host: "bank.com" } com") }; doLogin(password); Emulation
to thwart attacks of the kind on the previous slide, bookmarklet authors could attempt to test the validity of the "window" object
rootkit authors simply emulate the expected behavior:
window.__defineGetter__("location", function () { return "https://bank.com/login#"; Rootkit Code });
window.__defineSetter__("location", function (v) { });
Bookmarklet Code window.location = "#" Prototype Poisoning
alter behavior of native objects like strings, functions and regular expressions
Rootkit Code Bookmarklet Code
RegExp.prototype.exec = (/ˆhttps?:/i).exec(url) function () { return true; } Global variable hijacking
rootkit author may subvert integrity of global variables by declaring getters and setters for the vars in the window object bookmarklet author may: never use any variables (yeah right) wrap the entire bookmarklet code in an anonymous function. It's cool and it works, but leads to problem on the next slide...
Rootkit Code Bookmarklet Code
window.__defineGetter__( "x", function () { ... }); var x = "#" window.__defineSetter__( "x", function (v) { ... }); Caller
say bookmarklet author wraps entire bookmarklet in an anonymous function, to protect against global var hijacking: (function () { ... if (obj == "bank.com") ... })();
not good enough: == implicitly calls the valueOf method. Attacker owns that function. The moment control gets transferred to valueOf, attacker: 1. obtains pointer to anonymous function by checking call stack 2. calls the anonymous function's toString() method 3. ☠,$,☹ because some bookmarklets store all passwords in the code. Locally. I know. Case studies
team evaluated 6 commercial password managers. all vulnerable. some used encryption; didn't matter. 4 revealed all secrets with 1 click. remaining 2 were exploited by attacking their cross-site scripting filter. VeriSign (yes, that one)
product: "One-Click Sign-In Bookmark" what it took (shadowing): var location = { hostname: "www.facebook.com", href: "http://www.facebook.com/" }; a variant on the above extracted all passwords at once authors' recommended fix implemented soon after reported MashedLife what it took (prototype poisoning): String.prototype.toLowerCase = function() { return "bank.com"; }; authors' recommended fix implemented in under a month
Passpack
what it took (prototype poisoning): String.prototype.toString = function() { return "https://delicious.com"; }; Passpack also validates Referer header, but if none is present, it lets the request through. So it actually doesn't validate the Referer header. authors' recommended fix implemented and deployed in 20 minutes 1Password
stores all user data locally, encrypted, in a global var named 'database.' what it took (global variable setters): window.__defineSetter__("database", function (v) { ... }); attacker overrides the event handler for the user's master password input and decrypts all passwords at once; vendor acknowledged vulnerability but declined to fix it. Clipperz
bookmarklet serializes contents of the login form and presents it to user user pastes serialized content into Clipperz later on, Clipperz submits form as if it came from user when user wants to sign in CSRF anyone? because Clipperz relies on CSRF to make this work, it attempts to sanitize the form to prevent XSS however, it sanitizes locally, in JavaScript (in the bookmarklet) what it took (prototype poisoning): Array.prototype.join = function() { ... return evilString; } fixed within 4 days of reporting MyVidoop
very similar to Clipperz, except it submits the serialized form itself -- user does not have to paste it during registration process same weakness: sanitizes form locally fixed within 1 day of reporting Defenses
1. Don't store passwords locally; instead, store a secure cookie for pwdmgr.com containing a master secret 2. When a pass is needed, query server by inserting a