CVE-2020-7071

Improper Input Validation (4.16)
Affects
PHP
in
PHP
No items found.
Versions
<7.3.26, >=7.4.0 <7.4.14, >=8.0.0 <8.0.1

Patch Available.

Exclamation circle icon
Patch Available

This Vulnerability has been fixed in the Never-Ending Support (NES) version offered by HeroDevs.

Overview

PHP is a general-purpose scripting language used mostly for web development. It runs behind web servers through server APIs such as Apache mod_php and PHP-FPM, and powers content management systems and frameworks such as WordPress, Drupal, Moodle and Laravel. Its filter extension validates and sanitizes input, and its FILTER_VALIDATE_URL filter, used through filter_var(), is a common way for applications to check that a URL is well formed before they store, fetch or redirect to it.

An Improper Input Validation vulnerability (CVE-2020-7071) has been identified in the FILTER_VALIDATE_URL filter of PHP's filter extension, which allows an attacker to get a URL with characters that RFC 3986 forbids in its userinfo part accepted as valid, so that parse_url(), a browser or an HTTP client may resolve it to a different host than the one the application checked. PHP tracks this issue as bug #77423.

Per MITRE CWE-20: The product receives input or data, but it does not validate or incorrectly validates that the input has the properties that are required to process the data safely and correctly.

This issue affects all versions of PHP before 7.3.26, PHP 7.4 before 7.4.14 and PHP 8.0.0.

Details

Module Info

Vulnerability Info

This Medium-severity vulnerability is found in the filter extension of all PHP versions before 7.3.26, PHP 7.4 before 7.4.14 and PHP 8.0.0, including the End-of-Life PHP 5.6, 7.0, 7.1 and 7.2 release lines, which never received the upstream fix. The PHP project scores it 5.3 under CVSS 3.1 (CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:N).

FILTER_VALIDATE_URL splits the URL with PHP's own URL parser, the one behind parse_url(), and then checks the scheme and, for http and https, that the host is a valid host name. It did not check the userinfo, the user:password@ part before the host. PHP's parser can place characters in the userinfo that RFC 3986 does not allow there, such as a backslash, and the filter accepted them.

Other URL parsers do not all read such a URL the same way. The reporter showed a URL with a backslash in the userinfo for which parse_url() returns one host while a browser following the same link opens another. An application that validates a URL with FILTER_VALIDATE_URL and then compares the host from parse_url() against an allow list, for example before a redirect or an outbound request, can therefore be led to send the user or the request to a host it meant to reject. The CVE record describes the result as functions that rely on the URL being valid mis-parsing it and producing wrong data as its components.

Exploitation needs an application that relies on FILTER_VALIDATE_URL to vet an attacker-supplied URL before it uses the URL. The filter extension is built into PHP by default and the issue applies to every SAPI. The impact is limited to how the application acts on the URL: PHP itself does not read or change data because of it.

The upstream fix, by Christoph M. Becker, first made the URL parser itself reject invalid userinfo. Because that changed parse_url() results that existing code relied on, PHP replaced it in PHP 7.3.27 with an alternative that restores the old parsing and validates the userinfo only inside FILTER_VALIDATE_URL. The check that FILTER_VALIDATE_URL now applies to the userinfo reads:

static int is_userinfo_valid(zend_string *str)
{
    const char *valid = "-._~!$&'()*+,;=:";
    const char *p = ZSTR_VAL(str);
    while (p - ZSTR_VAL(str) < ZSTR_LEN(str)) {
        if (isalpha(*p) || isdigit(*p) || strchr(valid, *p)) {
            p++;
        } else if (*p == '%' && p - ZSTR_VAL(str) <= ZSTR_LEN(str) - 3 && isdigit(*(p+1)) && isxdigit(*(p+2))) {
            p += 3;
        } else {
            return 0;
        }
    }
    return 1;
}

Mitigation

The PHP project publishes security fixes only for its supported release lines. PHP 5.6, 7.0, 7.1 and 7.2 are End-of-Life and will not receive any public updates to address this issue.

Until an upgrade is possible, do not rely on FILTER_VALIDATE_URL alone before redirecting to or fetching a URL: reject URLs that contain userinfo, or check the host with the same parser that will use the URL.

Users of the affected components should apply one of the following mitigations:

  • Upgrade to PHP 7.3.26, 7.4.14, 8.0.1, or later.
  • Leverage a commercial support partner like HeroDevs (NES for PHP) for post-EOL security support.

Credits

Vulnerability Details
Severity
Level
CVSS Assessment
Low
>=0 <4
Medium
>=4 <6
High
>=6 <8
Critical
>=8 <10
Medium
ID
CVE-2020-7071
PROJECT Affected
PHP
Versions Affected
<7.3.26, >=7.4.0 <7.4.14, >=8.0.0 <8.0.1
NES Versions Affected
Published date
February 15, 2021
≈ Fix date
January 7, 2021
Fixed in
Category
Improper Input Validation (4.16)
Vex Document
Download VEXHow do I use it?
Sign up for the latest vulnerability alerts fixed in
PHP
Rss feed icon
Subscribe via RSS
or

By submitting the form I acknowledge receipt of our Privacy Policy.

Thanks for signing up for our Newsletter! We look forward to connecting with you.
Oops! Something went wrong while submitting the form.