Bug 1868109 (CVE-2020-7068) - CVE-2020-7068 php: Use of freed hash key in the phar_parse_zipfile function
Summary: CVE-2020-7068 php: Use of freed hash key in the phar_parse_zipfile function
Keywords:
Status: NEW
Alias: CVE-2020-7068
Product: Security Response
Classification: Other
Component: vulnerability
Version: unspecified
Hardware: All
OS: Linux
low
low
Target Milestone: ---
Assignee: Red Hat Product Security
QA Contact:
URL:
Whiteboard:
Depends On: 1869773 1869774 1869777 1869796 1868110 1869775 1869776
Blocks: 1868111
TreeView+ depends on / blocked
 
Reported: 2020-08-11 17:30 UTC by Michael Kaplan
Modified: 2020-09-23 19:12 UTC (History)
6 users (show)

Fixed In Version: php 7.2.33, php 7.3.21, php 7.4.9
Doc Type: If docs needed, set a value
Doc Text:
Clone Of:
Environment:
Last Closed:


Attachments (Terms of Use)

Description Michael Kaplan 2020-08-11 17:30:40 UTC
he phar_parse_zipfile function had use-after-free vulnerability because of mishandling of the actual_alias variable.

----- ext/phar/zip.c -----
int phar_parse_zipfile(php_stream *fp, char *fname, size_t fname_len, char *alias, size_t alias_len, phar_archive_data** pphar, char **error) /* {{{ */
{
	...

	mydata->alias = entry.is_persistent ? pestrndup(actual_alias, mydata->alias_len, 1) : actual_alias;

	if (entry.is_persistent) {
		efree(actual_alias);
	}

	zend_hash_str_add_ptr(&(PHAR_G(phar_alias_map)), actual_alias, mydata->alias_len, mydata);

	...
---------------------------

`actual_alias` variable is allocated by estrndup function, which string is part of data of the zip file.

The above code snippet `mydata->alias` is assigned by `pestrndup(actual_alias, mydata->alias_len, 1)` if entry.is_persistent is true. Or `mydata->alias` is assigned by `actual_alias` variable.
And if `entry.is_persistent` is true, `actual_alias` variable is freed by invoke efree function. `actual_alias` variable is used invoke of zend_hash_str_add_ptr function as 2nd argument.

Problem is that `actual_alias` variable is freed if `entry.is_persistent` is true, the key of `phar_alias_map` will use freed memory. `entry.is_persistent` is true if `phar.cache_list` fields is defined in php.ini file. 

So if `phar.cache_list` is defined with target phar path so that `entry.is_persistent` is true, then it can be that `phar_alias_map` hash key would use sensitive freed memory data such as heap addresses that addresses set via linked list after invoke the efree function.


Possibly affected versions: php 7.2.32, php 7.3.20, php 7.4.8

Upstream Reference:

https://bugs.php.net/bug.php?id=79797
https://www.php.net/ChangeLog-7.php

Comment 1 Michael Kaplan 2020-08-11 17:30:55 UTC
Created php tracking bugs for this issue:

Affects: fedora-all [bug 1868110]

Comment 3 Todd Cullum 2020-08-11 20:52:37 UTC
Flaw summary:

The flaw is in phar_parse_zipfile() of ext/phar/zip.c. When processing a PHP archive file (phar), if a persistent entry is used as defined in php.ini, then memory pointed to by the actual_alias pointer is freed. Directly after the free, the actual_alias pointer is passed to zend_hash_str_add_ptr, where it is dereferenced. Prior to the function call, a copy of the memory pointed to by actual_alias is duplicated and assigned to the mydata->alias pointer. The patch simply uses the unfreed mydata->alias pointer as an argument to the zend_hash_add_str() call rather than the freed memory pointed to by actual_alias.

To trigger this flaw, an attacker needs to place a specially crafted file on the server's filesystem and then load it with PHP. The attacker also needs a setting to be present in PHP's configuration file. Due to this, the attack complexity is high as an attacker would need to find other flaws or already have admin access to the server machine to do this.

Comment 10 Todd Cullum 2020-08-18 16:38:54 UTC
in php 5.4 (RHEL7), it's in ext/phar/zip.c ~ line 687:

        mydata->alias = entry.is_persistent ? pestrndup(actual_alias, mydata->alias_len, 1) : actual_alias;

        if (entry.is_persistent) {
            efree(actual_alias);
        }

        zend_hash_add(&(PHAR_GLOBALS->phar_alias_map), actual_alias, mydata->alias_len, (void*)&mydata, sizeof(phar_archive_data*), NULL);

In this ver, the function is called zend_hash_add instead of zend_hash_str_add.


Note You need to log in before you can comment on or make changes to this bug.