常见的php后门基本需要文件来维持(常规php脚本后门:一句话、大马等各种变形;WebServer模块:apache扩展等,需要高权限并且需要重启WebServer),或者是脚本运行后删除自身,利用死循环驻留在内存里,不断主动外连获取指令并且执行。两者都无法做到无需高权限、无需重启WeServer、触发后删除脚本自身并驻留内存、无外部进程、能主动发送控制指令触发后门(避免内网无法外连的情况)。
而先前和同事一块测试Linux下面通过/proc/PID/fd文件句柄来利用php文件包含漏洞时,无意中发现了一个有趣的现象。经过后续的分析,可以利用其在特定环境下实现受限的无文件后门,效果见动图:
测试环境
CentOS 7.5.1804 x86_64 nginx + php-fpm(监听在tcp 9000端口)
为了方便观察,建议修改php-fpm默认pool的如下参数:
# /etc/php-fpm.d/www.conf
pm.start_servers = 1
pm.min_spare_servers = 1
pm.max_spare_servers = 1
修改后重启php-fpm,可以看到只有一个master进程和一个worker进程:
[root@localhost php-fpm.d]# ps -ef|grep php-fpm
nginx 2439 30354 0 18:40 ? 00:00:00 php-fpm: pool www
root 30354 1 0 Oct15 ? 00:00:37 php-fpm: master process (/etc/php-fpm.conf)
php-fpm文件句柄泄露
在利用php-fpm运行的php脚本里,使用system()等函数执行外部程序时,由于php-fpm没有使用FD_CLOEXEC处理句柄,导致fork出来的子进程会继承php-fpm进程的所有文件句柄。
简单测试代码: