CVE-2021-21705

Server-Side Request Forgery
Affects
PHP
in
PHP
No items found.
Versions
<7.3.29, >=7.4.0 <7.4.21, >=8.0.0 <8.0.8

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 filter_var() with the FILTER_VALIDATE_URL filter is widely used to check that a string is a well-formed URL.

A Server-Side Request Forgery (SSRF) vulnerability (CVE-2021-21705) has been identified in the FILTER_VALIDATE_URL filter of PHP's filter extension, which allows an attacker who supplies a URL to an application that validates it with filter_var() to have a URL accepted whose user or password part contains characters such as a backslash or a second @, so that other software contacts a different host than the one the application checked. PHP tracks this issue as bug #81122.

Per MITRE CWE-918: The web server receives a URL or similar request from an upstream component and retrieves the contents of this URL, but it does not sufficiently ensure that the request is being sent to the expected destination.

This issue affects PHP before 7.3.29, PHP 7.4 before 7.4.21 and PHP 8.0 before 8.0.8, which includes the End-of-Life PHP 5.6, 7.0, 7.1 and 7.2 release lines through their final releases (5.6.40, 7.0.33, 7.1.33 and 7.2.34).

Details

Module Info

Vulnerability Info

This Medium-severity vulnerability is found in the filter extension of PHP before 7.3.29, 7.4 before 7.4.21 and 8.0 before 8.0.8. The CVE record does not list the End-of-Life PHP 5.6, 7.0, 7.1 and 7.2 release lines, but HeroDevs' analysis found them affected; they never received the fix. The PHP project scores it 4.3 under CVSS 3.1 (CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:L/I:N/A:N). The record classifies it as CWE-20, Improper Input Validation.

FILTER_VALIDATE_URL parses the URL with PHP's own URL parser, the one behind parse_url(), and then checks the parts it finds. For http and https URLs it checks the host name, but it did not check that the user and password parts contain only characters allowed there. In PHP 5.6.40 the filter checks the scheme, host, path and query and then accepts the URL:

if (
    url->scheme == NULL || 
    /* some schemas allow the host to be empty */
    (url->host == NULL && (strcmp(url->scheme, "mailto") && strcmp(url->scheme, "news") && strcmp(url->scheme, "file"))) ||
    ((flags & FILTER_FLAG_PATH_REQUIRED) && url->path == NULL) || ((flags & FILTER_FLAG_QUERY_REQUIRED) && url->query == NULL)
) {
bad_url:
    php_url_free(url);
    RETURN_VALIDATION_FAILED
}
php_url_free(url);

The reporter showed that https://example.com:\@test.com/ passes the filter. PHP's parser reads it as user example.com, password \ and host test.com, but a browser treats example.com as the host. An application that validates a URL with FILTER_VALIDATE_URL, checks its host with parse_url(), and then redirects to it or lets another client fetch it can be sent to a different host than the one it approved. The CVE record notes that this can lead to contacting the wrong server or making a wrong access decision.

Exploitation needs an application that relies on FILTER_VALIDATE_URL, often together with a host check, to decide whether to fetch, redirect to or otherwise trust a URL the attacker supplies. This applies to any SAPI with the filter extension. Applications that do not use FILTER_VALIDATE_URL as a security check are not exposed.

The fix rejects URLs whose user or password contains characters other than letters, digits, a small set of punctuation allowed in that part of a URL, and percent-encoded bytes, so a backslash or an extra @ no longer passes. HeroDevs' fixes for PHP 5.6 and 7.2 apply the same check. In the upstream code it reads:

if ((url->user != NULL && !is_userinfo_valid(url->user))
    || (url->pass != NULL && !is_userinfo_valid(url->pass))
) {
    php_url_free(url);
    RETURN_VALIDATION_FAILED

}

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.

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

  • Upgrade to PHP 7.3.29, 7.4.21, 8.0.8, 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-2021-21705
PROJECT Affected
PHP
Versions Affected
<7.3.29, >=7.4.0 <7.4.21, >=8.0.0 <8.0.8
NES Versions Affected
Published date
October 4, 2021
≈ Fix date
June 17, 2021
Fixed in
Category
Server-Side Request Forgery
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.