AntSword BYPASS disable_function 分析 🚀

AntSword BYPASS disable_functions 插件分析 🚀

📍 ABSTRACT

实战中很多次遇到上传了 webshell 却无法执行命令的情况,大多数时候是因为目标设置了 php disable_functions 禁用了一些用来执行命令的函数,本文主要分析一下 AntSword 插件 bypass_disable_functions 的绕过实现方式。

🤔️ Analyse

加载插件,有几种利用方式:

image-20200524180353495

📍 LD_PRELOAD

利用条件

  • 目标是 Linux 系统
  • PHP 可执行 putenv() 函数
  • 未禁用 mail 或 error_log
  • 存在可写入权限的目录,用来上传 .so 库文件

LD_PRELOAD 是 Linux 的环境变量,允许你定义在程序运行前优先加载的动态链接库。这个功能主要就是用来有选择性的载入不同动态链接库中的相同函数。我们写一个简单的示例 random_num.c :

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

int main(){
srand(time(NULL));
int i = 10;
while(i--) printf("%d\n", rand()%100);
return 0;
}

它会输出 0-99 中的十个随机数,将它编译成可执行程序: gcc random_num.c -o random_num

然后再写另一个简单的 C 文件 unrandom.c :

int rand(){
return 10;
}

这个 rand() 函数会返回 10。然后我们将它编译进一个共享库中:

gcc -shared -fPIC unrandom.c -o unrandom.so

现在我们有了:

  1. 可以输出十个随机数的程序。
  2. 一个定制的库,其中的 rand() 函数返回常数 10。

接着我们设定环境变量 LD_PRELOAD :

export LD_PRELOAD=$PWD/unrandom.so

然后运行可执行程序 random_num :

image-20200525001938428

按我们的期望,该可执行程序应该输出十个随机数才对,但是这里却输出了十个常量 10。这里就暴露出了问题,当我们的程序被启动后,某些库被加载,我们用 ldd 命令去查看它调用了哪些库:

Screenshot 2020-05-25 上午12.23.32

可见它调用了我们新建立的库,本来 random_num 应当去调用 libc.so.6 这个库中的 rand() 函数,但这里首先调用了我们设置的「恶意库」。所以,环境变量 LD_PRELOAD 为程序强制加载一些库,那么如果这个库可以被我们所构造,然后设置环境变量指向我们构造的「恶意库」,就可以达到攻击的目的。

PHP 中有函数 putenv() ,是用来设置环境变量的值的。如果我们利用 putenv() 函数设置 LD_PRELOAD 环境变量来加载指定的 .so 库文件,而 .so 文件中包含相同名称的函数,那么就可以实现劫持动态链接库执行危险函数。

利用方式比较简单,在此就不过多赘述:https://github.com/AntSwordProject/AntSword-Labs/tree/master/bypass_disable_functions/1

加载插件选择模式,启动插件后,发现上传了 .antproxy.php 文件,然后蚁剑创建副本连接该文件即可 BYPASS。

image-20200525005405428

image-20200525005745418

查看 .antproxy.php 代码:

image-20200525010635186

即向 127.0.0.1:63450 的 index.php 发送请求。我们在被攻击的主机上查看下:

image-20200525010949694

63450 端口运行了 php 命令,ps 查看下:

image-20200525011118167

可见这里是用 php 另起了一个 web 服务。

-n 不使用 php.ini 配置文件( php.ini 中设置了 disable_functions )

-t 指定目录,一开始上传的 shell 的目录

这其实就是蚁剑 BYPASS disable_functions 的第一步:重新起一个没有应用 php.ini 的 web 服务,然后与新生成的 web 服务下的 shell 文件(即 index.php)建立连接执行命令。查看下插件的源码:

Screenshot 2020-05-25 上午1.27.47

Screenshot 2020-05-25 上午1.24.38

生成 extensions:

Screenshot 2020-05-31 下午11.21.42

这种攻击方式需要用到 mail() 或者 error_log() 函数,在运行的时候启动子进程,从而重新加载恶意环境变量,来劫持子进程所调用的库函数。

image-20200531232812179

error_log() 函数当第二个参数为 1 时,会启动子进程来调用系统的 sendmail,如上图( mail() 函数在运行时,也会启动子进程来调用 sendmail)。

所以如果要利用这种方式,目标主机必须装有 sendmail 以供调用,同时对于 sendmail 的调用没有做限制;可以调用 mail() 或 error_log() 。

📍 Fastcgi/PHP_FPM

Nginx 为 Fastcgi 提供了 fastcgi_param 来主要处理映射关系,将 Nginx 中的变量翻译成 php 能够理解的变量。

判断 php-fpm 的连接方式是 TCP 连接还是 Unix Socket 连接:

image-20200531235414631

接着将启动新的 web 服务的命令写入 .so 库文件上传,初始化 fastcgi client。

Screenshot 2020-06-01 上午12.06.57

构造攻击 fastcgi 的 payload:

image-20200531234941675

攻击包为什么是上面这个样子呢,因为 Nginx 会将请求解析成键值对,然后发送给 php 解析。PHP_VALUE 和 PHP_ADMIN_VALUE 将 ext 指向恶意的 .so 文件,发送攻击包动态加载恶意 .so 文件,于是启动了不配置 php.ini 的 web 服务。

最后上传代理脚本 .antproxy.php ,使流量通过 shell 转发到新的 web 服务,从而绕过 php disable_function。

📍 Apache_mod_cgi

Mod_CGI 模式其实就是把 php 作为 Apache 的一个内置模块,让 Apache 本身能够支持解析 php。

利用条件

  • 当前目录具有写入权限
  • Apache + PHP,且 PHP 以 module 方式与 Apache 结合

📍 JSON_Serializer_UAF

📍 PHP7_GC_UAF

📍 PHP7_Backtrace_UAF

📍 PHP74_FFI