2

A few weeks ago I made a proof-of-concept app demonstrating how LastPass' method of filling out creds in Chrome was insecure. For those interested the source is at https://github.com/activems/clipcaster

Essentially they copy a chunk of javascript to the clipboard and have the user execute it. This includes the user name and password. In previous versions it has been filled out plainly as:

if (l_bte) {
    l_sfv(l_bte, decodeURIComponent(escape(atob('dXNlckBleGFtcGxlLmNvbQ=='))));
}
l_sfv(l_bpe, decodeURIComponent(escape(atob('cDRzc3cwcmQ='))));

With 'dXNlckBleGFtcGxlLmNvbQ==' being Base64 for 'user@example.com' and 'cDRzc3cwcmQ=' being 'p4ssw0rd'

LastPass recently updated the JavaScript they use. Now it is (full version at https://raw.githubusercontent.com/activems/clipcaster/master/lastpass_output_v2.js):

var l_x = function(t, l, m) {
    var o = [];
    var b = '';
    var p = document.location.href.replace(/https?:\/\//, '').substring(0, l);
    p = l_s('' + l_f(m) + p);
    for (z = 1; z <= 255; z++) {
        o[String.fromCharCode(z)] = z;
    }
    for (j = z = 0; z < t.length; z++) {
        b += String.fromCharCode(o[t.substr(z, 1)] ^ o[p.substr(j, 1)]);
        j = (j < p.length) ? j + 1 : 0;
    }
    return decodeURIComponent(escape(b));
};

....

var l_f=function(m){ 
    var t=new Date().getTime() /
        1000 | 0;
        while (t % 10 != m) {
            --t;
        }
        return t;
    };

....

if (l_bte) {

    l_sfv(l_bte, l_x(atob('W01cCVUlA1AVCkIDAk8AC1g='), 61, 0));
}
l_sfv(l_bpe, l_x(atob('QldeA0BREUAWDEMC'), 61, 0));

Is there any pragmatic reason to write JavaScript like this besides obfuscation?

1
  • Seems like they're beginning to implement some kind of "encryption" and a very preliminary version somehow made it into production code. (I almost hear the manager saying something like "Someone cracked our current encryption. Seems base64 isn't that secure after all. I don't care if you're not finished yet, if you have a version that doesn't use base64, move it to production. NOW.") Dec 8 '14 at 0:48
2

In short, no. If they're going to implement the "crypto" in Javascript in this way there isn't anything you can do beyond more obfuscation. This is 100% applicable to this situation but see MataSano's article here explaining pitfalls of client side authentication using JavaScript.

Similar to what's touched on in the article, the issue is that no matter how complicated the JavaScript is, it's trivial for an attacker to intercept and run the code. Similar to a MitM where an attack can intercept and replace client side JavaScrip, in this case the issue is that it's so easy for another app to access the Clipboard via the ClipboardManager. A much better bare minimum solution would be to have LastPass et al store saved credentials in an authenticated SQLite database. And upon detecting the fillable are use code in the application. to pull the saved credentials and enter them directly instead of using the Clipboard and running JavaScript.

The crux of the problem is it's too easy for an attacker to get a callback using the current API; having the app use its own database prevents an attacker from intercepting the authentication workflow without having root privileges (which is a different discussion altogether). This is a good example of not considering security from the ground up when implementing an application.

As an aside, cool stuff and reporting the bug. Can you put a vulnerable version of the application on github (if you haven't already)? It would be a great demo in the future.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.