Sec Bug->Bug #78322 [Opn]: Integer overflow in mb_strpos allows to bypass security related checks
| From: | stas@php.net | Date: | Mon, 22 Jul 2019 19:48:17 +0000 |
| Subject: | Sec Bug->Bug #78322 [Opn]: Integer overflow in mb_strpos allows to bypass security related checks | ||
| References: | 1 | Groups: | php.bugs |
| Request: | Send a blank email to php-bugs+get-221897@lists.php.net to get a copy of this message | ||
Edit report at https://bugs.php.net/bug.php?id=78322&edit=1
ID: 78322
Updated by: stas@php.net
Reported by: contact at scannell-infosec dot net
Summary: Integer overflow in mb_strpos allows to bypass
security related checks
Status: Open
-Type: Security
+Type: Bug
Package: mbstring related
Operating System: N/A
PHP Version: 7.2.20
Block user comment: N
Private report: Y
New Comment:
Looks like a contrived example, requiring special settings to reproduce. Per https://wiki.php.net/security not a security issue.
Previous Comments:
------------------------------------------------------------------------
[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