CVE-2022-31631

SQL Injection
Affects
PHP
in
PHP
No items found.
Versions
<8.0.27, >=8.1.0 <8.1.15, >=8.2.0 <8.2.2

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 PDO extension gives applications one database API across drivers, and the pdo_sqlite driver connects it to SQLite databases.

A SQL Injection vulnerability (CVE-2022-31631) has been identified in the PDO::quote() method of PHP's PDO SQLite driver, which allows an attacker who can supply a very long string to an application that quotes it with PDO::quote() to receive back a string that is not properly quoted, and so to inject SQL into the query the application builds from it. PHP tracks this issue as bug #81740.

Per OWASP: A SQL injection attack consists of insertion or "injection" of a SQL query via the input data from the client to the application. A successful SQL injection exploit can read sensitive data from the database, modify database data (Insert/Update/Delete), execute administration operations on the database (such as shutdown the DBMS), recover the content of a given file present on the DBMS file system and in some cases issue commands to the operating system.

This issue affects PHP before 8.0.27, PHP 8.1 before 8.1.15 and PHP 8.2 before 8.2.2, which includes every End-of-Life release line from PHP 5.6 through 7.4, each through its final release.

Details

Module Info

Vulnerability Info

This Critical-severity vulnerability is found in the pdo_sqlite extension of PHP before 8.0.27, 8.1 before 8.1.15 and 8.2 before 8.2.2, including every End-of-Life release line from PHP 5.6 through 7.4, which never received the upstream fix. The PHP project scores it 9.1 under CVSS 3.1 (CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:N).

PDO::quote() escapes a string so an application can place it inside a SQL statement. For SQLite connections, PHP implements it in sqlite_handle_quoter(), which allocates a buffer twice the input length plus three bytes and lets SQLite's sqlite3_snprintf() fill it with the input wrapped in single quotes and its quotes doubled. In PHP 7.4.33, the function reads:

static int sqlite_handle_quoter(pdo_dbh_t *dbh, const char *unquoted, size_t unquotedlen, char **quoted, size_t *quotedlen, enum pdo_param_type paramtype )
{
    *quoted = safe_emalloc(2, unquotedlen, 3);
    sqlite3_snprintf(2*unquotedlen + 3, *quoted, "'%q'", unquoted);
    *quotedlen = strlen(*quoted);
    return 1;
}

The buffer size is computed as a size_t, but the first parameter of sqlite3_snprintf() is an int. When the input is long enough, 2*unquotedlen + 3 no longer fits in an int and wraps, so SQLite is told the buffer is far smaller than it is and writes a truncated result. The reporter showed that with recent SQLite versions the call can return a single apostrophe. An application that concatenates that result into a query no longer has its value enclosed in quotes, so the rest of the attacker's input is parsed as SQL.

Exploitation needs an application that passes attacker-controlled input to PDO::quote() on an SQLite connection without limiting its length. HeroDevs' analysis puts the threshold at strings of about 2 GiB on PHP 7.2 and 7.4, and about 1 GiB on PHP 5.6. PHP's memory_limit and, for request data, post_max_size must allow a string that large, which common settings do not. Applications that use prepared statements with bound parameters instead of PDO::quote() are not affected.

The fix rejects input whose quoted length cannot fit in an int, so PDO::quote() returns false instead of a broken string:

if (unquotedlen > (INT_MAX - 3) / 2) {
    return 0;
}
*quoted = safe_emalloc(2, unquotedlen, 3);
sqlite3_snprintf(2*unquotedlen + 3, *quoted, "'%q'", unquoted);

Mitigation

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

Until an upgrade is possible, use prepared statements with bound parameters instead of PDO::quote(), and keep memory_limit and post_max_size well below the sizes needed to reach the overflow.

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

  • Upgrade to PHP 8.0.27, 8.1.15, 8.2.2, 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
Critical
ID
CVE-2022-31631
PROJECT Affected
PHP
Versions Affected
<8.0.27, >=8.1.0 <8.1.15, >=8.2.0 <8.2.2
NES Versions Affected
Published date
February 12, 2025
≈ Fix date
January 5, 2023
Fixed in
Category
SQL Injection
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.