80,000 Plaintext Passwords: An Open Source Love Story in Three Acts

80,000 Plaintext Passwords: An Open Source Love Story in Three Acts

F3a34c1bd3b8a36b4dd07869bd6b5506?s=128

T.J. Schuck

June 26, 2014
Tweet

Transcript

  1. 80,000 Plaintext Passwords @tjschuck

  2. Act I

  3. mallory@local$ ′

  4. None
  5. T.J. Schuck
 @tjschuck

  6. HARVEST getHarvest.com

  7. I am not a Security Expert™

  8. mallory@local$ ′

  9. Layers Layers Layers Layers

  10. mallory@local$ perl haxor.pl ′

  11. mallory@local$ perl haxor.pl ! +------+-----------------------+------------+ | id | email |

    password | +------+-----------------------+------------+ | 6125 | provos@openbsd.org | honeyd | | 6126 | schneier@schneier.com | blowfish | | 6127 | tj@tjschuck.com | peppercorn | | 6128 | rivest@mit.edu | md1947 | +------+-----------------------+------------+
  12. “But…”

  13. mallory@local$ perl haxor.pl ! +------+-----------------------+------------+ | id | email |

    password | +------+-----------------------+------------+ | 6125 | provos@openbsd.org | honeyd | | 6126 | schneier@schneier.com | blowfish | | 6127 | tj@tjschuck.com | peppercorn | | 6128 | rivest@mit.edu | md1947 | +------+-----------------------+------------+
  14. mallory@local$ perl haxor.pl ! +------+-----------------------+------------+ | id | email |

    password | +------+-----------------------+------------+ | 6125 | provos@openbsd.org | ubarlq | | 6126 | schneier@schneier.com | oybjsvfu | | 6127 | tj@tjschuck.com | crccrepbea | | 6128 | rivest@mit.edu | zq1947 | +------+-----------------------+------------+
  15. Encryption is reversible

  16. Hashing is irreversible

  17. None
  18. hash(‘peppercorn’) => 6a58d0ad2619df7d7fabc2603b79063f

  19. hash(‘peppercorn’) => 6a58d0ad2619df7d7fabc2603b79063f hash(‘secret1234’) => bdfc2db0aa599f5919e565c328216a51

  20. hash(‘peppercorn’) => 6a58d0ad2619df7d7fabc2603b79063f hash(‘secret1234’) => bdfc2db0aa599f5919e565c328216a51 => 18ad6448e70b7b0254cad4d77653f2d7

  21. hash(‘peppercorn’) => 6a58d0ad2619df7d7fabc2603b79063f hash(‘secret1234’) => bdfc2db0aa599f5919e565c328216a51 => 18ad6448e70b7b0254cad4d77653f2d7 ?

  22. Hashing is deterministic

  23. None
  24. hash(‘peppercorn’) => 6a58d0ad2619df7d7fabc2603b79063f

  25. hash(‘peppercorn’) => 6a58d0ad2619df7d7fabc2603b79063f hash(‘peppercorn’) => 6a58d0ad2619df7d7fabc2603b79063f

  26. hash(‘peppercorn’) => 6a58d0ad2619df7d7fabc2603b79063f hash(‘peppercorn’) => 6a58d0ad2619df7d7fabc2603b79063f hash(‘peppercorn’) => 6a58d0ad2619df7d7fabc2603b79063f

  27. Hashing is deterministic (but not obvious)

  28. hash(‘peppercorn’) => 6a58d0ad2619df7d7fabc2603b79063f hash(‘peppercorn’) => 6a58d0ad2619df7d7fabc2603b79063f !

  29. hash(‘peppercorn’) => 6a58d0ad2619df7d7fabc2603b79063f hash(‘peppercorn’) => 6a58d0ad2619df7d7fabc2603b79063f ! hash(‘Peppercorn’) => b8bfa4f1b72ee60755a71dbdf0700fe9

  30. hash(‘peppercorn’) => 6a58d0ad2619df7d7fabc2603b79063f hash(‘peppercorn’) => 6a58d0ad2619df7d7fabc2603b79063f ! hash(‘Peppercorn’) => b8bfa4f1b72ee60755a71dbdf0700fe9

    => b8bfa4f1b72ee60755a71dbdf0700fe8
  31. hash(‘peppercorn’) => 6a58d0ad2619df7d7fabc2603b79063f hash(‘peppercorn’) => 6a58d0ad2619df7d7fabc2603b79063f ! hash(‘Peppercorn’) => b8bfa4f1b72ee60755a71dbdf0700fe9

    => b8bfa4f1b72ee60755a71dbdf0700fe8 ?
  32. mallory@local$ perl haxor.pl ! +------+-----------------------+----------------------------------+ | id | email |

    password | +------+-----------------------+----------------------------------+ | 6125 | provos@openbsd.org | 6ee717a4bc91d99170ce0d0922ab6c43 | | 6126 | schneier@schneier.com | b258a419ddbc13d92b8e7fc25c2b9d6c | | 6127 | tj@tjschuck.com | 6a58d0ad2619df7d7fabc2603b79063f | | 6128 | rivest@mit.edu | 0304432f4c8080781f1b210c6b92b12f | +------+-----------------------+----------------------------------+
  33. Hashing is deterministic

  34. hash(‘peppercorn’) => 6a58d0ad2619df7d7fabc2603b79063f hash(‘peppercorn’) => 6a58d0ad2619df7d7fabc2603b79063f hash(‘peppercorn’) => 6a58d0ad2619df7d7fabc2603b79063f

  35. None
  36. Rainbow Tables

  37. mallory@local$ perl haxor.pl ! +------+-----------------------+----------------------------------+ | id | email |

    password | +------+-----------------------+----------------------------------+ | 6125 | provos@openbsd.org | 6ee717a4bc91d99170ce0d0922ab6c43 | | 6126 | schneier@schneier.com | b258a419ddbc13d92b8e7fc25c2b9d6c | | 6127 | tj@tjschuck.com | 6a58d0ad2619df7d7fabc2603b79063f | | 6128 | rivest@mit.edu | 0304432f4c8080781f1b210c6b92b12f | +------+-----------------------+----------------------------------+
  38. None
  39. 6a58d0ad2619df7d7fabc2603b79063f

  40. None
  41. None
  42. Defeating the Rainbow

  43. hash(‘peppercorn’) => 6a58d0ad2619df7d7fabc2603b79063f

  44. hash(‘peppercorn-tc5gplQopZ617zRQ8h9pAg’) => c5dde1b5cc0e6d89bda0f5e350bda319

  45. None
  46. WE DID IT!

  47. (no we didn’t)

  48. Proof of Concept

  49. peppercorn

  50. pepper8 pepper83 pepper88 pepper99 ! pepperdog pepperi1 peppermint peppermint1 pepperoni

    pepperpepper peppers peppers4 peppi123 peppone pepsi pepsi1 pepsi123 pepsi2006 pepsi5 pepsi78bottle pepsicat pepsico pepsii pepsimax pepsione pepsis12 pequot per12fect peralta1 peppercorn
  51. un1v3r53 1q2w#E$R fkg7h4f3v6

  52. SALTING

  53. SALTING

  54. hash(‘peppercorn-tc5gplQopZ617zRQ8h9pAg’) => c5dde1b5cc0e6d89bda0f5e350bda319 hash(‘peppercorn-R1XrmmZVRedKMTE9nlIy9Q’) => fc5ad4a64796506086424af78f57df9d

  55. mallory@local$ perl haxor.pl ! +------+----------------------------------+------------------------+ | id | password |

    salt | +------+----------------------------------+------------------------+ | 6125 | 5b5f47a49cdd4386611ee0a63577eccd | CeVDwwrT7saa_cY2rV_qng | | 6126 | a50f4854739e10773c99d5576dbb2f73 | rRWjkN4ioELXIPpQ6aDY4w | | 6127 | 94c91484c8bb05113b28f9da2b7ea624 | XvALmgae9uUGmpikd8sohg | | 6128 | 5d2ee837249e9340624b12e653c5e4a3 | D-ZUYoaSadkCze1fPibbgg | +------+----------------------------------+------------------------+
  56. This is pretty good…

  57. This is pretty good… for 1976.

  58. None
  59. None
  60. None
  61. None
  62. bcrypt ✓ One-way hash
 ✓ Pre-image resistant
 ✓ Deterministic ✓

    Built-in per-password salts
  63. Eksblowfish

  64. Adaptive Cost

  65. mallory@local$ perl haxor.pl ! +-----------------------+--------------------------------------------------------------+ | email | password |

    +-----------------------+--------------------------------------------------------------+ | provos@openbsd.org | $2a$10$1ObnU/cPb3AjVU5iu8ntfe77xO83roRhoJMyBqYhlq5ZMMbHCcELK | | schneier@schneier.com | $2a$10$CelbCnmBjJez5ego4w.mbusfnZGOn/lRhLjrr37R0iUCr1UIC6ZyC | | tj@tjschuck.com | | | rivest@mit.edu | $2a$10$9WLufYmucbh.yaTHKKUuUeihbcA3hBUiI.XiW7ygmaYcYXtl4MBKy | +-----------------------+--------------------------------------------------------------+ $ 2a 10 LrfFlMh6Yc7JWKlpRwVjUuPCOPU5574fXAVrvLZRFT87cT55oLBEe $ $
  66. $ 2a 10 LrfFlMh6Yc7JWKlpRwVjUuPCOPU5574fXAVrvLZRFT87cT55oLBEe $ $

  67. $ 2a 10 LrfFlMh6Yc7JWKlpRwVjUu PCOPU5574fXAVrvLZRFT87cT55oLBEe $ $

  68. $ 2a 10 LrfFlMh6Yc7JWKlpRwVjUu PCOPU5574fXAVrvLZRFT87cT55oLBEe $ $

  69. $ 2a 10 LrfFlMh6Yc7JWKlpRwVjUu PCOPU5574fXAVrvLZRFT87cT55oLBEe $ $

  70. $ 2a 10 LrfFlMh6Yc7JWKlpRwVjUu PCOPU5574fXAVrvLZRFT87cT55oLBEe $ $

  71. $ 2a 10 LrfFlMh6Yc7JWKlpRwVjUu PCOPU5574fXAVrvLZRFT87cT55oLBEe $ $

  72. $ 2a 10 LrfFlMh6Yc7JWKlpRwVjUu PCOPU5574fXAVrvLZRFT87cT55oLBEe $ $ “Cost”

  73. None
  74. bcrypt(‘peppercorn’, 10) =>

  75. bcrypt(‘peppercorn’, 10) => $2a$10$41JmpddjOSEGWU099uQx7O7Y1EiQMTRQFZCcFqFMlYWekR5pj9xFi

  76. bcrypt(‘peppercorn’, 10) => $2a$10$41JmpddjOSEGWU099uQx7O7Y1EiQMTRQFZCcFqFMlYWekR5pj9xFi bcrypt(‘peppercorn’, 10) =>

  77. bcrypt(‘peppercorn’, 10) => $2a$10$41JmpddjOSEGWU099uQx7O7Y1EiQMTRQFZCcFqFMlYWekR5pj9xFi bcrypt(‘peppercorn’, 10) => $2a$10$8ONmT2oiKPoPn/KQTrvHq.gWTnqQ5p.T13lw.lCm9d.QoqIZzbHPS

  78. bcrypt(‘peppercorn’, 10) => $2a$10$41JmpddjOSEGWU099uQx7O7Y1EiQMTRQFZCcFqFMlYWekR5pj9xFi bcrypt(‘peppercorn’, 10) => $2a$10$8ONmT2oiKPoPn/KQTrvHq.gWTnqQ5p.T13lw.lCm9d.QoqIZzbHPS bcrypt(‘peppercorn’, 14)

    =>
  79. bcrypt(‘peppercorn’, 10) => $2a$10$41JmpddjOSEGWU099uQx7O7Y1EiQMTRQFZCcFqFMlYWekR5pj9xFi bcrypt(‘peppercorn’, 10) => $2a$10$8ONmT2oiKPoPn/KQTrvHq.gWTnqQ5p.T13lw.lCm9d.QoqIZzbHPS bcrypt(‘peppercorn’, 14)

    => $2a$14$4US.NV/qyRkctl.LaYvNzOln70yIaqGfJeMq1deb/bPJMMmtcxOU.
  80. bcrypt(‘peppercorn’, 10) => $2a$10$41JmpddjOSEGWU099uQx7O7Y1EiQMTRQFZCcFqFMlYWekR5pj9xFi bcrypt(‘peppercorn’, 10) => $2a$10$8ONmT2oiKPoPn/KQTrvHq.gWTnqQ5p.T13lw.lCm9d.QoqIZzbHPS bcrypt(‘peppercorn’, 14)

    => $2a$14$4US.NV/qyRkctl.LaYvNzOln70yIaqGfJeMq1deb/bPJMMmtcxOU.
  81. bcrypt(‘peppercorn’, 10) => $2a$10$41JmpddjOSEGWU099uQx7O7Y1EiQMTRQFZCcFqFMlYWekR5pj9xFi bcrypt(‘peppercorn’, 10) => $2a$10$8ONmT2oiKPoPn/KQTrvHq.gWTnqQ5p.T13lw.lCm9d.QoqIZzbHPS bcrypt(‘peppercorn’, 14)

    => $2a$14$4US.NV/qyRkctl.LaYvNzOln70yIaqGfJeMq1deb/bPJMMmtcxOU. 0.0656 seconds
  82. bcrypt(‘peppercorn’, 10) => $2a$10$41JmpddjOSEGWU099uQx7O7Y1EiQMTRQFZCcFqFMlYWekR5pj9xFi bcrypt(‘peppercorn’, 10) => $2a$10$8ONmT2oiKPoPn/KQTrvHq.gWTnqQ5p.T13lw.lCm9d.QoqIZzbHPS bcrypt(‘peppercorn’, 14)

    => $2a$14$4US.NV/qyRkctl.LaYvNzOln70yIaqGfJeMq1deb/bPJMMmtcxOU. 0.0656 seconds 0.0657 seconds
  83. bcrypt(‘peppercorn’, 10) => $2a$10$41JmpddjOSEGWU099uQx7O7Y1EiQMTRQFZCcFqFMlYWekR5pj9xFi bcrypt(‘peppercorn’, 10) => $2a$10$8ONmT2oiKPoPn/KQTrvHq.gWTnqQ5p.T13lw.lCm9d.QoqIZzbHPS bcrypt(‘peppercorn’, 14)

    => $2a$14$4US.NV/qyRkctl.LaYvNzOln70yIaqGfJeMq1deb/bPJMMmtcxOU. 0.0656 seconds 0.0657 seconds 1.0481 seconds
  84. Cost Seconds 9 0.0344 10 0.0656 11 0.1333 12 0.2646

    13 0.5236 14 1.0481 15 2.1645 16 4.2801
  85. “Well, actually…”

  86. The Fix

  87. def authenticate(plaintext_password)! if old_hashing_method(plaintext_password) == password_digest! self! end! end

  88. def authenticate(plaintext_password)! if BCrypt::Password.new(password_digest) == plaintext_password! self! end! end

  89. def authenticate(plaintext_password)! return unless convert_old_hash_to_bcrypt(plaintext_password)! ! if BCrypt::Password.new(password_digest) == plaintext_password!

    self! end! end
  90. def convert_old_hash_to_bcrypt(plaintext_password)! return true if BCrypt::Password.valid_hash?(password_digest)! ! if old_hashing_method(plaintext_password) ==

    password_digest! update_column :password_digest,! BCrypt::Password.create(plaintext_password)! end! end
  91. None
  92. None
  93. None
  94. —Act II—

  95. Fat Binary Gems —Act II— You make the rockin’ world

    go ’round
  96. bcrypt-ruby github.com/codahale/bcrypt-ruby

  97. None
  98. None
  99. None
  100. None
  101. None
  102. None
  103. None
  104. None
  105. None
  106. None
  107. None
  108. None
  109. None
  110. None
  111. Well shit.

  112. None
  113. None
  114. rake-compiler-dev-box with Rubies, GCC, JDK, MinGW…

  115. None
  116. LOLOLOLOL NO.

  117. None
  118. rake-compiler#79

  119. Act III

  120. Act III Luis Lavena

  121. None
  122. • One-Click Ruby
 Installer for Windows

  123. • One-Click Ruby
 Installer for Windows • Ruby core

  124. • One-Click Ruby
 Installer for Windows • Ruby core •

    Ruby Hero (2010)
  125. • One-Click Ruby
 Installer for Windows • Ruby core •

    Ruby Hero (2010) • rake-compiler
  126. rake-compiler-dev-box#2

  127. None
  128. None
  129. None
  130. None
  131. None
  132. @luislavena <3 <3 <3

  133. Find your Luis

  134. “Be the Luis you wish to see in the world”

  135. What have we learned?

  136. 1. Just use bcrypt

  137. 2. Distribute a dev box

  138. 3. Release, collaborate, iterate

  139. Thank You @tjschuck getHarvest.com