Bcrypt broken in PHP? Can easily include any malicious payload
-
27-10-2019 - |
Question
Salt: can be anything.
Work factor: can be anything.
All of the following generate the same hash!
$pad = base64_decode('/gB=');
$data = array(
'LegitimatePayload',
'LaterSwitchedToMaliciousPayload',
'Abracadabra',
'hatIsGoingOn',
'CanBeAlmostAnything',
);
foreach($data as $str){
echo crypt($pad.$str, '$2a$04$AnySaltHere')."<br>\n";
}
Output:
$2a$04$AnySaltHere$$$$$$$$$$.m/QKi19jyBmSuP2VMcVuFRw.weCNRBa
$2a$04$AnySaltHere$$$$$$$$$$.m/QKi19jyBmSuP2VMcVuFRw.weCNRBa
$2a$04$AnySaltHere$$$$$$$$$$.m/QKi19jyBmSuP2VMcVuFRw.weCNRBa
$2a$04$AnySaltHere$$$$$$$$$$.m/QKi19jyBmSuP2VMcVuFRw.weCNRBa
$2a$04$AnySaltHere$$$$$$$$$$.m/QKi19jyBmSuP2VMcVuFRw.weCNRBa
$2a$04$AnySaltHere$$$$$$$$$$.m/QKi19jyBmSuP2VMcVuFRw.weCNRBa
Edit:
Here is a string that has the same first two bytes but has a different hash:
base64_decode('/gBQyoK71jVY/J7QuBNJuFdxyf2eTBCs42chkx6ZvpJYszpzg===')
If php stopped at first NUL byte, then how do you explain this?
Solution
All your strings have a prefix that will - when run through base64_decode
- result in a 0xfe
character and a 0x00
character with the extra - varying - characters after the 0x00. Since standard crypt will stop at a 0x00
character, all your crypt calls only encrypt the 0xfe
character.
You can verify it by just calling
echo crypt("\376", '$2a$04$AnySaltHere')."<br>\n";
which will give the same result.
I'm assuming you used base64_decode
by mistake meaning to actually call base64_encode
.
Edit: As Roman points out, the string
"/gBQyoK71jVY/J7QuBNJuFdxyf2eTBCs42chkx6ZvpJYszpzg==="
will actually - despite the same prefix - crypt to something else entirely. This is due to that string actually being invalid base64 and base64_decode returning false. That results in the string crypt'ing to the same hash as the empty string does instead.
OTHER TIPS
You're not providing any valid base64 encoded strings, so base64_decode will probably just return false for all of your test cases, and thus it will encrypt them all the same. Why are you using base64_decode anyway?
You probably want base64_encode
and not base64_decode
. the reason it all returns the same is because the result is always false.