We launched new forums in March 2019—join us there. In a hurry for help with your website? Get Help Now!
    • 44909
    • 13 Posts
    Hi!

    One of the servers I tested modx with had mbstring.func_overload = 2, thus exchanging a lot of string functions with the mb_* counterpart.

    I noticed that if I created a new user, that he was not able to login into the manager: "The username or password you entered is incorrect. Please check the username, re-type the password, and try again."

    When looking at the code, I found out, that the modx hash function caluclates different hashes based on php's internal encoding.

    Here's a snip from the hash function in modpbkdf2.class.php:
    $iterations = (integer) $this->getOption('iterations', $options, 1000);
    $derivedKeyLength = (integer) $this->getOption('derived_key_length', $options, 32);
    $algorithm = $this->getOption('algorithm', $options, 'sha256');
    
    $hashLength = strlen(hash($algorithm, null, true));
    $keyBlocks = ceil($derivedKeyLength / $hashLength);
    


    $hashLength should be length in bytes, therefor the raw output is used.
    Now, if mbstring.func_overload ist active, strlen will be exchanged with mb_strlen.

    If furthermore mb_internal_encoding ist set to UTF-8, the function might return a smaller number, because the hash's raw output can contain byte sequences that will be recognized as multibyte characters.

    This wouldn't be a big issue, if the internal encoding is the same for every use of modx's hash function. But it seems that this is not the case.

    Here is what happens when the hash function is called inside the manager whilst changing a user's password:

    D:\webroot\modx_1\core\model\modx\hashing\modpbkdf2.class.php:34
    debug_backtrace:
    Array
    (
        [0] => Array
            (
                [file] => D:\webroot\modx_1\core\model\modx\moduser.class.php
                [line] => 60
                [function] => hash
                [class] => modPBKDF2
                [type] => ->
            )
    
        [1] => Array
            (
                [file] => D:\webroot\modx_1\core\model\modx\processors\security\user\_validation.php
                [line] => 83
                [function] => set
                [class] => modUser
                [type] => ->
            )
    
        [2] => Array
            (
                [file] => D:\webroot\modx_1\core\model\modx\processors\security\user\_validation.php
                [line] => 26
                [function] => checkPassword
                [class] => modUserValidation
                [type] => ->
            )
    
        [3] => Array
            (
                [file] => D:\webroot\modx_1\core\model\modx\processors\security\user\update.class.php
                [line] => 96
                [function] => validate
                [class] => modUserValidation
                [type] => ->
            )
    
        [4] => Array
            (
                [file] => D:\webroot\modx_1\core\model\modx\modprocessor.class.php
                [line] => 788
                [function] => beforeSave
                [class] => modUserUpdateProcessor
                [type] => ->
            )
    
        [5] => Array
            (
                [file] => D:\webroot\modx_1\core\model\modx\modprocessor.class.php
                [line] => 173
                [function] => process
                [class] => modObjectUpdateProcessor
                [type] => ->
            )
    
        [6] => Array
            (
                [file] => D:\webroot\modx_1\core\model\modx\modx.class.php
                [line] => 1632
                [function] => run
                [class] => modProcessor
                [type] => ->
            )
    
        [7] => Array
            (
                [file] => D:\webroot\modx_1\core\model\modx\modconnectorresponse.class.php
                [line] => 131
                [function] => runProcessor
                [class] => modX
                [type] => ->
            )
    
        [8] => Array
            (
                [file] => D:\webroot\modx_1\core\model\modx\modconnectorrequest.class.php
                [line] => 79
                [function] => outputContent
                [class] => modConnectorResponse
                [type] => ->
            )
    
        [9] => Array
            (
                [file] => D:\webroot\modx_1\core\model\modx\modconnectorrequest.class.php
                [line] => 66
                [function] => prepareResponse
                [class] => modConnectorRequest
                [type] => ->
            )
    
        [10] => Array
            (
                [file] => D:\webroot\modx_1\connectors\security\user.php
                [line] => 3
                [function] => handleRequest
                [class] => modConnectorRequest
                [type] => ->
            )
    
    )
    
    func args:
    Array
    (
        [0] => modx12345
        [1] => Array
            (
                [salt] => 9bb1074ed4aa029c5ca162212757533f
            )
    
    )
    
    mb_internal_encoding:
    ISO-8859-1
    hashLength:
    32
    
    derived key: lomluVOqpHWOPoLKSf7+XDBjNdiOLiQqhMM9da75F7s=
    


    Here's the same debug output when trying to log in:

    D:\webroot\modx_1\core\model\modx\hashing\modpbkdf2.class.php:34
    debug_backtrace:
    Array
    (
        [0] => Array
            (
                [file] => D:\webroot\modx_1\core\model\modx\moduser.class.php
                [line] => 237
                [function] => hash
                [class] => modPBKDF2
                [type] => ->
            )
    
        [1] => Array
            (
                [file] => D:\webroot\modx_1\core\model\modx\processors\security\login.php
                [line] => 143
                [function] => passwordMatches
                [class] => modUser
                [type] => ->
            )
    
        [2] => Array
            (
                [file] => D:\webroot\modx_1\core\model\modx\modprocessor.class.php
                [line] => 343
                [args] => Array
                    (
                        [0] => D:\webroot\modx_1\core\model\modx\processors\security\login.php
                    )
    
                [function] => include
            )
    
        [3] => Array
            (
                [file] => D:\webroot\modx_1\core\model\modx\modprocessor.class.php
                [line] => 173
                [function] => process
                [class] => modDeprecatedProcessor
                [type] => ->
            )
    
        [4] => Array
            (
                [file] => D:\webroot\modx_1\core\model\modx\modx.class.php
                [line] => 1632
                [function] => run
                [class] => modProcessor
                [type] => ->
            )
    
        [5] => Array
            (
                [file] => D:\webroot\modx_1\manager\controllers\default\security\login.class.php
                [line] => 189
                [function] => runProcessor
                [class] => modX
                [type] => ->
            )
    
        [6] => Array
            (
                [file] => D:\webroot\modx_1\manager\controllers\default\security\login.class.php
                [line] => 157
                [function] => handleLogin
                [class] => SecurityLoginManagerController
                [type] => ->
            )
    
        [7] => Array
            (
                [file] => D:\webroot\modx_1\manager\controllers\default\security\login.class.php
                [line] => 40
                [function] => handlePost
                [class] => SecurityLoginManagerController
                [type] => ->
            )
    
        [8] => Array
            (
                [file] => D:\webroot\modx_1\core\model\modx\modmanagercontroller.class.php
                [line] => 143
                [function] => process
                [class] => SecurityLoginManagerController
                [type] => ->
            )
    
        [9] => Array
            (
                [file] => D:\webroot\modx_1\core\model\modx\modmanagerresponse.class.php
                [line] => 121
                [function] => render
                [class] => modManagerController
                [type] => ->
            )
    
        [10] => Array
            (
                [file] => D:\webroot\modx_1\core\model\modx\modmanagerrequest.class.php
                [line] => 176
                [function] => outputContent
                [class] => modManagerResponse
                [type] => ->
            )
    
        [11] => Array
            (
                [file] => D:\webroot\modx_1\core\model\modx\modmanagerrequest.class.php
                [line] => 124
                [function] => prepareResponse
                [class] => modManagerRequest
                [type] => ->
            )
    
        [12] => Array
            (
                [file] => D:\webroot\modx_1\manager\index.php
                [line] => 75
                [function] => handleRequest
                [class] => modManagerRequest
                [type] => ->
            )
    
    )
    
    func args:
    Array
    (
        [0] => modx12345
        [1] => Array
            (
                [salt] => 9bb1074ed4aa029c5ca162212757533f
            )
    
    )
    
    mb_internal_encoding:
    UTF-8
    hashLength:
    25
    
    derived key: lomluVOqpHWOPoLKSf7+XDBjNdiOLiQqhMM9da75F7vnb8EFxz0=
    


    Obviously the internal encoding differs between the manager's login page and the manager itself. Therefor newly created users can not login.

    I don't know if modx is prepared for being used with mbstring.func_overload. If yes, internal encoding should be equal around the whole site. If not, func_overload should be checked during install, maybe even at runtime.

    A quick fix would be using mb_strlen():

    $hashLength = mb_strlen(hash($algorithm, null, true), '8bit');

    This always returns the length in bytes.

    Greetings

    Nico

    PS: Tested on Revo 2.2.9, PHP 5.4.18



    [ed. note: scope_v24 last edited this post 10 years, 8 months ago.]