Skip to content

Instantly share code, notes, and snippets.

@timmc
Last active August 29, 2015 14:02
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save timmc/264d5c0d033b6b62d6e5 to your computer and use it in GitHub Desktop.
Save timmc/264d5c0d033b6b62d6e5 to your computer and use it in GitHub Desktop.
LastPass brute-forcing for master password recovery

Below is a script I used to recover a LastPass master password from Firefox's Browser Console (not Firebug or the Web Console, this is in the Tools -> Web Developer menu.)

Caveats

  • Be sure to disable your internet connection before running this, or LastPass will lock your account for too many attempts! Yes, this probably means there is something wrong with their security model, since it's all supposed to be done offline.
  • I do not know whether there is a chance the Browser Console might log what you enter (and therefore your password) to some file. You probably want to change your password after this, thus beginning anew the cycle of forgetting.
  • This script only works for single-character substitutions. It should be easy to modify for other ways of walking through a keyspace.

Code

// Let's say you've forgotten a single character in your password.
// We'll represent that substitution with the string "_" since it's
// not found anywhere else in the password.

var pformat = "hunter_two"; // This is your password with an empty slot
var preplace = "_"; // This is the empty slot representation.
var email = "email@example.com"; // The email you want to log in with.

var syms =  "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}";
var candidates, found, stopBrute, candidateIndex;
function resetBrute() {
  candidates = [].map.call(syms, function(c) { return pformat.replace(preplace, c); });
  found = null;
  stopBrute = false;
  candidateIndex = 0;
}
function tryCandidates() {
  if(stopBrute || (candidateIndex >= candidates.length))
    return;

  var attempt = candidates[candidateIndex];
  console.log("Attempt:", attempt);
  LP.lplogin(email, attempt, false);
  // We're using a timeout loop in order to not block the browser thread.
  setTimeout(function receiveOrRecur() {
    if(LP.getLoggedIn()) {
      found = attempt;
      console.log("Success! The last logged attempt worked.");
    } else {
      candidateIndex++;
      tryCandidates();
    }
  }, 100);
}

resetBrute();
tryCandidates();
// To stop early, issue stopBrute = true;
// If logging is disabled, successful attempt can still be found in candidates[candidateIndex]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment