Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Breaking User Passwords -- and why you should

973e0861866767b3940a6dbb5aac3642?s=47 Matt Land
October 05, 2014

Breaking User Passwords -- and why you should

How can we fix ‘broken’ password hashing in our applications? Using the cloud and brute force, applications can be repaired. From code audit to account upgrade, techniques for reversing user hashes will be discussed, and well as success rates, costs, and choosing appropriate security frameworks. Finally, the appropriate applications for sorting methods will be discussed.


Matt Land

October 05, 2014

More Decks by Matt Land

Other Decks in Technology


  1. Breaking User Passwords and Why You Should

  2. We help people get storage ! ! ! ! Move

    in and move on.
  3. Matt Land github.com/matt-land linkedin.com/in/matthewland

  4. My organization is not immune

  5. 110 M 56 M 76 M 56 M 115 M

    Households! 330 M People! Most are compromised! 150 M 50 M 1 M 50 M 45 M 2.5 M 1.5 M
  6. What did we lose?

  7. None
  8. Permanent Compromise Permanent Compromise Reissued Big Hassle Reissued Trivial Hassle

    Self Reissued Minor Hassle Never should have been saved Its complicated…
  9. Users are special • Passwords are terrible. • Arbitrary rules

    forced on your users does not make them stronger. • Make no restrictions beyond a minimum length. • Do not restrict the length or pattern. • We cannot prevent a user from sharing tokens across sites. Assume they will.
  10. Passwords are special • Was it compromised? • Has the

    most value to the user • May have the most value to an attacker • Users will continue using a compromised password after a breach
  11. • Was it compromised? • Has the most value to

    the user • May have the most value to an attacker • Users will continue using a compromised password after a breach Cryptographically Secure passwords are special !
  12. Secure Methods • Not based on a sorting algorithms like

    md5 or sha • Unique and variable salts per account • Expensive expressed in terms of cycles or heat • /dev/random > os.urandom() > random.random() • Time based functions are the devil • Do not write your own crypto. There be dragons.
  13. Hash vs Crypt Fast I could implement Slow I would

    never implement Sorting methods are still great. For sorting!
  14. Good candidate for writing his own crypto: Again, do not

    write your own crypto. Dustin Boswell http://dustwell.com/how-to-handle-passwords-bcrypt.html
  15. Dangers of Writing Crypto Poor node balance in a hash

    causes poor performance. Poor node balance in a crypt breaks the crypt.
  16. None
  17. None
  18. None
  19. If you can break your user’s passwords, you should break

    your user’s passwords.
  20. • I could update my application to use better crypto

    • In a way that is transparent to my users • In a week
  21. Vulnerability Testing select * from users where password in( !

    ! md5(‘password’), md5(‘123456’), md5(‘jesus’), ! ! ! md5(‘football’), md5(‘ninja’), ! ! sha1(‘password’), sha1(‘123456’), sha1(‘jesus’), ! ! ! sha1(‘football’), sha1(‘ninja’)! );! ! select * from users where password in (! ! md5(concat(‘123456’, salt)),! ! sha1(concat(‘123456’, salt)),! ! sha2(concat(‘123456’, salt)),! ! password(concat(‘123456’, salt))! ); MySQL hash methods http://dev.mysql.com/doc/refman/5.5/en/encryption-functions.html
  22. The Plan • Build a replacement auth service • The

    service authenticator would support two tiers • Refactor all entry points to use the service authenticator • All new users use the new method • All user authentications auto-upgrade to the new method • Build a dedicated API for a challenge and upgrade • Start cracking codes
  23. Replacement auth mechanism public static function loadByLogin($emailAddress, $password) { $user

    = self::load( Genesis_Db_Restriction::equal('email', $emailAddress) )->uniqueResult(); ! if ($user && $user->checkRawPassword($password)) { return $user; } } ! public function checkRawPassword($password) { if ($this->getBcryptPasswordFlag()) { $bcrypt = new Bcrypt(); return $bcrypt->verify($password, $this->getPassword()); } else { return (some_hash_method($password) == $this->getPassword()); } } public static function loadByLogin($emailAddress, $password) { return Genesis_Dao_AccountMgmtUser::select( Genesis_Db_Restriction::and_( Genesis_Db_Restriction::equal('email', $email), Genesis_Db_Restriction::equal('password', some_hash_method($password)) ) )->uniqueResult(); }
  24. Bad Code if hash_func($oldPassword) is not self.getLoggedUser().getPassword(): Not owned by

    the model! ! if row.password is not sha1(sha1(salt) + sha1(password)): Wonky, 3x slower, and no stronger than sha1, possibly weaker! ! elif sha1(password) is self._accounts[‘username’][1] (???) ! return self._sha1(password) is self._accounts[‘username’]; ! Not dry in the model, and is matching against the user name?! ! $plain_sha1 = sha1($password); $password = '" . $this->_escape($plain_sha1) . "' No salt ! return sha1(uniqid('', true) . $request->getUrl()); In a password reset url, time based function
  25. Refactoring Remove dozens of implementations across the code and pushed

    back into the model. (Not DRY) ! Added the bcrypt boolean field to db. Millions of rows * 2 bytes = not much ! Added upgradeBcryptPassword method to login. Users now help with the upgrade. ! Wrote unit tests. ! Pushed it over the wall.
  26. A dedicated route for upgrades • Goes through the application

    and it’s models • No more sql methods used to bypass authentication • POST url with email, password, and api key • The cracking machine lives in a separate cloud
  27. Cracking with Wordlists • Crackstation is a superset of Gawker,

    Adobe, etc. • Actual passwords from users • Generate a dict using your application’s hash and salts • Compare each hash against your users table • Majority of passwords fell immediately, 63% • Rerun with the expanded list gained another 4%
  28. Cracking with Tables • Rainbow tables from freerainbowtables.com • SHA,

    MD5, NTLM • Hashes semi computed, but huge (4TB EC2) • Compile rcrack_rt with threads = cores • 4.5 months, run against only the remaining 33% • Called them in to the production server using curl request. Cracked passwords were never on the production box.
  29. • Move an existing application to modern method • All

    the users • Transparent to users • In a week
  30. Summary • Cannot reach 100%, yet • If we are

    breached, most of the passwords are safe • My cpu power is less than a botnet has available • But, all the low hanging fruit is gone • My active users will be protected
  31. Errata • The race state: very very tiny percent of

    pw upgrades fail because the user changed passwords during the window of dump, process, push, 0.2% • Swapping EC2 machines took forever because of the rotational storage attached, but didn’t matter to the run • EC2 is slow, the dedicated GPU configs help
  32. Matt Land github.com/matt-land linkedin.com/in/matthewland