Edit report at https://bugs.php.net/bug.php?id=78322&edit=1
ID: 78322
Updated by: nikic@php.net
Reported by: contact at scannell-infosec dot net
Summary: Integer overflow in mb_strpos allows to bypass
security related checks
-Status: Open
+Status: Closed
Type: Bug
Package: mbstring related
Operating System: N/A
PHP Version: 7.2.20
-Assigned To:
+Assigned To: nikic
Block user comment: N
Private report: N
New Comment:
This is already fixed in PHP 7.3, where libmbfl was migrated to use size_t.
Previous Comments:
------------------------------------------------------------------------
[2019-07-22 19:48:17] stas@php.net
Looks like a contrived example, requiring special settings to reproduce. Per https://wiki.php.net/security not a security issue.
------------------------------------------------------------------------
[2019-07-22 19:24:42] contact at scannell-infosec dot net
Description:
------------
The PHP function mb_strpos returns the index of the needle within the haystack.
PHP_FUNCTION(mb_strpos)
{
...
n = mbfl_strpos(&haystack, &needle, offset, reverse);
if (n >= 0) {
RETVAL_LONG(n);
} else {
switch (-n) {
case 1:
break;
case 2:
php_error_docref(NULL, E_WARNING, "Needle has not positive length");
break;
case 4:
php_error_docref(NULL, E_WARNING, "Unknown encoding or conversion error");
break;
case 8:
php_error_docref(NULL, E_NOTICE, "Argument is empty");
break;
default:
php_error_docref(NULL, E_WARNING, "Unknown error in mb_strpos");
int(1073741824)
PHP Warning: mb_strpos(): Unknown error in mb_strpos in /tmp/testscript.php on line 4
bool(false)
break;
}
RETVAL_FALSE;
}
depending on the return value of mbfl_strpos, either the index is returned if it positive or if it
is negative, false is returned.
It is possible to force mb_strpos to always return false. This is due to an integer overflow in
mbfl_strpos.
int
mbfl_strpos(
mbfl_string *haystack,
mbfl_string *needle,
int offset,
int reverse)
{
int result;
This is because the resulting index is stored in a signed 32 bit integer. If the index of the needle
is outside of the range 2^31, the result is negative, thus false is returned.
This makes it possible to hide dangerous values that are searched for with mb_strpos, eg. PHP code
or invalid characters
Test script:
---------------
<?php
ini_set("memory_limit", -1);
var_dump(mb_strpos(str_repeat('A', pow(2, 30)) . 'B', 'B'));
var_dump(mb_strpos(str_repeat('A', pow(2, 31)) . 'B', 'B'));
Expected result:
----------------
int(1073741824)
int(2147483649)
Actual result:
--------------
int(1073741824)
PHP Warning: mb_strpos(): Unknown error in mb_strpos in /tmp/testscript.php on line 4
bool(false)
------------------------------------------------------------------------
--
Edit this bug report at https://bugs.php.net/bug.php?id=78322&edit=1