PDA

View Full Version : Mini Mods - Secure BCrypt Password Hashing


MegaManSec
09-28-2012, 10:00 PM
This is a 'howto' for using bcrypt for your password hashs, instead of the default vBulletin one, which is highly insecure.

Remember, backup your database before doing this!!

bcrypt is a key derivation function for passwords designed by Niels Provos and David Mazi?res, based on the Blowfish cipher, and presented at USENIX in 1999. Besides incorporating a salt to protect against rainbow table attacks, bcrypt is an adaptive function: over time, the iteration count can be increased to make it slower, so it remains resistant to brute-force search attacks even with increasing computation power.


More information about BCrypt can be found here: http://codahale.com/how-to-safely-store-a-password/ - http://phpmaster.com/why-you-should-use-bcrypt-to-hash-stored-passwords/

tl;dr: if you want to be moar secure, use bcrypt.


" How much slower is bcrypt than, say, MD5? Depends on the work factor. Using a work factor of 12, bcrypt hashes the password 'password' in about 0.3 seconds on my laptop. MD5, on the other hand, takes less than a nanosecond."


BEFORE YOU DO THIS, PLEASE CREATE A .PHP FILE WITH THIS IN IT
<?php
if (defined("CRYPT_BLOWFISH") && CRYPT_BLOWFISH) {
echo "CRYPT_BLOWFISH is enabled!";
}
else {
echo "CRYPT_BLOWFISH is not available";
}


If it is not available, please contact your host.




/includes/functions.php
Add this to the end, just before the footer message.


/**
*
* Hash 'password' using the crypt() function w/ bcrypt
* Use the first 21 characters of the MD5(strrev($salt)) as our bcrypt salt
* Return the MD5 return of this crypt() call, to maintain database functionality. The main part of our security is kept(making hashing, thus cracking, longer).

* This should always be called like hash_password_bcrypt(md5(md5($password) . $salt), $salt)
**/
function hash_password_bcrypt($password, $salt) {
//You may set this to your liking. A higher cost means it will take longer for the password to hash. 15 seems to be a good value.
$cost = 15; // must be in range 04 - 31

return md5(crypt($password, '$2y$' . $cost . '$' . substr(md5(strrev($salt)),0,21) . '$'));

}





includes/class_dm_user.php
Now..

Find this:

if ($password == md5(md5($this->fetch_field('username')) . $salt))

and replace it with this:

if ($password == $this->hash_password($this->fetch_field('username'), $salt))


(Note to self.. Why does the original code use this implicit hashing rather than the hash_password function? hash_password takes cares of md5 stuff already if it's not already md5)


Then, on the same file, replace this:
return md5($password . $salt);
with this

//No need to md5($password), since it is already md5'd above.
return hash_password_bcrypt(md5($password . $salt), $salt);





includes/functions_login.php


Find this:

$vbulletin->userinfo['password'] != iif($password AND !$md5password, md5(md5($password) . $vbulletin->userinfo['salt']), '') AND
$vbulletin->userinfo['password'] != iif($md5password, md5($md5password . $vbulletin->userinfo['salt']), '') AND
$vbulletin->userinfo['password'] != iif($md5password_utf, md5($md5password_utf . $vbulletin->userinfo['salt']), '')


And replace it with this:


$vbulletin->userinfo['password'] != iif($password AND !$md5password, hash_password_bcrypt(md5(md5($password) . $vbulletin->userinfo['salt']), $vbulletin->userinfo['salt']), '') AND
$vbulletin->userinfo['password'] != iif($md5password, hash_password_bcrypt(md5($md5password . $vbulletin->userinfo['salt']), $vbulletin->userinfo['salt']), '') AND
$vbulletin->userinfo['password'] != iif($md5password_utf, hash_password_bcrypt(md5($md5password_utf. $vbulletin->userinfo['salt']), $vbulletin->userinfo['salt']), '')



So effectively, we are hashing the password using the normal vBulletin way of
md5(md5($password) . $vbulletin->userinfo['salt'])
however after doing that, we then run hash_password_bcrypt() around it.

By doing it this way, we can now convert our old hashes to the new bcrypt method.

Create a file called "convert.php", with the contents:

<?php
require("./global.php");
set_time_limit(0);
ini_set('max_execution_time',0);

$q = $db->query_read("select userid, username, password, salt from user WHERE password != ''");

echo "Updating " . $db->num_rows($q) . " accounts.<br />\n";


while($r = $db->fetch_array($q)){
$db->query_write("UPDATE user SET password = '" . hash_password_bcrypt($r['password'], $r['salt']) . "' WHERE userid = '" . $r['userid'] . "'");
echo "Updated password for " . htmlspecialchars($r['username']) . "<br />\n";
}

echo "Finished.<br />\n";
?>


I recommend running the script in a terminal, however you may be able to run it in a browser. If you run it in the browser, it may time out!

hakkuo23
09-29-2012, 04:10 AM
Thank you for the fast reply! I love you man!

hakkuo23
09-29-2012, 04:25 AM
After I applied the changes I am unable to login, it says my password is incorrect :(

EDIT

Stupid me, there was an extra parenthesis in functions_login.php

I will respond if it works in a bit!

EDIT

No it does not work :( vBulletin v4.2.0

MentaL
09-29-2012, 10:20 AM
excellent.

MegaManSec
09-29-2012, 12:24 PM
After I applied the changes I am unable to login, it says my password is incorrect :(

EDIT

Stupid me, there was an extra parenthesis in functions_login.php

I will respond if it works in a bit!

EDIT

No it does not work :( vBulletin v4.2.0

Yes, all of your passwords would be reset, as the algorythum would change.

kh99
09-29-2012, 06:59 PM
Since your new algorithm basically encrypts the original hash, I think you could actually write a function to go through and convert all the passwords so that existing members could log in without having to change their pw. But of course when it's uninstalled there's nothing else to be done but have everyone change their pw. Either way you might want to add a warning in the description.

Anyway, nice mod, I was thinking about something like this a while back but never got around to it.

MegaManSec
09-29-2012, 07:55 PM
Since your new algorithm basically encrypts the original hash, I think you could actually write a function to go through and convert all the passwords so that existing members could log in without having to change their pw. But of course when it's uninstalled there's nothing else to be done but have everyone change their pw. Either way you might want to add a warning in the description.

Anyway, nice mod, I was thinking about something like this a while back but never got around to it.

Filip(DragonByte-Tech) and I were working on somethbing like that, but it didn't work for some strange reason.

And yeah, it can only go 'one way'.

I'll add a disclaimer to the OP

Adrian Schneider
09-29-2012, 08:54 PM
First off, thanks for trying to make vBulletin more secure. BCrypt is an excellent algorithm and much much better than md5. From my latest research, it's the industry standard.

However - you are going to all this work to properly store the password using BCrypt, but then you md5 it. As soon as you md5 it, you have lost all of that security :(.

Second - and this is just a future suggestion, you could have the system detect which password hash they are using, and check accordingly. This way you can update peoples passwords to the new system whenever they change their password (and probably mass-email everyone suggesting they do). but still authenticate the old hashes properly. Unfortunately the way it's implemented, nobody will want to use this except for starting new boards. It is possible.

Cheers

MegaManSec
09-29-2012, 08:56 PM
First off, thanks for trying to make vBulletin more secure. BCrypt is an excellent algorithm and much much better than md5. From my latest research, it's the industry standard.

However - you are going to all this work to properly store the password using BCrypt, but then you md5 it. As soon as you md5 it, you have lost all of that security :(.

Second - and this is just a future suggestion, you could have the system detect which password hash they are using, and check accordingly. This way you can update peoples passwords to the new system whenever they change their password (and probably mass-email everyone suggesting they do). but still authenticate the old hashes properly. Unfortunately the way it's implemented, nobody will want to use this except for starting new boards. It is possible.

Cheers

Er, once I MD5 it it does not lose security. if anything, it makes it more secure(by 0.00001 of a percent, though)
I'm currently crteating the 'auto-bcrypt' pwd encrypter for it. it'll be done soon.

Adrian Schneider
09-29-2012, 09:03 PM
No - once you md5 it, you have lost all of the security. You are still succeptable to md5 collissions which is md5's biggset weakness.

MegaManSec
09-29-2012, 09:05 PM
Oh. I see what you mean. I thought you were referring to hash cracking.
MD5 collisions aren't such a problem in vBulletin, really.

+ Also, it would take a lot longer to find a hash collision...

Adrian Schneider
09-29-2012, 09:07 PM
It has nothing to do with vBulletin.

If someone hacks into your server and gets your database dump, they can brute force that to find other possible passwords for your users.

The whole point of BCrypt is to make that impossible by A) being ridiculously slow, and B) being a more crytographically unique hash.

MegaManSec
09-29-2012, 09:10 PM
It has nothing to do with vBulletin.

If someone hacks into your server and gets your database dump, they can brute force that to find other possible passwords for your users.

The whole point of BCrypt is to make that impossible by A) being ridiculously slow, and B) being a more crytographically unique hash.

Well, BCrypt is not impossible to brute force, it just takes longer, as you've said.


First of all, if they cracked the MD5, what would they get?
They would get the bcrypt value.
Then what? Then they have to crack that.
That's the pointy.

MegaManSec
09-29-2012, 09:40 PM
It has nothing to do with vBulletin.

If someone hacks into your server and gets your database dump, they can brute force that to find other possible passwords for your users.

The whole point of BCrypt is to make that impossible by A) being ridiculously slow, and B) being a more crytographically unique hash.

Wait, so are you talking about:

Dictionary Attacks, or
Rainbow Tables
or hash collisions?

Hash collisions aren't useful, afaik.. they just let you login to your account(or NOT your account) with more than just one password.

Fluke667
10-02-2012, 10:22 PM
NICE :)

this rocks

Skyrider
01-23-2015, 02:58 PM
I have a feeling that after using this, the forums login/reset wise is actually much slower.

Dave
01-23-2015, 03:04 PM
I have a feeling that after using this, the forums login/reset wise is actually much slower.

Generating the password hash with BCrypt is a bit slower than MD5, but you shouldn't notice any difference on the average server.

Note: the slower the algorithm (and amount of iterations/cost), the longer it takes to brute force passwords, which is a good thing.

kh99
01-23-2015, 03:24 PM
I have a feeling that after using this, the forums login/reset wise is actually much slower.

If you look at the second piece of code posted above there's a "cost" factor which can be adjusted so that users don't see an objectionable delay.

MegaManSec
09-06-2015, 10:40 PM
Updated with a method to set passwords :)

ChiNa
09-30-2015, 01:33 PM
Great Job and a Very good Idea. I have had my friends vB4.x forums hacked where the hackers later Published all forum Users Usernames, Email, and MD5 Password Hashes out in Public. I know by facts that they hacked their way in by decrypting the Admin Password somehow. And NOT by Brute Forcing their way in. We suspected that they got in because of a Custom Skin installed on the forum that was vulnerable.

I am not saying its not possible to Hack or Decrypt a Password by Brute Forcing, But I would rather Secure my forum and Passwords a bit Extra than just leaving the doors open and Welcome them! At least they would use more time to Crack the Passwords.

Thumbs up and Well Done.

Ps, I asssume you could use the same method for vB3.8. So I hope you will create a version for vBulletin 3.8 Users too.

Eruantien
10-24-2015, 06:44 PM
I just wanted to say thank you for creating this. MD5 needs to die a strong death. Do you know how hard it would be to implement on vb3? I have a client that uses it and I would love to get them away from MD5.

Dave
10-24-2015, 07:38 PM
I just wanted to say thank you for creating this. MD5 needs to die a strong death. Do you know how hard it would be to implement on vb3? I have a client that uses it and I would love to get them away from MD5.

OP's explanation should work for vBulletin 3 as well since the code structure is almost the same.

EvoDarrenshan
01-06-2016, 05:16 PM
Is it me or does it take longer to log in?

Dave
01-06-2016, 05:18 PM
It's a slower algorithm, but you should definitely not notice it. How slow are we talking about? Any other plugins which could affect it?

EvoDarrenshan
01-06-2016, 06:13 PM
It's a slower algorithm, but you should definitely not notice it. How slow are we talking about? Any other plugins which could affect it?

I noticed it soon as i done the change like 1-3 seconds difference also when users register it doesn't set the bcrypt algorithm...


Deprecated: preg_replace(): The /e modifier is deprecated, use preg_replace_callback instead in /home/site/public_html/includes/functions_login.php on line 167

Deprecated: preg_replace(): The /e modifier is deprecated, use preg_replace_callback instead in /home/site/public_html/includes/functions.php on line 5131
REDIRECTING...
Thank you for logging in, admin.
Click here if your browser does not automatically redirect you.
X VBULLETIN 4.2.1 DEBUG INFORMATION
Page Generation 5.55788 seconds Memory Usage 9,080KB Queries Executed 14 (?)
More Information
Template Usage (16):
(1)STANDARD_REDIRECT
(1)ad_footer_end
(1)ad_footer_start
(1)ad_global_above_footer
(1)ad_global_below_navbar
(1)ad_global_header1
(1)ad_global_header2
(1)ad_navbar_below
(1)footer
(1)gobutton
(1)header
(1)headinclude
(1)headinclude_bottom
(1)navbar_notifications_menubit
(1)spacer_close
(1)spacer_open
Phrase Groups Available (1):
global
Included Files (20):
./login.php
./global.php
./includes/class_bootstrap.php
./includes/init.php
./includes/class_core.php
./includes/functions.php
./includes/functions_navigation.php
./includes/class_hook.php
./includes/class_bootstrap_framework.php
./vb/vb.php
./vb/phrase.php
./includes/class_friendly_url.php
./includes/functions_facebook.php
./includes/functions_login.php
./includes/functions_misc.php
./includes/functions_notice.php
Hooks Called (33):
init_startup
database_pre_fetch_array
database_post_fetch_array
fetch_userinfo_query
fetch_musername
fetch_userinfo
global_bootstrap_init_start
global_bootstrap_init_complete
cache_permissions
load_show_variables
load_forum_show_variables
global_state_check
global_bootstrap_complete
global_start
style_fetch
global_setup_complete
login_verify_success
fetch_session_complete
login_process
login_redirect
redirect_generic
cache_templates
cache_templates_process
template_register_var
template_render_output
fetch_template_start
fetch_template_complete
parse_templates
notices_check_start
friendlyurl_resolve_class
friendlyurl_geturl
notifications_list
process_templates_complete

Dave
01-06-2016, 06:32 PM
Well my only guess is that you made a mistake somewhere, double check the changes you did and make sure it matches the ones of OP.

EvoDarrenshan
01-06-2016, 06:38 PM
Well my only guess is that you made a mistake somewhere, double check the changes you did and make sure it matches the ones of OP.

I've followed it step by step no mistake made, I disabled plugins and generated a result above. Should i revert?

---
I reverted login time gone back to normal. Do not use this if your board is 10k members plus.

Dave
01-07-2016, 12:52 PM
I've followed it step by step no mistake made, I disabled plugins and generated a result above. Should i revert?

---
I reverted login time gone back to normal. Do not use this if your board is 10k members plus.

I've installed this on boards with 100k+ members, this is not something caused by the script.