Nasty bug with very simple exploit hits PHP just in time for the weekend

A critical vulnerability in the PHP programming language can be trivially exploited to execute malicious code on Windows devices, security researchers warned as they urged those affected to take action before the weekend starts.

Within 24 hours of the vulnerability and accompanying patch being published, researchers from the nonprofit security organization Shadowserver reported Internet scans designed to identify servers that are susceptible to attacks. That—combined with (1) the ease of exploitation, (2) the availability of proof-of-concept attack code, (3) the severity of remotely executing code on vulnerable machines, and (4) the widely used XAMPP platform being vulnerable by default—has prompted security practitioners to urge admins check to see if their PHP servers are affected before starting the weekend.

When “Best Fit” isn’t

“A nasty bug with a very simple exploit—perfect for a Friday afternoon,” researchers with security firm WatchTowr wrote.

CVE-2024-4577, as the vulnerability is tracked, stems from errors in the way PHP converts unicode characters into ASCII. A feature built into Windows known as Best Fit allows attackers to use a technique known as argument injection to pass user-supplied input into commands executed by an application, in this case, PHP. Exploits allow attackers to bypass CVE-2012-1823, a critical code execution vulnerability patched in PHP in 2012.

“While implementing PHP, the team did not notice the Best-Fit feature of encoding conversion within the Windows operating system,” researchers with Devcore, the security firm that discovered CVE-2024-4577, wrote. “This oversight allows unauthenticated attackers to bypass the previous protection of CVE-2012-1823 by specific character sequences. Arbitrary code can be executed on remote PHP servers through the argument injection attack.”

CVE-2024-4577 affects PHP only when it runs in a mode known as CGI, in which a web server parses HTTP requests and passes them to a PHP script for processing. Even when PHP isn’t set to CGI mode, however, the vulnerability may still be exploitable when PHP executables such as php.exe and php-cgi.exe are in directories that are accessible by the web server. This configuration is set by default in XAMPP for Windows, making the platform vulnerable unless it has been modified.

One example, WatchTowr noted, occurs when queries are parsed and sent through a command line. The result: a harmless request such as http://host/cgi.php?foo=bar could be converted into php.exe cgi.php foo=bar, a command that would be executed by the main PHP engine.

No escape

Like many other languages, PHP converts certain types of user input to prevent it from being interpreted as a command for execution. This is a process known as escaping. For example, in HTML, the < and > characters are often escaped by converting them into their unicode hex value equivalents < and > to prevent them from being interpreted as HTML tags by a browser.

The WatchTowr researchers demonstrate how Best Fit fails to escape characters such as a soft hyphen (with unicode value 0xAD) and instead converts it to an unescaped regular hyphen (0x2D), a character that’s instrumental in many code syntaxes.

The researchers went on to explain:

It turns out that, as part of unicode processing, PHP will apply what’s known as a ‘best fit’ mapping, and helpfully assume that, when the user entered a soft hyphen, they actually intended to type a real hyphen, and interpret it as such. Herein lies our vulnerability—if we supply a CGI handler with a soft hyphen (0xAD), the CGI handler won’t feel the need to escape it, and will pass it to PHP. PHP, however, will interpret it as if it were a real hyphen, which allows an attacker to sneak extra command line arguments, which begin with hyphens, into the PHP process.

This is remarkably similar to an older PHP bug (when in CGI mode), CVE-2012-1823, and so we can borrow some exploitation techniques developed for this older bug and adapt them to work with our new bug. A helpful writeup advises that, to translate our injection into RCE, we should aim to inject the following arguments:

-d allow_url_include=1 -d auto_prepend_file=php://input
This will accept input from our HTTP request body, and process it using PHP. Straightforward enough – let’s try a version of this equipped with our 0xAD ‘soft hyphen’ instead of the usual hyphen. Maybe it’s enough to slip through the escaping?

POST /test.php?%ADd+allow_url_include%3d1+%ADd+auto_prepend_file%3dphp://input HTTP/1.1
Host: {{host}}
User-Agent: curl/8.3.0
Accept: */*
Content-Length: 23
Content-Type: application/x-www-form-urlencoded
Connection: keep-alive

The vulnerability was discovered by Devcore researcher Orange Tsai, who said: “The bug is incredibly simple, but that’s also what makes it interesting.”

The Devcore writeup said that the researchers have confirmed that XAMPP is vulnerable when Windows is configured to use the locales for Traditional Chinese, Simplified Chinese, or Japanese. In Windows, a locale is a set of user preference information related to the user’s language, environment, and/or cultural conventions. The researchers haven’t tested other locales and have urged people using them to perform a comprehensive asset assessment to test their usage scenarios.

CVE-2024-4577 affects all versions of PHP running on a Windows device. That includes version branches 8.3 prior to 8.3.8, 8.2 prior to 8.2.20, and 8.1 prior to 8.1.29.

The 8.0, 7, and 5 version branches are also vulnerable, but since they’re no longer supported, admins will have to follow mitigation advice since patches aren’t available. One option is to apply what are known as rewrite rules such as:

RewriteEngine On
RewriteCond %{QUERY_STRING} ^%ad [NC]
RewriteRule .? - [F,L]

The researchers caution these rules have been tested only for the three locales they have confirmed as vulnerable.

XAMPP for Windows had yet to release a fix at the time this post went live. For admins without the need for PHP CGI, they can turn it off using the following Apache HTTP Server configuration:

C:/xampp/apache/conf/extra/httpd-xampp.conf

Locating the corresponding lines:

ScriptAlias /php-cgi/ "C:/xampp/php/"

And comment it out:

# ScriptAlias /php-cgi/ "C:/xampp/php/"

Additional analysis of the vulnerability is available here.