原创投稿活动:
http://link.zhihu.com/?target=https%3A//mp.weixin.qq.com/s/Nw2VDyvCpPt_GG5YKTQuUQ
在PHP中有以下几种常见的安装模式:

1. CGI模式
CGI是通用网关接口,HTTP做事器利用这样的接口程序来调用外部程序,外部程序可以利用任何打算机措辞来编写,例如C,C++,Perl,Visual Basic,Shell等等,历史上用来编写CGI程序利用最广泛的是Perl措辞。
做事器在认为这是一个CGI要求时,会调用干系CGI程序,并通过环境变量和标准输出将数据传送给CGI程序,CGI程序处理完数据,天生html,然后再通过标准输出将内容返回给做事器,做事器再将内容交给用户浏览器,CGI进程退出。
CGI的涌现让WEB从静态变为为动态,随着Web的越来越遍及,很多的网站的都须要有动态的页面,以便与浏览者互交。CGI办法的缺陷也越来越突出。由于HTTP要天生一个动态页面,系统就必须启动一个新的进程以运行CGI程序,CGI采取fork and execution办法,每次要求都须要新建立CGI程序来进行处理,不断地fork是一项很花费韶光和资源的事情,导致性能的低下。这就涌现了FastCGI。
2. FastCGI模式
FastCGI是从CGI发展改进而来的。传统CGI接口办法的紧张缺陷是性能很差,由于每次HTTP做事器碰着动态程序时都须要重新启动脚本解析器来实行解析,然后结果被返回给HTTP做事器。这在处理高并发访问时,险些是不可用的。其余传统的CGI接口办法安全性也很差,现在已经很少被利用。FASTCGI快速通用网关接口是常驻内存的CGI,实际上是对CGI程序的进程管理,FastCGI接口办法采取C/S构造,可以将HTTP做事器和脚本解析做事器分开,同时在脚本解析做事器上启动一个或者多个脚本解析守护进程。当HTTP做事器每次碰着动态程序时,可以将其直接交付给FastCGI进程来实行,然后将得到的结果返回给浏览器。这种办法可以让HTTP做事器专一地处理静态要求或者将动态脚本做事器的结果返回给客户端,这在很大程度长进步了全体运用系统的性能。
干系的Fastcgi学习可到合天网安实验室操作实验——Fastcgi安全:http://www.hetianlab.com/expc.do?ec=ECID172.19.104.182015060115422500001本实验先容了fastcgi安全,因此nginx+php+fastcgi为环境,在多台fastcgi做事器做负载均衡的情形下,随意马虎涌现的缺点。
3. Module模式
Module模式便是把php作为apache的一个子模块来运行,利用LoadModule来加载php模块,比如在apache的配置文件中
//httpd.conf LoadModule php7_module \公众${INSTALL_DIR}/bin/php/php7.2.13/php7apache2_4.dll\"大众
当web访问php文件时,apache会调用php模块来解析,phpmodule通过sapi来把数据通报给php解析器进行解析。
4. PHP-FPM模式
末了是本篇文章的主角PHP-FPM,FPM是一个FastCGI协议解析器,Nginx等做事器中间件将用户要求按照FastCGI的规则打包好发送给PHP-FPM,再由PHP-FPM来将打包的数据进行解析并与FastCGI进行通信,PHP-FPM便是为了实现和管理FastCGI协议的进程(fastcgi进程管理器),管理一个进程池,处理来自于web做事器的要求。个中,Ngnix与PHP-FPM有两种通信办法,分别是TCP与Unix domain sockets模式。在windows系统中只能利用tcp socket的通信办法。
TCP模式
TCP模式是PHP-FPM进程监听本机上端口(默认为9000),Ngnix将用户要求按照fastcgi的规则打包好发送给php-fpm,由PHP-FPM调用cgi进行解析。TCP通信模式许可通过网络进程之间的通信,也可以通过loopback进行本地进程之间通信。
Unix domain sockets模式
Unix socket 又叫 IPC (inter-process communication 进程间通信) socket,用于实现同一主机上的进程间通信,这种办法须要在 Ngnix配置文件中填写 PHP-FPM 的 socket 文件位置。
在P神的Fastcgi协议剖析 && PHP-FPM未授权访问漏洞 && Exp编写这篇文章中对个中的事理已经做了比较详细的阐明:
如果用户访问
http://127.0.0.1/index.php?a=1&b=2
如果web 目录为 /var/www/html,Nginx将要求变成键值对
{ 'GATEWAY_INTERFACE': 'FastCGI/1.0', 'REQUEST_METHOD': 'GET', 'SCRIPT_FILENAME': '/var/www/html/index.php', 'SCRIPT_NAME': '/index.php', 'QUERY_STRING': '?a=1&b=2', 'REQUEST_URI': '/index.php?a=1&b=2', 'DOCUMENT_ROOT': '/var/www/html', 'SERVER_SOFTWARE': 'php/fcgiclient', 'REMOTE_ADDR': '127.0.0.1', 'REMOTE_PORT': '12345', 'SERVER_ADDR': '127.0.0.1', 'SERVER_PORT': '80', 'SERVER_NAME': \"大众localhost\"大众, 'SERVER_PROTOCOL': 'HTTP/1.1' }
这个数组实在便是PHP中$_SERVER数组的一部分,也便是PHP里的环境变量。其浸染不仅是添补$_SERVER数组,也是在见告FPM要实行哪个PHP文件。当PHP-FPM拿到了数据包在之后,进行解析,得到了环境变量,然后实行SCRIPT_FILENAME的值指向的PHP文件,即/var/www/html/index.php。
0X01 如何利用PHP-FPM默认监听9000端口,如果这个端口暴露在公网,则我们可以自己布局FastCGI协议,和FPM进行通信。这时候可以利用SCRIPT_FILENAME来指定实行php文件,如果文件不存在则返回404。在Nginx中存在一个配置限定了只有带某些后缀的文件才许可被PHP-FPM实行,默认为.php,security.limit_extensions
; Limits the extensions of the main script FPM will allow to parse. This can ; prevent configuration mistakes on the web server side. You should only limit ; FPM to .php extensions to prevent malicious users to use other extensions to ; exectute php code. ; Note: set an empty value to allow all extensions. ; Default Value: .php ;security.limit_extensions = .php .php3 .php4 .php5 .php7
为了避免404,首先须要找到已存在的PHP文件,如果不知道web的绝对路径或者web目录下的php文件名,可以利用全局搜索得到环境中默认的php文件。
find / -name \公众.php\公众
在我们得到一个webshell的时候,怎么能打破限定实行任意PHP代码呢?
首先我们能掌握SCRIPT_FILENAME,让fpm实行的任意文件,但是也只是实行目标做事器上的文件,并不能实行我们须要其实行的文件,但是在PHP中有很多有趣的技巧,比如在php.ini中有两个配置项
auto_prepend_file //在实行目标文件之前,先包含auto_prepend_file中指定的文件 auto_append_file //在实行完成目标文件后,包含auto_append_file指向的文件
如果设置auto_prepend_file为php://input,则相称于实行任何php文件之前会包含$_POST中的内容,利用php://input须要开启远程文件包含(allow_url_include)。
在PHP-FPM中还会解析两个环境变量
PHP_VALUE //用于设置PHP的配置项,除 disable_function 以外的大部分 php 配置 PHP_ADMIN_VALUE
设置auto_prepend_file = php://input且allow_url_include = On,然后将我们须要实行的代码放在Body中,即可实行任意代码。
{ 'GATEWAY_INTERFACE': 'FastCGI/1.0', 'REQUEST_METHOD': 'GET', 'SCRIPT_FILENAME': '/var/www/html/index.php', 'SCRIPT_NAME': '/index.php', 'QUERY_STRING': '?a=1&b=2', 'REQUEST_URI': '/index.php?a=1&b=2', 'DOCUMENT_ROOT': '/var/www/html', 'SERVER_SOFTWARE': 'php/fcgiclient', 'REMOTE_ADDR': '127.0.0.1', 'REMOTE_PORT': '12345', 'SERVER_ADDR': '127.0.0.1', 'SERVER_PORT': '80', 'SERVER_NAME': \"大众localhost\"大众, 'SERVER_PROTOCOL': 'HTTP/1.1' 'PHP_VALUE': 'auto_prepend_file = php://input', 'PHP_ADMIN_VALUE': 'allow_url_include = On' }
以上先容的只是对PHP-FPM进行攻击的正常流程,如果环境中增加了disable_functions的限定,如果利用包含PHP_VALUE==disable_function=的恶意FastCgi攻击FPM时,只能修正展示phpinfo信息的EG(ini_directives),也便是表面修正,对付已经禁用的函数无效的。
0X02 实例解析以SUCTF2019中的一道题为例easyphp,在得到webshell往后,创造有disable_functions的限定,这里可以通过与php-fpm进行通信来绕过open_basedir。
这里想要得到flag须要利用php_value对open_basedir的值进行重设
'PHP_VALUE': 'auto_prepend_file = php://input'+chr(0x0A)+'open_basedir = /',
官方给的环境很有问题,少了upload目录,须要自行加上,进去往后直接用官方给的exp复现也没成功,进去docker创造php-fpm根本没有起,emmmm醉了
直接在ubuntu16.04起一个phpfpm
sudo apt update sudo apt install -y nginx sudo apt install -y software-properties-common sudo add-apt-repository -y ppa:ondrej/php sudo apt update sudo apt install -y php7.3-fpm
修正nginx站点文件
sudo vim /etc/nginx/sites-enabled/default
启用unix socket模式
sudo vim /etc/php/7.3/fpm/pool.d/www.conf
配置php-fpm监听,将listen参数修正为127.0.0.1:9000
重启php-fpm和nginx
/etc/init.d/php7.3-fpm restart service nginx restart
修正相应的open_basedir
利用php-fpm通信来修正basedir,用p神的脚本修正一下
末了绕过open_basedir成功
参考链接
https://php-fpm.org/
https://www.awaimai.com/371.html
https://bugs.php.net/bug.php?id=70134
http://www.rai4over.cn/2019/06/11/PHP%E5%86%85%E6%A0%B8%E5%88%86%E6%9E%90-FPM%E5%92%8Cdisable-function%E5%AE%89%E5%85%A8%E9%97%AE%E9%A2%98/
https://www.cnblogs.com/Alight/p/4709753.html
https://forum.90sec.com/t/topic/129
https://www.leavesongs.com/PENETRATION/fastcgi-and-php-fpm.html
http://lonelyrain.me/2017/10/10/PHP%E8%87%AA%E5%8A%A8%E6%96%87%E4%BB%B6%E6%89%A9%E5%B1%95%E5%AE%89%E5%85%A8%E7%A0%94%E7%A9%B6/
声明:笔者初衷用于分享与遍及网络知识,若读者因此作出任何危害网络安全行为后果自大,与合天智汇及原作者无关!