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

Breaking User Passwords, extended

Matt Land
October 29, 2014

Breaking User Passwords, extended

This version of the talk was given at Zendcon uncon 2014. This version is more focused on PHP instead of Python

Matt Land

October 29, 2014
Tweet

More Decks by Matt Land

Other Decks in Technology

Transcript

  1. Breaking User Passwords Background Passwords are special Sorting vs Crypto

    When we fix our applications How we fix our applications Code examples
  2. 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 ? 130 M
  3. Permanent Compromise Permanent Compromise Reissued Big Hassle Reissued Trivial Hassle

    Self Reissued Minor Hassle Never should have been saved (PCI) Its complicated…
  4. Users are special • Passwords are a poor technology for

    humans. • Enforcing arbitrary rules on passwords makes them worse for both parties. • Compromise with a minimum length only. • Do not restrict the length or symbols. • Do not disable paste. • We cannot prevent passwords being used for multiple sites. Assume they will be.
  5. 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 even after it was exposed
  6. • 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 !
  7. Best Practices • Expensive in terms of cycles and energy

    (IE Not based on a sorting algorithms like md5 or sha) • Unique and variable salts per account • Asymmetric • /dev/random > /dev/urandom • Time based functions are the devil: uniqid() • Do not write your own crypto. There be dragons.
  8. Arbitrary Rules Red: MMDDYY Green: YYDDMM Yellow: YYMMDD Pink: ended

    in 19XX Requiring capitals and numbers can make passwords worse. <Capital><+rest of word><number, usually 1>
  9. Hash vs Crypt Fast Slow Sorting methods are still great.

    For sorting! PHP’s array type MD5 TwoFish Uses a fast sorting method
  10. The list of people qualified to write crypto is short.

    Do not write your own crypto. Use builtin crypt() function, or a vetted library like Zend/Auth/Bcrypt
  11. Dangers of Writing Crypto Bad Really Bad Maybe OK? Poor

    node balance in a hash causes poor performance. Poor node balance in a crypt breaks security.
  12. • I could update my application to use better crypto

    • In a way that is transparent to my users • In a week
  13. 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
  14. The Plan 12% 15% 15% 59% • Dictionary Attack •

    Rainbow Cloud Attack • Users Authenticating • Unachievable All User Passwords
  15. Implementation • 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
  16. Replacement Auth Service public static function loadByLogin($emailAddress, $password) { $user

    = self::load( Restriction::equal('email', $emailAddress) )->uniqueResult(); if (! $user || ! $user->checkRawPassword($password)) { return false; } return $user; } public function checkRawPassword($password) { if ($this->getBcryptPasswordFlag()) { $bcrypt = new Bcrypt(); return $bcrypt->verify($password, $this->getPassword()); } if (some_hash_method($password) !== $this->getPassword()) { return false;} $this->upgradePassword($password); return true; } public static function loadByLogin($emailAddress, $password) { return AccountMgmtUser::select( Restriction::and_( Restriction::equal('email', $email), Restriction::equal('password', some_hash_method($password)) ))->uniqueResult(); }
  17. Bad Code if(sha1($oldPassword) != $this->getLoggedUser()->getPassword()) { Not owned by the

    model, not DRY if($row->password != sha1(sha1($salt).sha1($pwd))){ Wonky, 3x slower, and no stronger than sha1, possibly weaker else if (sha1($password) == $this->_accounts[$username][1]) (???) return $this->_sha1($password) == $this->_accounts[$username]; Matching against the user name? $plain_sha1 = sha1($password); $password = '" . $this->_escape($plain_sha1) . "' No salt, escape before transform return sha1(uniqid('', true) . $request->getUrl()); In a password reset url, this was a time based function
  18. 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.
  19. Dedicated upgrades route • 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
  20. 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%
  21. 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.
  22. • Move an existing application to modern method • All

    the users • Transparent to users • In a week
  23. 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 • All the low hanging fruit is gone • Users password will be protected
  24. In Your Project • Saltless md5, sha1, ntlm • Sitewide

    salt + md5, sha1, ntlm • one magnitude more difficult • Correctly salted accounts • AutoUpgrading
  25. 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
  26. Matt Land CERTIFIED A R C H I T E

    CT 2 github.com/matt-land linkedin.com/in/matthewland speakerdeck.com/mattland/ https://joind.in/12551