Password Storage (And Attacking) In PHP Anthony Ferrara
“Anyone, from the most clueless amateur to the best cryptographer, can create an algorithm that he himself can't break.” - Bruce Schneier
Github URL Follow Along: github.com/ircmaxell/password-bad-web-app A "Bad Web App" - Has Known Vulnerabilities - Only Use For Education!!! - Requires only Apache + PHP - Has Composer Dependencies
Let's Start From The Beginning
Plain-Text Storage git checkout plaintext Stores passwords in Plain-Text What's wrong with this picture?
Plain-Text Storage What happens if we have a SQL-Injection Vulnerability? localhost/sqli Simulates: ?offset=0'+UNION+SELECT+*+FROM+users
Plain-Text Storage Problem! Any attack vector results in leakage of ALL credentials!
We Can Do Better
MD5 git checkout md5 Uses the MD5 Cryptographic Hash function. md5($password) hash('md5', $password)
Wait, What Is A Hash?
What's A Cryptographic Hash? Like a fingerprint. One-way. - Easy and efficient to compute - Very inefficient to reverse - (Practically impossible) - Very hard to create collision - (new input with same output)
MD5 What's the problem now? SQL-Injection still gives us hash But the hash is one-way, how can we attack it?
Enter: Lookup Tables
Lookup Table Google is a great example Maps hash to password directly Database Table: hash | password --------------+----------- "5f4dcc3b..." | "password" "acbd18db..." | "foo"
Lookup Table Lookups are CPU efficient. Require a LOT of storage space - (Very space inefficient) All passwords <= 7 chars (95^7, 70 Trillion) Requires 1.5 PetaBytes - In Most Optimal Storage Format
We Can Do Better
Lookup Table Password Hash a4fef...
Rainbow Table Seed Hash Reduce Hash a4fef... Reduce New Password b741...
Chained Table Seed 1 Hash Reduce Hash Reduce Hash Reduce Hash Seed 2 Hash Reduce Hash Reduce Hash Reduce Hash Seed 3 Hash Reduce Hash Reduce Hash Reduce Hash Seed 4 Hash Reduce Hash Reduce Hash Reduce Hash Seed 5 Hash Reduce Hash Reduce Hash Reduce Hash Seed 6 Hash Reduce Hash Reduce Hash Reduce Hash
Rainbow Table Seed 1 Hash Reduce Hash Reduce Hash Reduce Hash Seed 2 Hash Reduce Hash Reduce Hash Reduce Hash Seed 3 Hash Reduce Hash Reduce Hash Reduce Hash Seed 4 Hash Reduce Hash Reduce Hash Reduce Hash Seed 5 Hash Reduce Hash Reduce Hash Reduce Hash Seed 6 Hash Reduce Hash Reduce Hash Reduce Hash
Using A Rainbow Table Seed 1 Hash Reduce Hash Reduce Hash Seed 2 Hash Reduce Hash Reduce Hash Seed 3 Hash Reduce Hash Reduce Hash a4fef... b741... b741... b741...
Using A Rainbow Table Seed 1 Hash Reduce Hash Reduce Hash Seed 2 Hash Reduce Hash Reduce Hash Seed 3 Hash Reduce Hash Reduce Hash a4fef... b741... b741... b741...
Using A Rainbow Table Seed 1 Hash Reduce Hash Reduce Hash Seed 2 Hash Reduce Hash Reduce Hash Seed 3 Hash Reduce Hash Reduce Hash a4fef... b741... b741... b741... Reduce Hash
Using A Rainbow Table Seed 1 Hash Reduce Hash Reduce Hash Seed 2 Hash Reduce Hash Reduce Hash Seed 3 Hash Reduce Hash Reduce Hash a4fef... b741... b741... b741... Reduce Reduce Hash Hash
Rainbow Table Time/Space Tradeoff - Slower than a Lookup Table - Uses Much less storage Most (99.9%) passwords <= 7 chars Requires only 64 GB - Chain length of 71,000
Defense!
Salted MD5 git checkout salted-md5 Uses the MD5 Cryptographic Hash function. But adds a random salt UNIQUE per user. md5($salt . $password) hash('md5', $salt . $password)
Salts Must be unique! - Per Hash - Globally Should be random - Strong!!! - Reasonably long (at least 64 bits)
Salted MD5 What's the problem now? SQL-Injection still gives us hash - And the salt But the salt defeats rainbow tables...
Can Anyone See The Problem?
What's A Cryptographic Hash? Like a fingerprint. One-way. - Easy and efficient to compute - Very inefficient to reverse - (Practically impossible) - Very hard to create collision - (new input with same output)
What's A Cryptographic Hash? Like a fingerprint. One-way. - Easy and efficient to compute - Very inefficient to reverse - (Practically impossible) - Very hard to create collision - (new input with same output)
Hash Functions Are Made To Be FAST
Brute Forcing Several Tools Available - John The Ripper - OCIHashCat A Lot Faster Than You May Think
Brute Forcing Multiple Ways To Attack - Mask Based (permutations) - Dictionary Based - Combinator Based - Combinations of dictionary words - Fingerprint Based - Combinators applied with permutations - Rule Based - Takes input password and transforms it
Brute Forcing Salted MD5 2012 Macbook Pro: - md5: 33 million per second - sha256: 20 million per second Mask Attack: 6 char passwords: 5 hours 7 char passwords: 22 days Entire English Language: 1.8 seconds "LEET" Permutations: 1 hour
We Can Do Better
Brute Forcing Salted MD5 25 GPU Cluster - md5: 180 Billion per second - < US$50,000 6 char passwords: 4 seconds 7 char passwords: 6 minutes 8 char passwords: 10 hours Entire English Language: "LEET" Permutations:
Brute Forcing Salted MD5 25 GPU Cluster - md5: 180 Billion per second - < US$50,000 6 char passwords: 4 seconds 7 char passwords: 6 minutes 8 char passwords: 10 hours Entire English Language: yeah... "LEET" Permutations: 0.7 seconds
But Wait, I Thought MD5 Was Broken?
MD5 IS Broken! But No Other Primitive Hash Is Not!!! sha1≈ md5 sha256 ≈ md5 sha512 ≈ md5 whirlpool ≈ md5 ALL raw primitive hashes are broken for password storage.
So, How Can We Combat Such Hardware?
Iterated MD5 git checkout iterated-md5 Uses the MD5 Cryptographic Hash function. But adds a random salt UNIQUE per user. And iterates a lot of times do { $h = md5($h . $salt . $password) } while($i++ < 1000);
We're Intentionally Slowing It Down
Brute Forcing Iterated MD5 25 GPU Cluster - md5: 70 million per second 6 char passwords: 17 minutes 7 char passwords: 1 day 8 char passwords: 124 days Entire English Language: 0.8 seconds
We Can Do Better
PBKDF2 git checkout pbkdf2 Uses the standard PBKDF2 algo - With SHA512 primitive Slower, and harder to use on GPU pbkdf2($pass, $salt, 10000, 40)
Brute Forcing PBKDF2 25 GPU Cluster - PBKDF2(sha512): 300,000 per second 6 char passwords: 28 days 7 char passwords: 7 years 8 char passwords: 700 years Entire English Language: 3 minutes
We Can Still Do Better
BCrypt git checkout bcrypt Uses the standard BCrypt algo - based on Blowfish cipher Same execution time, Much harder to run on GPU crypt $2a$
Brute Forcing BCrypt 25 GPU Cluster - BCrypt: 70,000 per second 6 char passwords: 120 days 7 char passwords: 31 years 8 char passwords: 3000 years Entire English Language: 14 minutes
A Note On Cost BCrypt accepts a "cost" parameter Must be tuned per server! - Target about 0.1 to 0.25 second runtime - Cost of 10 is a good baseline - Cost of 11 or 12 is better - Only if you have good hardware.
PHP 5.5 Password Hashing API git checkout password-compat A thin wrapper over crypt() - Simplifies implmentation - Strong random salt generation - Can specify cost as int option password_hash($pass, $algo, [$opts]) password_verify($pass, $hash) github.com/ircmaxell/password_compat
We Can Do Even Better!
Let's Encrypt As Well!
Encrypted BCrypt git checkout bcrypt-with-encryption Hash with BCrypt, Then encrypt result with AES-128. Requires key storage for the app. - Not trivial Use only if needed! - BCrypt alone is typically sufficient
Brute Forcing Encrypted BCrypt Attack requires low level server compromise! - SQL Injection is not enough! localhost/codeinject - Simulates code injection that reads source Any low level compromise Is No Worse than raw BCrypt - BCrypt is the baseline.
The Future
The Future scrypt - Sequential Memory Hard - Uses a LOT of memory (> 4mb / hash) - MUCH Harder to brute-force than bcrypt - IFF setup correctly
The Future Password Hashing Competition - Currently being setup - Aims to pick "standard" password hashing algorithm - A community effort
The Future Brute Forcing Word Lists - Complex combinations of words - "horse correct battery staple" Brute Forcing Grammar - "I don't want no cookies" Brute Forcing Structures - URLs, Email Addresses, URLs, etc
“Few false ideas have more firmly gripped the minds of so many intelligent men than the one that, if they just tried, they could invent a cipher that no one could break.” - David Kahn
A Note On Protecting Yourself
xkcd.com/936/
BAD ADVICE xkcd.com/936/
Use True Random Passwords
Use A Password Manager
Anthony Ferrara @ircmaxell me@ircmaxell.com blog.ircmaxell.com youtube.com/ircmaxell

Password Storage And Attacking In PHP - PHP Argentina

  • 1.
    Password Storage (AndAttacking) In PHP Anthony Ferrara
  • 2.
    “Anyone, from themost clueless amateur to the best cryptographer, can create an algorithm that he himself can't break.” - Bruce Schneier
  • 3.
    Github URL FollowAlong: github.com/ircmaxell/password-bad-web-app A "Bad Web App" - Has Known Vulnerabilities - Only Use For Education!!! - Requires only Apache + PHP - Has Composer Dependencies
  • 5.
    Let's Start FromThe Beginning
  • 6.
    Plain-Text Storage gitcheckout plaintext Stores passwords in Plain-Text What's wrong with this picture?
  • 7.
    Plain-Text Storage Whathappens if we have a SQL-Injection Vulnerability? localhost/sqli Simulates: ?offset=0'+UNION+SELECT+*+FROM+users
  • 9.
    Plain-Text Storage Problem! Any attack vector results in leakage of ALL credentials!
  • 10.
    We Can DoBetter
  • 11.
    MD5 git checkoutmd5 Uses the MD5 Cryptographic Hash function. md5($password) hash('md5', $password)
  • 12.
  • 14.
    What's A CryptographicHash? Like a fingerprint. One-way. - Easy and efficient to compute - Very inefficient to reverse - (Practically impossible) - Very hard to create collision - (new input with same output)
  • 15.
    MD5 What's theproblem now? SQL-Injection still gives us hash But the hash is one-way, how can we attack it?
  • 17.
  • 19.
    Lookup Table Googleis a great example Maps hash to password directly Database Table: hash | password --------------+----------- "5f4dcc3b..." | "password" "acbd18db..." | "foo"
  • 20.
    Lookup Table Lookupsare CPU efficient. Require a LOT of storage space - (Very space inefficient) All passwords <= 7 chars (95^7, 70 Trillion) Requires 1.5 PetaBytes - In Most Optimal Storage Format
  • 21.
    We Can DoBetter
  • 22.
    Lookup Table Password Hash a4fef...
  • 23.
    Rainbow Table Seed Hash Reduce Hash a4fef... Reduce New Password b741...
  • 24.
    Chained Table Seed1 Hash Reduce Hash Reduce Hash Reduce Hash Seed 2 Hash Reduce Hash Reduce Hash Reduce Hash Seed 3 Hash Reduce Hash Reduce Hash Reduce Hash Seed 4 Hash Reduce Hash Reduce Hash Reduce Hash Seed 5 Hash Reduce Hash Reduce Hash Reduce Hash Seed 6 Hash Reduce Hash Reduce Hash Reduce Hash
  • 25.
    Rainbow Table Seed1 Hash Reduce Hash Reduce Hash Reduce Hash Seed 2 Hash Reduce Hash Reduce Hash Reduce Hash Seed 3 Hash Reduce Hash Reduce Hash Reduce Hash Seed 4 Hash Reduce Hash Reduce Hash Reduce Hash Seed 5 Hash Reduce Hash Reduce Hash Reduce Hash Seed 6 Hash Reduce Hash Reduce Hash Reduce Hash
  • 26.
    Using A RainbowTable Seed 1 Hash Reduce Hash Reduce Hash Seed 2 Hash Reduce Hash Reduce Hash Seed 3 Hash Reduce Hash Reduce Hash a4fef... b741... b741... b741...
  • 27.
    Using A RainbowTable Seed 1 Hash Reduce Hash Reduce Hash Seed 2 Hash Reduce Hash Reduce Hash Seed 3 Hash Reduce Hash Reduce Hash a4fef... b741... b741... b741...
  • 28.
    Using A RainbowTable Seed 1 Hash Reduce Hash Reduce Hash Seed 2 Hash Reduce Hash Reduce Hash Seed 3 Hash Reduce Hash Reduce Hash a4fef... b741... b741... b741... Reduce Hash
  • 29.
    Using A RainbowTable Seed 1 Hash Reduce Hash Reduce Hash Seed 2 Hash Reduce Hash Reduce Hash Seed 3 Hash Reduce Hash Reduce Hash a4fef... b741... b741... b741... Reduce Reduce Hash Hash
  • 30.
    Rainbow Table Time/SpaceTradeoff - Slower than a Lookup Table - Uses Much less storage Most (99.9%) passwords <= 7 chars Requires only 64 GB - Chain length of 71,000
  • 31.
  • 33.
    Salted MD5 gitcheckout salted-md5 Uses the MD5 Cryptographic Hash function. But adds a random salt UNIQUE per user. md5($salt . $password) hash('md5', $salt . $password)
  • 34.
    Salts Must beunique! - Per Hash - Globally Should be random - Strong!!! - Reasonably long (at least 64 bits)
  • 35.
    Salted MD5 What'sthe problem now? SQL-Injection still gives us hash - And the salt But the salt defeats rainbow tables...
  • 37.
    Can Anyone See The Problem?
  • 38.
    What's A CryptographicHash? Like a fingerprint. One-way. - Easy and efficient to compute - Very inefficient to reverse - (Practically impossible) - Very hard to create collision - (new input with same output)
  • 39.
    What's A CryptographicHash? Like a fingerprint. One-way. - Easy and efficient to compute - Very inefficient to reverse - (Practically impossible) - Very hard to create collision - (new input with same output)
  • 40.
    Hash Functions AreMade To Be FAST
  • 41.
    Brute Forcing SeveralTools Available - John The Ripper - OCIHashCat A Lot Faster Than You May Think
  • 42.
    Brute Forcing MultipleWays To Attack - Mask Based (permutations) - Dictionary Based - Combinator Based - Combinations of dictionary words - Fingerprint Based - Combinators applied with permutations - Rule Based - Takes input password and transforms it
  • 43.
    Brute Forcing SaltedMD5 2012 Macbook Pro: - md5: 33 million per second - sha256: 20 million per second Mask Attack: 6 char passwords: 5 hours 7 char passwords: 22 days Entire English Language: 1.8 seconds "LEET" Permutations: 1 hour
  • 44.
    We Can DoBetter
  • 46.
    Brute Forcing SaltedMD5 25 GPU Cluster - md5: 180 Billion per second - < US$50,000 6 char passwords: 4 seconds 7 char passwords: 6 minutes 8 char passwords: 10 hours Entire English Language: "LEET" Permutations:
  • 47.
    Brute Forcing SaltedMD5 25 GPU Cluster - md5: 180 Billion per second - < US$50,000 6 char passwords: 4 seconds 7 char passwords: 6 minutes 8 char passwords: 10 hours Entire English Language: yeah... "LEET" Permutations: 0.7 seconds
  • 48.
    But Wait, IThought MD5 Was Broken?
  • 49.
    MD5 IS Broken! But No Other Primitive Hash Is Not!!! sha1≈ md5 sha256 ≈ md5 sha512 ≈ md5 whirlpool ≈ md5 ALL raw primitive hashes are broken for password storage.
  • 50.
    So, How CanWe Combat Such Hardware?
  • 51.
    Iterated MD5 gitcheckout iterated-md5 Uses the MD5 Cryptographic Hash function. But adds a random salt UNIQUE per user. And iterates a lot of times do { $h = md5($h . $salt . $password) } while($i++ < 1000);
  • 52.
  • 53.
    Brute Forcing IteratedMD5 25 GPU Cluster - md5: 70 million per second 6 char passwords: 17 minutes 7 char passwords: 1 day 8 char passwords: 124 days Entire English Language: 0.8 seconds
  • 54.
    We Can DoBetter
  • 55.
    PBKDF2 git checkoutpbkdf2 Uses the standard PBKDF2 algo - With SHA512 primitive Slower, and harder to use on GPU pbkdf2($pass, $salt, 10000, 40)
  • 57.
    Brute Forcing PBKDF2 25 GPU Cluster - PBKDF2(sha512): 300,000 per second 6 char passwords: 28 days 7 char passwords: 7 years 8 char passwords: 700 years Entire English Language: 3 minutes
  • 58.
    We Can Still Do Better
  • 59.
    BCrypt git checkoutbcrypt Uses the standard BCrypt algo - based on Blowfish cipher Same execution time, Much harder to run on GPU crypt $2a$
  • 61.
    Brute Forcing BCrypt 25 GPU Cluster - BCrypt: 70,000 per second 6 char passwords: 120 days 7 char passwords: 31 years 8 char passwords: 3000 years Entire English Language: 14 minutes
  • 62.
    A Note OnCost BCrypt accepts a "cost" parameter Must be tuned per server! - Target about 0.1 to 0.25 second runtime - Cost of 10 is a good baseline - Cost of 11 or 12 is better - Only if you have good hardware.
  • 63.
    PHP 5.5 PasswordHashing API git checkout password-compat A thin wrapper over crypt() - Simplifies implmentation - Strong random salt generation - Can specify cost as int option password_hash($pass, $algo, [$opts]) password_verify($pass, $hash) github.com/ircmaxell/password_compat
  • 64.
    We Can Do Even Better!
  • 65.
  • 66.
    Encrypted BCrypt gitcheckout bcrypt-with-encryption Hash with BCrypt, Then encrypt result with AES-128. Requires key storage for the app. - Not trivial Use only if needed! - BCrypt alone is typically sufficient
  • 68.
    Brute Forcing EncryptedBCrypt Attack requires low level server compromise! - SQL Injection is not enough! localhost/codeinject - Simulates code injection that reads source Any low level compromise Is No Worse than raw BCrypt - BCrypt is the baseline.
  • 70.
  • 71.
    The Future scrypt - Sequential Memory Hard - Uses a LOT of memory (> 4mb / hash) - MUCH Harder to brute-force than bcrypt - IFF setup correctly
  • 72.
    The Future PasswordHashing Competition - Currently being setup - Aims to pick "standard" password hashing algorithm - A community effort
  • 73.
    The Future BruteForcing Word Lists - Complex combinations of words - "horse correct battery staple" Brute Forcing Grammar - "I don't want no cookies" Brute Forcing Structures - URLs, Email Addresses, URLs, etc
  • 74.
    “Few false ideashave more firmly gripped the minds of so many intelligent men than the one that, if they just tried, they could invent a cipher that no one could break.” - David Kahn
  • 75.
    A Note On Protecting Yourself
  • 76.
  • 77.
  • 78.
    Use True Random Passwords
  • 79.
  • 80.
    Anthony Ferrara @ircmaxell me@ircmaxell.com blog.ircmaxell.com youtube.com/ircmaxell