php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Sec Bug #64449 crypt doesn't fail on "$" in CRYPT_DES salt
Submitted: 2013-03-18 22:25 UTC Modified: 2020-06-24 12:07 UTC
From: brad at bradconte dot com Assigned: nikic (profile)
Status: Closed Package: *Encryption and hash functions
PHP Version: 5.4.13 OS: Linux
Private report: No CVE-ID: None
Welcome back! If you're the original bug submitter, here's where you can edit the bug or add additional notes.
If you forgot your password, you can retrieve your password here.
Password:
Status:
Package:
Bug Type:
Summary:
From: brad at bradconte dot com
New email:
PHP Version: OS:

 

 [2013-03-18 22:25 UTC] brad at bradconte dot com
Description:
------------
---
From manual page: http://www.php.net/function.crypt#refsect1-function.crypt-description
---

The PHP documentation states that crypt() will "return a failure" if the salt contains an invalid character. For CRYPT_DES, the character "$" (ie, dollar-sign) is not listed as a valid character. However, an input salt with the "$" character still results in valid CRYPT_DES hash output instead of a failure. The documentation and the function's behavior are inconsistent.

Note that the glibc crypt() function fails when "$" is provided, so the documentation is probably correct and it is probably the implementation that is at fault.

Note that allowing "$" for CRYPT_DES has an interesting security implication: Since other hash algorithm salt formats begin with "$", a mistake on the programmer's part in selecting the desired hash algorithm can cause a silent downgrade to the undesirable hash algorithm CRYPT_DES. Examples:

* Valid salt strings for unsupported salt algorithms may get downgraded to CRYPT_DES. For example, in PHP 5.2 (pre-CRYPT_BLOW_FISH support) the CRYPT_BLOWFISH salt string '$2a$abcdefghijklmnopqrstuv' will be silently downgraded to CRYPT_DES.

* An invalid salt string for another algorithm may get downgraded to CRYPT_DES. For example the attempted CRYPT_SHA256 string '$6 $1234567890123456789012345678901234567890123' (notice the space) will get downgraded to CRYPT_DES.

This downgrade will only be caught by the programmer comparing output format and length to the expected format. Since the documentation says CRYPT_DES will return a failure on a salt with a "$", the programmer could be led astray and not thoroughly examine the result. If crypt() failed instead, the programmer's mistake would be much more obvious.


Test script:
---------------
/* PHP 5.2 */
if (crypt('password', '$2') == crypt('password', '$2a$11$07fc1ae880d703a7a83424)
    echo "TRIPLE_DES selection";

/* PHP 5.4 */
crypt('password', '$2'); /* Outputs same as above. */

Expected result:
----------------
I expect crypt('password', '$2') to return a failure.

Actual result:
--------------
crypt('password', '$2') returns a valid hash.

Patches

Pull Requests

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2015-09-08 00:55 UTC] cmb@php.net
-Status: Open +Status: Verified -Type: Bug +Type: Security -Private report: No +Private report: Yes
 [2015-09-08 00:55 UTC] cmb@php.net
That appears to be a security issue, at least in PHP 5:
<https://3v4l.org/l4Uij>.
 [2020-06-24 12:07 UTC] nikic@php.net
-Status: Verified +Status: Closed -Assigned To: +Assigned To: nikic
 [2020-06-24 12:07 UTC] nikic@php.net
The specific examples are rejected since PHP 7, and crypt DES fallback is completely gone in PHP 8, so I'm closing this.
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Fri Dec 27 10:01:28 2024 UTC