February 18th, 2022: If you’re using PHP in your network, check that you’re using the latest versions, currently 7.4.28 or 8.1.3. Released yesterday [2022-02-17], this version fixes various memory mismanagement bugs, including CVE-2021-21708, which is a use-after-free blunder in a function called
A proof-of-concept exploit based on using PHP to query a database shows that the bug can be used to crash the PHP process, so a working Denial of Service (DoS) attack is already known to be possible.
Remote Code Execution (RCE) is likely possible as well, however, exploit code has not yet been discovered which performs RCE. If an RCE exploit becomes available, then data submitted from outside the company PHP systems can not only crash the PHP program on your computer but also gain control of it in the process, typically leads to network intrusion, data exfiltration, malware implantation, or a combination of all of them.
Invalid Validation Code
The PHP filter functions are designed to validate incoming data, for example, to ensure that if you’re expecting someone to send you an integer (e.g. 5, 7, 11), they haven’t sent you a string of text that can’t reliably be converted to a whole number, such as
The CVE-2021-21708 bug is part of the code that checks for valid floats, or floating-point numbers, a term for what you probably called “real numbers” or “decimals” at school.
Decimals typically have a dot (or a comma, depending on your country) that separates the whole part and the fractional part, as in
2.5 to represent two and five-tenths, or two-and-a-half.
PHP’s numeric filter functions allow you to check not only that the incoming number is valid, but also that it’s within a specified range, such as ensuring it’s no greater than 2.71828, or that it’s between -1 and 1.
If the number that comes in is already a floating-point number (a decimal), then the code goes as shown below, where the old PHP code (8.1.2) is on the left and the new code (8.1.3) is on the right. (There’s no bug here, so the two versions are identical.)
Don’t worry if you don’t know C; the important thing to note is that the error checking is done first, followed by a line that frees up the memory currently used by PHP to store the number, followed immediately by a line that reallocates memory for PHP to use.
In case you’re wondering, the curious name
zval_ptr_dtor() is shorthand for PHP internal memory pointer destructor:
If the number comes in as an integer, with no decimal part, a slightly different code is used.
Below, as you can see, the sequence of “do the check and exit if it fails, but if it’s OK then deallocate-and-reallocate storage for the number” was mixed up in the old version.
The sequence was “deallocate the memory used by this PHP value, then do the check and exit if it fails, leaving behind a PHP object referring to memory that will soon get allocated to something else and will thus later cause a use-after-free conflict; but if the check is OK then reallocate new storage for the number.”
That’s a bit like stepping into the road first, and only then checking if it’s safe and completing your crossing.
The updated code in version 8.1.3 has restored the code to a safer sequence, although it would be safer still if there were a single function called, say
dtor_and_alloc_in_one_go()so that future programmers couldn’t accidentally re-insert code between the call to the destructor and the call to the allocator.
The new code is more like checking the road is safe first, then stepping into it and walking directly to the other side.
The “diff” view (jargon for code difference) created by Visual Studio Code shows neatly how the line marked in red in the 8.1.2 version was moved down to the green spot in the 8.1.3 version:
What To Do?
- Scan your network for the existence of PHP systems operating in your environment to make sure they are upgraded to 8.1.3.
- If you’re a PHP user, update to 8.1.3. If you’re using a Linux distro that manages PHP for you, check your distro for details.
- If you’re a programmer, remember that code written in C requires you to take care with memory all the time, and everywhere, so that well-hidden bugs like this one don’t creep in unnoticed.
- If you’re a programmer, try to write your code to reduces the number of ways that errors can be introduced by the coders who come after you.
Future Escalation of Criticality Expected
DDOS attacks of this nature are often exploitable for Remote Code Execution (RCE). If an RCE type exploit is developed, your company will have very little time to patch for this vulnerability. CyberHoot suggests you treat this risk with priority and patch within the next 48 to 72 hours wherever possible. We will continue to monitor the situation and publish an update if and when an RCE becomes available. Take action now to assess and patch.