Security
Headlines
HeadlinesLatestCVEs

Headline

CVE-2020-7067: PHP :: Sec Bug #79465 :: OOB Read in urldecode()

In PHP versions 7.2.x below 7.2.30, 7.3.x below 7.3.17 and 7.4.x below 7.4.5, if PHP is compiled with EBCDIC support (uncommon), urldecode() function can be made to access locations past the allocated memory, due to erroneously using signed numbers as array indexes.

CVE
#windows#microsoft#linux#git#php

Sec Bug #79465

OOB Read in urldecode()

Submitted:

2020-04-10 16:00 UTC

Modified:

2020-04-14 04:10 UTC

From:

bigshaq at wearehackerone dot com

Assigned:

Status:

Closed

Package:

*URL Functions

PHP Version:

Irrelevant

OS:

Any

Private report:

No

CVE-ID:

2020-7067

[2020-04-10 16:00 UTC] bigshaq at wearehackerone dot com

Description:

If ``CHARSET_EBCDIC`` is defined (usually, on systems with EBCDIC encoding support), an Out-of-Bounds read can occur using a malformed url-encoded string.

[C_SNIPPET] PHPAPI size_t php_url_decode(char *str, size_t len) { char *dest = str; char *data = str; /*…more code…*/

#ifndef CHARSET_EBCDIC *dest = (char) php_htoi(data + 1); #else *dest = os_toebcdic[(char) php_htoi(data + 1)]; // <— here #endif

/* … more code … */ [/C_SNIPPET]

* ``os_toebcdic[256]`` is an array(or an "encoding map", i assume) used for decoding purposes. * To convert the url-encoded string input into actual hex values, PHP uses ``php_htoi()`` and then convert the result into a signed byte(char). * This signed number is then provided as an index to the ``os_toebcdic[]`` array. * There will be no OOB Read *after* the buffer because the max value of a byte is 0xff (=256), which is the same size as ``os_toebcdic[]`` * However, the casting (mentioned in the second bullet) is done to a ``char`` type and not an ``unsigned char``, which means that we can insert negative hex values to leak values that are found in the memory BEFORE the array.

if we run: [PHP_SNIPPET] <? urldecode(‘%xfd’); //0xfd == -3, It could also be 0x80 for bigger OOB (which is -128 in dec) ?> [/PHP_SNIPPET]

we can look at the casting in dynamic analysis:

[GDB_SNIPPET] gdb-peda$ call php_htoi(data+1) $42 = 0xfd

gdb-peda$ p/d (char)$42 $43 = -3 [/GDB_SNIPPET]

Note: I did not **completely** verify it because CHARSET_EBCDIC is not supported on my system. So I hope the gdb snippet demonstrates the concept well enough. I’m 99% sure that it’s a valid bug because: if you look at it, it’s pretty straight forward. There’s a casting to a signed byte and there are no bounds checking/validations. I usually won’t report without a fully working PoC on my system but on this case i still think it’s worth looking into it (I tried to enable EBCDIC support in my system but didn’t find any info on the internet about how to do it). Please let me know if you can verify.

Thanks!

Test script:

<? urldecode(‘%xfd’); //0xfd == -3, It could also be 0x80 for bigger OOB (which is -128 in dec) ?>

Expected result:

copy the 253rd (unsigned 0xfd) index of os_toebcdic

Actual result:

copy the -3rd (signed 0xfd) byte before os_toebcdic

PatchesCVE-2020-7067 (last revision 2021-03-22 03:42 UTC by 1552630135 at qq dot com)

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports

[2020-04-10 16:23 UTC] bigshaq at wearehackerone dot com

There’s a mistake in my payload/test script, it should be without the ‘x’ character after the precent(%) character.

Here’s a new one: [PHP_SNIPPET] <?php urldecode(‘%fd’); ?> [/PHP_SNIPPET]

[2020-04-11 10:05 UTC] [email protected]

> […] then convert the result into a signed byte(char).

char is not necessarily signed. Whether it is signed or unsigned is actually implementation defined.

[2020-04-11 11:43 UTC] bigshaq at wearehackerone dot com

Hi @cmb, thanks for the quick response. Yes, I know that it depends on the implementation…

I wrote that char is signed by default as if it was “obvious” because any common implementation (that respect itself) support both signed and unsigned char by default(x86 GNU/Linux, Microsoft Windows and so on)

Yes, there might be some cases when char is unsigned by default and the OOB-Read won’t work but those are edge cases imho.

[2020-04-13 05:01 UTC] [email protected]

-CVE-ID: +CVE-ID: 2020-7067

[2020-04-14 04:06 UTC] [email protected]

I have no way to test it and I am not 100% sure it even compiles now, but I guess it doesn’t hurt to put unsigned char there…

[2020-04-14 04:10 UTC] [email protected]

-Status: Open +Status: Closed

Related news

CVE-2020-14829: Oracle Critical Patch Update Advisory - October 2020

Vulnerability in the MySQL Server product of Oracle MySQL (component: InnoDB). Supported versions that are affected are 8.0.21 and prior. Easily exploitable vulnerability allows high privileged attacker with network access via multiple protocols to compromise MySQL Server. Successful attacks of this vulnerability can result in unauthorized ability to cause a hang or frequently repeatable crash (complete DOS) of MySQL Server. CVSS 3.1 Base Score 4.9 (Availability impacts). CVSS Vector: (CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:U/C:N/I:N/A:H).

CVE-2016-4343: PHP: PHP 7 ChangeLog

The phar_make_dirstream function in ext/phar/dirstream.c in PHP before 5.6.18 and 7.x before 7.0.3 mishandles zero-size ././@LongLink files, which allows remote attackers to cause a denial of service (uninitialized pointer dereference) or possibly have unspecified other impact via a crafted TAR archive.

CVE: Latest News

CVE-2023-50976: Transactions API Authorization by oleiman · Pull Request #14969 · redpanda-data/redpanda
CVE-2023-6905
CVE-2023-6903
CVE-2023-6904
CVE-2023-3907