VYPR
High severity7.5NVD Advisory· Published Feb 22, 2016· Updated May 6, 2026

CVE-2015-5267

CVE-2015-5267

Description

lib/moodlelib.php in Moodle through 2.6.11, 2.7.x before 2.7.10, 2.8.x before 2.8.8, and 2.9.x before 2.9.2 relies on the PHP mt_rand function to implement the random_string and complex_random_string functions, which makes it easier for remote attackers to predict password-recovery tokens via a brute-force approach.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
moodle/moodlePackagist
< 2.7.102.7.10
moodle/moodlePackagist
>= 2.8.0, < 2.8.82.8.8
moodle/moodlePackagist
>= 2.9.0, < 2.9.22.9.2

Affected products

21
  • Moodle/Moodle21 versions
    cpe:2.3:a:moodle:moodle:*:*:*:*:*:*:*:*+ 20 more
    • cpe:2.3:a:moodle:moodle:*:*:*:*:*:*:*:*range: <=2.6.11
    • cpe:2.3:a:moodle:moodle:2.7.0:*:*:*:*:*:*:*
    • cpe:2.3:a:moodle:moodle:2.7.1:*:*:*:*:*:*:*
    • cpe:2.3:a:moodle:moodle:2.7.2:*:*:*:*:*:*:*
    • cpe:2.3:a:moodle:moodle:2.7.3:*:*:*:*:*:*:*
    • cpe:2.3:a:moodle:moodle:2.7.4:*:*:*:*:*:*:*
    • cpe:2.3:a:moodle:moodle:2.7.5:*:*:*:*:*:*:*
    • cpe:2.3:a:moodle:moodle:2.7.6:*:*:*:*:*:*:*
    • cpe:2.3:a:moodle:moodle:2.7.7:*:*:*:*:*:*:*
    • cpe:2.3:a:moodle:moodle:2.7.8:*:*:*:*:*:*:*
    • cpe:2.3:a:moodle:moodle:2.7.9:*:*:*:*:*:*:*
    • cpe:2.3:a:moodle:moodle:2.8.0:*:*:*:*:*:*:*
    • cpe:2.3:a:moodle:moodle:2.8.1:*:*:*:*:*:*:*
    • cpe:2.3:a:moodle:moodle:2.8.2:*:*:*:*:*:*:*
    • cpe:2.3:a:moodle:moodle:2.8.3:*:*:*:*:*:*:*
    • cpe:2.3:a:moodle:moodle:2.8.4:*:*:*:*:*:*:*
    • cpe:2.3:a:moodle:moodle:2.8.5:*:*:*:*:*:*:*
    • cpe:2.3:a:moodle:moodle:2.8.6:*:*:*:*:*:*:*
    • cpe:2.3:a:moodle:moodle:2.8.7:*:*:*:*:*:*:*
    • cpe:2.3:a:moodle:moodle:2.9.0:*:*:*:*:*:*:*
    • cpe:2.3:a:moodle:moodle:2.9.1:*:*:*:*:*:*:*

Patches

4
5337b2295237

MDL-50860 core: improve creation of random strings

https://github.com/moodle/moodlePetr SkodaAug 18, 2015via ghsa
2 files changed · +144 3
  • lib/moodlelib.php+48 3 modified
    @@ -7832,14 +7832,16 @@ function count_letters($string) {
      * @param int $length The length of the string to be created.
      * @return string
      */
    -function random_string ($length=15) {
    +function random_string($length=15) {
    +    $randombytes = random_bytes_emulate($length);
         $pool  = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
         $pool .= 'abcdefghijklmnopqrstuvwxyz';
         $pool .= '0123456789';
         $poollen = strlen($pool);
         $string = '';
         for ($i = 0; $i < $length; $i++) {
    -        $string .= substr($pool, (mt_rand()%($poollen)), 1);
    +        $rand = ord($randombytes[$i]);
    +        $string .= substr($pool, ($rand%($poollen)), 1);
         }
         return $string;
     }
    @@ -7860,13 +7862,56 @@ function complex_random_string($length=null) {
         if ($length===null) {
             $length = floor(rand(24, 32));
         }
    +    $randombytes = random_bytes_emulate($length);
         $string = '';
         for ($i = 0; $i < $length; $i++) {
    -        $string .= $pool[(mt_rand()%$poollen)];
    +        $rand = ord($randombytes[$i]);
    +        $string .= $pool[($rand%$poollen)];
         }
         return $string;
     }
     
    +/**
    + * Try to generates cryptographically secure pseudo-random bytes.
    + *
    + * Note this is achieved by fallbacking between:
    + *  - PHP 7 random_bytes().
    + *  - OpenSSL openssl_random_pseudo_bytes().
    + *  - In house random generator getting its entropy from various, hard to guess, pseudo-random sources.
    + *
    + * @param int $length requested length in bytes
    + * @return string binary data
    + */
    +function random_bytes_emulate($length) {
    +    global $CFG;
    +    if ($length <= 0) {
    +        debugging('Invalid random bytes length', DEBUG_DEVELOPER);
    +        return '';
    +    }
    +    if (function_exists('random_bytes')) {
    +        // Use PHP 7 goodness.
    +        $hash = @random_bytes($length);
    +        if ($hash !== false) {
    +            return $hash;
    +        }
    +    }
    +    if (function_exists('openssl_random_pseudo_bytes')) {
    +        // For PHP 5.3 and later with openssl extension.
    +        $hash = openssl_random_pseudo_bytes($length);
    +        if ($hash !== false) {
    +            return $hash;
    +        }
    +    }
    +
    +    // Bad luck, there is no reliable random generator, let's just hash some unique stuff that is hard to guess.
    +    $hash = sha1(serialize($CFG) . serialize($_SERVER) . microtime(true) . uniqid('', true), true);
    +    // NOTE: the last param in sha1() is true, this means we are getting 20 bytes, not 40 chars as usual.
    +    if ($length <= 20) {
    +        return substr($hash, 0, $length);
    +    }
    +    return $hash . random_bytes_emulate($length - 20);
    +}
    +
     /**
      * Given some text (which may contain HTML) and an ideal length,
      * this function truncates the text neatly on a word boundary if possible
    
  • lib/tests/moodlelib_test.php+96 0 modified
    @@ -2918,4 +2918,100 @@ public function test_getremoteaddr() {
             $_SERVER['HTTP_X_FORWARDED_FOR'] = $xforwardedfor;
     
         }
    +
    +    /*
    +     * Test emulation of random_bytes() function.
    +     */
    +    public function test_random_bytes_emulate() {
    +        $result = random_bytes_emulate(10);
    +        $this->assertSame(10, strlen($result));
    +        $this->assertnotSame($result, random_bytes_emulate(10));
    +
    +        $result = random_bytes_emulate(21);
    +        $this->assertSame(21, strlen($result));
    +        $this->assertnotSame($result, random_bytes_emulate(21));
    +
    +        $result = random_bytes_emulate(666);
    +        $this->assertSame(666, strlen($result));
    +
    +        $this->assertDebuggingNotCalled();
    +
    +        $result = random_bytes_emulate(0);
    +        $this->assertSame('', $result);
    +        $this->assertDebuggingCalled();
    +
    +        $result = random_bytes_emulate(-1);
    +        $this->assertSame('', $result);
    +        $this->assertDebuggingCalled();
    +    }
    +
    +    /**
    +     * Test function for creation of random strings.
    +     */
    +    public function test_random_string() {
    +        $pool = 'a-zA-Z0-9';
    +
    +        $result = random_string(10);
    +        $this->assertSame(10, strlen($result));
    +        $this->assertRegExp('/^[' . $pool . ']+$/', $result);
    +        $this->assertNotSame($result, random_string(10));
    +
    +        $result = random_string(21);
    +        $this->assertSame(21, strlen($result));
    +        $this->assertRegExp('/^[' . $pool . ']+$/', $result);
    +        $this->assertNotSame($result, random_string(21));
    +
    +        $result = random_string(666);
    +        $this->assertSame(666, strlen($result));
    +        $this->assertRegExp('/^[' . $pool . ']+$/', $result);
    +
    +        $result = random_string();
    +        $this->assertSame(15, strlen($result));
    +        $this->assertRegExp('/^[' . $pool . ']+$/', $result);
    +
    +        $this->assertDebuggingNotCalled();
    +
    +        $result = random_string(0);
    +        $this->assertSame('', $result);
    +        $this->assertDebuggingCalled();
    +
    +        $result = random_string(-1);
    +        $this->assertSame('', $result);
    +        $this->assertDebuggingCalled();
    +    }
    +
    +    /**
    +     * Test function for creation of complex random strings.
    +     */
    +    public function test_complex_random_string() {
    +        $pool = preg_quote('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789`~!@#%^&*()_+-=[];,./<>?:{} ', '/');
    +
    +        $result = complex_random_string(10);
    +        $this->assertSame(10, strlen($result));
    +        $this->assertRegExp('/^[' . $pool . ']+$/', $result);
    +        $this->assertNotSame($result, complex_random_string(10));
    +
    +        $result = complex_random_string(21);
    +        $this->assertSame(21, strlen($result));
    +        $this->assertRegExp('/^[' . $pool . ']+$/', $result);
    +        $this->assertNotSame($result, complex_random_string(21));
    +
    +        $result = complex_random_string(666);
    +        $this->assertSame(666, strlen($result));
    +        $this->assertRegExp('/^[' . $pool . ']+$/', $result);
    +
    +        $result = complex_random_string();
    +        $this->assertEquals(28, strlen($result), '', 4); // Expected length is 24 - 32.
    +        $this->assertRegExp('/^[' . $pool . ']+$/', $result);
    +
    +        $this->assertDebuggingNotCalled();
    +
    +        $result = complex_random_string(0);
    +        $this->assertSame('', $result);
    +        $this->assertDebuggingCalled();
    +
    +        $result = complex_random_string(-1);
    +        $this->assertSame('', $result);
    +        $this->assertDebuggingCalled();
    +    }
     }
    
6e8224365ffc

MDL-50860 core: improve creation of random strings

https://github.com/moodle/moodlePetr SkodaAug 18, 2015via ghsa
2 files changed · +144 3
  • lib/moodlelib.php+48 3 modified
    @@ -7787,14 +7787,16 @@ function count_letters($string) {
      * @param int $length The length of the string to be created.
      * @return string
      */
    -function random_string ($length=15) {
    +function random_string($length=15) {
    +    $randombytes = random_bytes_emulate($length);
         $pool  = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
         $pool .= 'abcdefghijklmnopqrstuvwxyz';
         $pool .= '0123456789';
         $poollen = strlen($pool);
         $string = '';
         for ($i = 0; $i < $length; $i++) {
    -        $string .= substr($pool, (mt_rand()%($poollen)), 1);
    +        $rand = ord($randombytes[$i]);
    +        $string .= substr($pool, ($rand%($poollen)), 1);
         }
         return $string;
     }
    @@ -7815,13 +7817,56 @@ function complex_random_string($length=null) {
         if ($length===null) {
             $length = floor(rand(24, 32));
         }
    +    $randombytes = random_bytes_emulate($length);
         $string = '';
         for ($i = 0; $i < $length; $i++) {
    -        $string .= $pool[(mt_rand()%$poollen)];
    +        $rand = ord($randombytes[$i]);
    +        $string .= $pool[($rand%$poollen)];
         }
         return $string;
     }
     
    +/**
    + * Try to generates cryptographically secure pseudo-random bytes.
    + *
    + * Note this is achieved by fallbacking between:
    + *  - PHP 7 random_bytes().
    + *  - OpenSSL openssl_random_pseudo_bytes().
    + *  - In house random generator getting its entropy from various, hard to guess, pseudo-random sources.
    + *
    + * @param int $length requested length in bytes
    + * @return string binary data
    + */
    +function random_bytes_emulate($length) {
    +    global $CFG;
    +    if ($length <= 0) {
    +        debugging('Invalid random bytes length', DEBUG_DEVELOPER);
    +        return '';
    +    }
    +    if (function_exists('random_bytes')) {
    +        // Use PHP 7 goodness.
    +        $hash = @random_bytes($length);
    +        if ($hash !== false) {
    +            return $hash;
    +        }
    +    }
    +    if (function_exists('openssl_random_pseudo_bytes')) {
    +        // For PHP 5.3 and later with openssl extension.
    +        $hash = openssl_random_pseudo_bytes($length);
    +        if ($hash !== false) {
    +            return $hash;
    +        }
    +    }
    +
    +    // Bad luck, there is no reliable random generator, let's just hash some unique stuff that is hard to guess.
    +    $hash = sha1(serialize($CFG) . serialize($_SERVER) . microtime(true) . uniqid('', true), true);
    +    // NOTE: the last param in sha1() is true, this means we are getting 20 bytes, not 40 chars as usual.
    +    if ($length <= 20) {
    +        return substr($hash, 0, $length);
    +    }
    +    return $hash . random_bytes_emulate($length - 20);
    +}
    +
     /**
      * Given some text (which may contain HTML) and an ideal length,
      * this function truncates the text neatly on a word boundary if possible
    
  • lib/tests/moodlelib_test.php+96 0 modified
    @@ -2853,4 +2853,100 @@ public function test_getremoteaddr() {
             $_SERVER['HTTP_X_FORWARDED_FOR'] = $xforwardedfor;
     
         }
    +
    +    /*
    +     * Test emulation of random_bytes() function.
    +     */
    +    public function test_random_bytes_emulate() {
    +        $result = random_bytes_emulate(10);
    +        $this->assertSame(10, strlen($result));
    +        $this->assertnotSame($result, random_bytes_emulate(10));
    +
    +        $result = random_bytes_emulate(21);
    +        $this->assertSame(21, strlen($result));
    +        $this->assertnotSame($result, random_bytes_emulate(21));
    +
    +        $result = random_bytes_emulate(666);
    +        $this->assertSame(666, strlen($result));
    +
    +        $this->assertDebuggingNotCalled();
    +
    +        $result = random_bytes_emulate(0);
    +        $this->assertSame('', $result);
    +        $this->assertDebuggingCalled();
    +
    +        $result = random_bytes_emulate(-1);
    +        $this->assertSame('', $result);
    +        $this->assertDebuggingCalled();
    +    }
    +
    +    /**
    +     * Test function for creation of random strings.
    +     */
    +    public function test_random_string() {
    +        $pool = 'a-zA-Z0-9';
    +
    +        $result = random_string(10);
    +        $this->assertSame(10, strlen($result));
    +        $this->assertRegExp('/^[' . $pool . ']+$/', $result);
    +        $this->assertNotSame($result, random_string(10));
    +
    +        $result = random_string(21);
    +        $this->assertSame(21, strlen($result));
    +        $this->assertRegExp('/^[' . $pool . ']+$/', $result);
    +        $this->assertNotSame($result, random_string(21));
    +
    +        $result = random_string(666);
    +        $this->assertSame(666, strlen($result));
    +        $this->assertRegExp('/^[' . $pool . ']+$/', $result);
    +
    +        $result = random_string();
    +        $this->assertSame(15, strlen($result));
    +        $this->assertRegExp('/^[' . $pool . ']+$/', $result);
    +
    +        $this->assertDebuggingNotCalled();
    +
    +        $result = random_string(0);
    +        $this->assertSame('', $result);
    +        $this->assertDebuggingCalled();
    +
    +        $result = random_string(-1);
    +        $this->assertSame('', $result);
    +        $this->assertDebuggingCalled();
    +    }
    +
    +    /**
    +     * Test function for creation of complex random strings.
    +     */
    +    public function test_complex_random_string() {
    +        $pool = preg_quote('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789`~!@#%^&*()_+-=[];,./<>?:{} ', '/');
    +
    +        $result = complex_random_string(10);
    +        $this->assertSame(10, strlen($result));
    +        $this->assertRegExp('/^[' . $pool . ']+$/', $result);
    +        $this->assertNotSame($result, complex_random_string(10));
    +
    +        $result = complex_random_string(21);
    +        $this->assertSame(21, strlen($result));
    +        $this->assertRegExp('/^[' . $pool . ']+$/', $result);
    +        $this->assertNotSame($result, complex_random_string(21));
    +
    +        $result = complex_random_string(666);
    +        $this->assertSame(666, strlen($result));
    +        $this->assertRegExp('/^[' . $pool . ']+$/', $result);
    +
    +        $result = complex_random_string();
    +        $this->assertEquals(28, strlen($result), '', 4); // Expected length is 24 - 32.
    +        $this->assertRegExp('/^[' . $pool . ']+$/', $result);
    +
    +        $this->assertDebuggingNotCalled();
    +
    +        $result = complex_random_string(0);
    +        $this->assertSame('', $result);
    +        $this->assertDebuggingCalled();
    +
    +        $result = complex_random_string(-1);
    +        $this->assertSame('', $result);
    +        $this->assertDebuggingCalled();
    +    }
     }
    
e4ac3879c2d1

MDL-50860 core: improve creation of random strings

https://github.com/moodle/moodlePetr SkodaAug 18, 2015via ghsa
2 files changed · +144 3
  • lib/moodlelib.php+48 3 modified
    @@ -7558,14 +7558,16 @@ function count_letters($string) {
      * @param int $length The length of the string to be created.
      * @return string
      */
    -function random_string ($length=15) {
    +function random_string($length=15) {
    +    $randombytes = random_bytes_emulate($length);
         $pool  = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
         $pool .= 'abcdefghijklmnopqrstuvwxyz';
         $pool .= '0123456789';
         $poollen = strlen($pool);
         $string = '';
         for ($i = 0; $i < $length; $i++) {
    -        $string .= substr($pool, (mt_rand()%($poollen)), 1);
    +        $rand = ord($randombytes[$i]);
    +        $string .= substr($pool, ($rand%($poollen)), 1);
         }
         return $string;
     }
    @@ -7586,13 +7588,56 @@ function complex_random_string($length=null) {
         if ($length===null) {
             $length = floor(rand(24, 32));
         }
    +    $randombytes = random_bytes_emulate($length);
         $string = '';
         for ($i = 0; $i < $length; $i++) {
    -        $string .= $pool[(mt_rand()%$poollen)];
    +        $rand = ord($randombytes[$i]);
    +        $string .= $pool[($rand%$poollen)];
         }
         return $string;
     }
     
    +/**
    + * Try to generates cryptographically secure pseudo-random bytes.
    + *
    + * Note this is achieved by fallbacking between:
    + *  - PHP 7 random_bytes().
    + *  - OpenSSL openssl_random_pseudo_bytes().
    + *  - In house random generator getting its entropy from various, hard to guess, pseudo-random sources.
    + *
    + * @param int $length requested length in bytes
    + * @return string binary data
    + */
    +function random_bytes_emulate($length) {
    +    global $CFG;
    +    if ($length <= 0) {
    +        debugging('Invalid random bytes length', DEBUG_DEVELOPER);
    +        return '';
    +    }
    +    if (function_exists('random_bytes')) {
    +        // Use PHP 7 goodness.
    +        $hash = @random_bytes($length);
    +        if ($hash !== false) {
    +            return $hash;
    +        }
    +    }
    +    if (function_exists('openssl_random_pseudo_bytes')) {
    +        // For PHP 5.3 and later with openssl extension.
    +        $hash = openssl_random_pseudo_bytes($length);
    +        if ($hash !== false) {
    +            return $hash;
    +        }
    +    }
    +
    +    // Bad luck, there is no reliable random generator, let's just hash some unique stuff that is hard to guess.
    +    $hash = sha1(serialize($CFG) . serialize($_SERVER) . microtime(true) . uniqid('', true), true);
    +    // NOTE: the last param in sha1() is true, this means we are getting 20 bytes, not 40 chars as usual.
    +    if ($length <= 20) {
    +        return substr($hash, 0, $length);
    +    }
    +    return $hash . random_bytes_emulate($length - 20);
    +}
    +
     /**
      * Given some text (which may contain HTML) and an ideal length,
      * this function truncates the text neatly on a word boundary if possible
    
  • lib/tests/moodlelib_test.php+96 0 modified
    @@ -2906,4 +2906,100 @@ public function test_getremoteaddr() {
             $_SERVER['HTTP_X_FORWARDED_FOR'] = $xforwardedfor;
     
         }
    +
    +    /*
    +     * Test emulation of random_bytes() function.
    +     */
    +    public function test_random_bytes_emulate() {
    +        $result = random_bytes_emulate(10);
    +        $this->assertSame(10, strlen($result));
    +        $this->assertnotSame($result, random_bytes_emulate(10));
    +
    +        $result = random_bytes_emulate(21);
    +        $this->assertSame(21, strlen($result));
    +        $this->assertnotSame($result, random_bytes_emulate(21));
    +
    +        $result = random_bytes_emulate(666);
    +        $this->assertSame(666, strlen($result));
    +
    +        $this->assertDebuggingNotCalled();
    +
    +        $result = random_bytes_emulate(0);
    +        $this->assertSame('', $result);
    +        $this->assertDebuggingCalled();
    +
    +        $result = random_bytes_emulate(-1);
    +        $this->assertSame('', $result);
    +        $this->assertDebuggingCalled();
    +    }
    +
    +    /**
    +     * Test function for creation of random strings.
    +     */
    +    public function test_random_string() {
    +        $pool = 'a-zA-Z0-9';
    +
    +        $result = random_string(10);
    +        $this->assertSame(10, strlen($result));
    +        $this->assertRegExp('/^[' . $pool . ']+$/', $result);
    +        $this->assertNotSame($result, random_string(10));
    +
    +        $result = random_string(21);
    +        $this->assertSame(21, strlen($result));
    +        $this->assertRegExp('/^[' . $pool . ']+$/', $result);
    +        $this->assertNotSame($result, random_string(21));
    +
    +        $result = random_string(666);
    +        $this->assertSame(666, strlen($result));
    +        $this->assertRegExp('/^[' . $pool . ']+$/', $result);
    +
    +        $result = random_string();
    +        $this->assertSame(15, strlen($result));
    +        $this->assertRegExp('/^[' . $pool . ']+$/', $result);
    +
    +        $this->assertDebuggingNotCalled();
    +
    +        $result = random_string(0);
    +        $this->assertSame('', $result);
    +        $this->assertDebuggingCalled();
    +
    +        $result = random_string(-1);
    +        $this->assertSame('', $result);
    +        $this->assertDebuggingCalled();
    +    }
    +
    +    /**
    +     * Test function for creation of complex random strings.
    +     */
    +    public function test_complex_random_string() {
    +        $pool = preg_quote('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789`~!@#%^&*()_+-=[];,./<>?:{} ', '/');
    +
    +        $result = complex_random_string(10);
    +        $this->assertSame(10, strlen($result));
    +        $this->assertRegExp('/^[' . $pool . ']+$/', $result);
    +        $this->assertNotSame($result, complex_random_string(10));
    +
    +        $result = complex_random_string(21);
    +        $this->assertSame(21, strlen($result));
    +        $this->assertRegExp('/^[' . $pool . ']+$/', $result);
    +        $this->assertNotSame($result, complex_random_string(21));
    +
    +        $result = complex_random_string(666);
    +        $this->assertSame(666, strlen($result));
    +        $this->assertRegExp('/^[' . $pool . ']+$/', $result);
    +
    +        $result = complex_random_string();
    +        $this->assertEquals(28, strlen($result), '', 4); // Expected length is 24 - 32.
    +        $this->assertRegExp('/^[' . $pool . ']+$/', $result);
    +
    +        $this->assertDebuggingNotCalled();
    +
    +        $result = complex_random_string(0);
    +        $this->assertSame('', $result);
    +        $this->assertDebuggingCalled();
    +
    +        $result = complex_random_string(-1);
    +        $this->assertSame('', $result);
    +        $this->assertDebuggingCalled();
    +    }
     }
    
289bc7f9e302

MDL-50860 core: improve creation of random strings

https://github.com/moodle/moodlePetr SkodaAug 18, 2015via ghsa
2 files changed · +144 3
  • lib/moodlelib.php+48 3 modified
    @@ -7464,14 +7464,16 @@ function count_letters($string) {
      * @param int $length The length of the string to be created.
      * @return string
      */
    -function random_string ($length=15) {
    +function random_string($length=15) {
    +    $randombytes = random_bytes_emulate($length);
         $pool  = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
         $pool .= 'abcdefghijklmnopqrstuvwxyz';
         $pool .= '0123456789';
         $poollen = strlen($pool);
         $string = '';
         for ($i = 0; $i < $length; $i++) {
    -        $string .= substr($pool, (mt_rand()%($poollen)), 1);
    +        $rand = ord($randombytes[$i]);
    +        $string .= substr($pool, ($rand%($poollen)), 1);
         }
         return $string;
     }
    @@ -7492,13 +7494,56 @@ function complex_random_string($length=null) {
         if ($length===null) {
             $length = floor(rand(24, 32));
         }
    +    $randombytes = random_bytes_emulate($length);
         $string = '';
         for ($i = 0; $i < $length; $i++) {
    -        $string .= $pool[(mt_rand()%$poollen)];
    +        $rand = ord($randombytes[$i]);
    +        $string .= $pool[($rand%$poollen)];
         }
         return $string;
     }
     
    +/**
    + * Try to generates cryptographically secure pseudo-random bytes.
    + *
    + * Note this is achieved by fallbacking between:
    + *  - PHP 7 random_bytes().
    + *  - OpenSSL openssl_random_pseudo_bytes().
    + *  - In house random generator getting its entropy from various, hard to guess, pseudo-random sources.
    + *
    + * @param int $length requested length in bytes
    + * @return string binary data
    + */
    +function random_bytes_emulate($length) {
    +    global $CFG;
    +    if ($length <= 0) {
    +        debugging('Invalid random bytes length', DEBUG_DEVELOPER);
    +        return '';
    +    }
    +    if (function_exists('random_bytes')) {
    +        // Use PHP 7 goodness.
    +        $hash = @random_bytes($length);
    +        if ($hash !== false) {
    +            return $hash;
    +        }
    +    }
    +    if (function_exists('openssl_random_pseudo_bytes')) {
    +        // For PHP 5.3 and later with openssl extension.
    +        $hash = openssl_random_pseudo_bytes($length);
    +        if ($hash !== false) {
    +            return $hash;
    +        }
    +    }
    +
    +    // Bad luck, there is no reliable random generator, let's just hash some unique stuff that is hard to guess.
    +    $hash = sha1(serialize($CFG) . serialize($_SERVER) . microtime(true) . uniqid('', true), true);
    +    // NOTE: the last param in sha1() is true, this means we are getting 20 bytes, not 40 chars as usual.
    +    if ($length <= 20) {
    +        return substr($hash, 0, $length);
    +    }
    +    return $hash . random_bytes_emulate($length - 20);
    +}
    +
     /**
      * Given some text (which may contain HTML) and an ideal length,
      * this function truncates the text neatly on a word boundary if possible
    
  • lib/tests/moodlelib_test.php+96 0 modified
    @@ -2906,4 +2906,100 @@ public function test_getremoteaddr() {
             $_SERVER['HTTP_X_FORWARDED_FOR'] = $xforwardedfor;
     
         }
    +
    +    /*
    +     * Test emulation of random_bytes() function.
    +     */
    +    public function test_random_bytes_emulate() {
    +        $result = random_bytes_emulate(10);
    +        $this->assertSame(10, strlen($result));
    +        $this->assertnotSame($result, random_bytes_emulate(10));
    +
    +        $result = random_bytes_emulate(21);
    +        $this->assertSame(21, strlen($result));
    +        $this->assertnotSame($result, random_bytes_emulate(21));
    +
    +        $result = random_bytes_emulate(666);
    +        $this->assertSame(666, strlen($result));
    +
    +        $this->assertDebuggingNotCalled();
    +
    +        $result = random_bytes_emulate(0);
    +        $this->assertSame('', $result);
    +        $this->assertDebuggingCalled();
    +
    +        $result = random_bytes_emulate(-1);
    +        $this->assertSame('', $result);
    +        $this->assertDebuggingCalled();
    +    }
    +
    +    /**
    +     * Test function for creation of random strings.
    +     */
    +    public function test_random_string() {
    +        $pool = 'a-zA-Z0-9';
    +
    +        $result = random_string(10);
    +        $this->assertSame(10, strlen($result));
    +        $this->assertRegExp('/^[' . $pool . ']+$/', $result);
    +        $this->assertNotSame($result, random_string(10));
    +
    +        $result = random_string(21);
    +        $this->assertSame(21, strlen($result));
    +        $this->assertRegExp('/^[' . $pool . ']+$/', $result);
    +        $this->assertNotSame($result, random_string(21));
    +
    +        $result = random_string(666);
    +        $this->assertSame(666, strlen($result));
    +        $this->assertRegExp('/^[' . $pool . ']+$/', $result);
    +
    +        $result = random_string();
    +        $this->assertSame(15, strlen($result));
    +        $this->assertRegExp('/^[' . $pool . ']+$/', $result);
    +
    +        $this->assertDebuggingNotCalled();
    +
    +        $result = random_string(0);
    +        $this->assertSame('', $result);
    +        $this->assertDebuggingCalled();
    +
    +        $result = random_string(-1);
    +        $this->assertSame('', $result);
    +        $this->assertDebuggingCalled();
    +    }
    +
    +    /**
    +     * Test function for creation of complex random strings.
    +     */
    +    public function test_complex_random_string() {
    +        $pool = preg_quote('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789`~!@#%^&*()_+-=[];,./<>?:{} ', '/');
    +
    +        $result = complex_random_string(10);
    +        $this->assertSame(10, strlen($result));
    +        $this->assertRegExp('/^[' . $pool . ']+$/', $result);
    +        $this->assertNotSame($result, complex_random_string(10));
    +
    +        $result = complex_random_string(21);
    +        $this->assertSame(21, strlen($result));
    +        $this->assertRegExp('/^[' . $pool . ']+$/', $result);
    +        $this->assertNotSame($result, complex_random_string(21));
    +
    +        $result = complex_random_string(666);
    +        $this->assertSame(666, strlen($result));
    +        $this->assertRegExp('/^[' . $pool . ']+$/', $result);
    +
    +        $result = complex_random_string();
    +        $this->assertEquals(28, strlen($result), '', 4); // Expected length is 24 - 32.
    +        $this->assertRegExp('/^[' . $pool . ']+$/', $result);
    +
    +        $this->assertDebuggingNotCalled();
    +
    +        $result = complex_random_string(0);
    +        $this->assertSame('', $result);
    +        $this->assertDebuggingCalled();
    +
    +        $result = complex_random_string(-1);
    +        $this->assertSame('', $result);
    +        $this->assertDebuggingCalled();
    +    }
     }
    

Vulnerability mechanics

Generated by null/stub on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

10

News mentions

0

No linked articles in our index yet.