首页 > 编程语言 >FastCGI访问PHP-FPM实现任意代码执行

FastCGI访问PHP-FPM实现任意代码执行

时间:2024-01-18 16:36:05浏览次数:37  
标签:文件 php FPM unsigned char 访问 代码执行 PHP FastCGI

之前学习web的Nginx解析漏洞就看到了FastCGI协议,今天学习一下。顺便看看有什么漏洞可以复现

Nginx解析漏洞

Nginx接受用户的http请求后生成的cgi环境变量有一SCRIPIT_NAME和PATH_INFO比如想要请求
/var/www/html/example.gif/.php那么/var/www/html/example.gif就是SCRIPT_NAME
/.php就是PATH_INFO之后我们就知道了,原本这两者应该分开,但是nginx将这两个一起交给php解释器去定位php文件
那么不存在这个文件就会报错了
包括php.ini中有一个那个选项是fix_pathinfo那么如果给的文件不存在,会去掉最后一个\之后的内容再去寻找,这就导致了解析漏洞,所以本质上其实就是配置错误的运维漏洞
想要检测也是很简单
这个漏洞会导致nginx将任意文件解析成php文件
比如web根目录下的robots.txt文件,如果我们访问robots.txt/.php
我们bp抓包后看到如果已经是Content-Type是text/html并且由php指纹
x-powered-by指定php解释器

php-fpm介绍

php作为一个服务端脚本编程语言,能够使用它制作强大功能的动态网页。一度被称之为世界上最好的编程语言。在大型企业内部,php往往以php-fpm的形式存在的。php-fpm是php官方提供的进程管理器,他是后台的一个守护进程,能够根据负载情况,管理不定数量的子进程。其中包括php处理器,能够接受web server传来的cgi环境变量,定位解析php文件,返回html代码。
大部分情况下php-fpm会通过fastCGI协议于web server之间进行通信。主要是传送一些环境变量

FastCgi协议介绍

fastcgi协议是一个二进制流通信协议,用于web server和其他应用服务之间通信。数据包称之为记录record。分为记录头Header和记录体Body,其中头部固定8字节长度,Body由header的contentlength决定
下面可以看一下record的c语言代码

typedef struct{
   /*Header*/
   unsigned char version;  //版本
   unsigned char type;  //本次record类型
   unsigned char requestIdB1;  //请求id,两个字节记录
   unsigned char requestIdB0;  
   unsigned char contentLength1;  //Body长度,两个字节记录
   unsigned char contentLength0;  
   unsigned char paddingLength;  //填充长度
   unsigned char reserved;  //保留字节

   /*Body*/
   unsigned char contentData [coontentLength];
   unsigned char paddingData [paddingLength];
} FCGI_Record;

fastcgi记录类型

fastcgi的数据包称之为record,它的type下面几种
FCGI_PARAMS #传递应用的cgi环境变量,name-value形式,最常用的一个type
FCGI_STDIN #服务器传递给应用的标准输入
FCGI_DATA #发送过滤器处理后的数据给应用
FCGI_STDOUT #应用返回服务器的标准输出
FCGI_STDERR #应用返回服务器的标注错误
FCGI_END_REQUEST #表示结束此次请求。可以是服务器或者应用发送的
其中当type是PARAMS的时候,web server发送cgi环境变量给应用。这个cgi环境变量其实就是各种配置。
name-value形式有四种实现方式。FastCGI会根据长度自动选择合适的,减少内存消耗

typedef struct{
  unsigned char nameLengthB0;
  unsigned char valueLengthB0;
  unsigned char nameData[nameLength];
  unsigned char valueData[valuelength];
}FCGI_NameValuePair11;

typedef struct{
  unsigned char nameLengthB0;
  unsigned char nameLengthB1;
  unsigned char nameLengthB2;
  unsigned char nameLengthB3;
  unsigned char valueLengthB0;
  unsigned char nameData[nameLength((B3 & 0x7f)<<24)+ (B2<<16)+(B1<<8)+B0];
  unsigned char valueData[valuelength];
}FCGI_NameValuePair41;

typedef struct{
  unsigned char nameLengthB0;
  unsigned char valueLengthB0;
  unsigned char valueLengthB1;
  unsigned char valueLengthB2;
  unsigned char valueLengthB3;
  unsigned char nameData[nameLength];
  unsigned char valueData[valuelength((B3 & 0x7f)<<24)+ (B2<<16)+(B1<<8)+B0];
}FCGI_NameValuePair14;

typedef struct{
  unsigned char nameLengthB0;
  unsigned char nameLengthB1;
  unsigned char nameLengthB2;
  unsigned char nameLengthB3;
  unsigned char valueLengthB0;
  unsigned char valueLengthB1;
  unsigned char valueLengthB2;
  unsigned char valueLengthB3;
  unsigned char nameData[nameLength((B3 & 0x7f)<<24)+ (B2<<16)+(B1<<8)+B0];
  unsigned char valueData[valuelength((B3 & 0x7f)<<24)+ (B2<<16)+(B1<<8)+B0];
}FCGI_NameValuePair44;

其实就是看key和value长度来分1一个字节还是4个字节
name,value都小于128B的时候, 使用FCGI_NameValuePair11;
name>128B value<128B 使用FCGI_NameValuePair41;
name<128B value<128B 使用FCGI_NameValuePair14;
name>128B value>128B 使用FCGI_NameValuePair44;

常见的CGI环境变量

REQUEST_METHOD                http请求方式
SCRIPT_FILENAME               用户想要访问的文件名,绝对路径
SCRIPT_NAME                   用户想要访问的文件名,相对路径
QUERY_STRING                  http请求传递的参数 包括get和post
DOCUMENT_ROOT                 web根目录
REMOTE_ADDR                   用户ip地址

FastCGI漏洞

FastCGI默认监听9000端口,如果它暴露出来,没有防火墙对不信任ip的隔离策略,我们就可以自己构造FastCGI协议的记录,直接发送给PHP-FPM。都不需要经过web server了。其中特别重要的是SCRIPT_FILENAME这个变量。在php-fpm某个版本之前,都是比可以指定任意后缀名文件的。
但是后来出现一个配置 security.limit_extensions = .php .php3 .php4
image
这时我们只能访问php后缀的文件,而且得去寻找现有的文件 这显然不是那么好使用的漏洞。怎么样能够任意代码执行呢?
我当时想到了php.ini的一个配置 auto_prepend_file:它可以指定一个文件,让访问一个php文件之前就包含它,相当于include
这一招在ctf里面很常见,我们通常会上传一个文件 .user.ini
里面写入 auto_prepend_file=/var/log/nginx/access.log 让他指定nginx的访问日志
然后访问index.php 就会自动 include('/var/log/nginx/access.log');
这样我们只需要在http请求头里
User-Agent: 便成功制成了一个后门文件
比如 CTFSHOW有一题文件上传 https://ctf.show/challenges#web169-612,感兴趣可以去试试,解题原理就是利用.user.ini自动包含日志
这时我们只能访问php后缀的文件,而且得去寻找现有的文件 这显然不是那么好使用的漏洞。怎么样能够任意代码执行呢?
我当时想到了php.ini的一个配置 auto_prepend_file:它可以指定一个文件,让访问一个php文件之前就包含它,相当于include
这一招在ctf里面很常见,我们通常会上传一个文件 .user.ini
里面写入 auto_prepend_file=/var/log/nginx/access.log 让他指定nginx的访问日志
然后访问index.php 就会自动 include('/var/log/nginx/access.log');
这样我们只需要在http请求头里
User-Agent: 便成功制成了一个后门文件
比如 CTFSHOW有一题文件上传 https://ctf.show/challenges#web169-612 感兴趣可以去试试,解题原理就是利用.user.ini自动包含日志
但是这一招确实需要一个文件上传的接口,还是有局限性的


不上传文件.user.ini我们能不能设置呢?
答案是可以的,因为FastCGI给了两个环境变量,PHP_VALUE和PHP_ADMIN_VALUE 就是用来配置php的
而且还可以额外配置一个allow_url_include这样就支持文件包含使用伪协议
如此 我们可以通过FastCGI协议直接给PHP-FPM传入环境变量
自己编写脚本写一个fpm的记录还是挺烦的,直接使用p神的脚本了,修改一下地址就行
来源:https://gist.github.com/phith0n/9615e2420f31048f7e30f3937356cf75
首先还是Docker开启一下环境
image
然后Nmap看看是否开启了服务
image
Nmap扫除了端口时开发的,却没有识别出来9000端口服务是FastCGI啊
端口就这样直接开放了,我们直接访问FastCGI访问
image

从脚本中可以看到,就是使用POST方式访问
然后指定访问文件/usr/local/lib/php/System.php。并且配置了包含php://input,本质就是包含了请求体里的参数,所以,将payload写进了post的请求体里面
访问后PHP-FPM就会解析对应的/usr/local/lib/php/System.php文件
image

从结果看,PHP-FPM返回的确实是html代码
image

标签:文件,php,FPM,unsigned,char,访问,代码执行,PHP,FastCGI
From: https://www.cnblogs.com/Erebussss/p/17972791

相关文章

  • PHP把数组按指定的个数分隔
    假设数组为array(‘1’,‘2’,‘3’,‘4’,‘5’,‘6’);想把它分割成四个,那么结果为array( ‘0’=>[‘1’,‘2’], ‘1’=>[‘3’,‘4’], ‘2’=>[‘5’], ‘3’=>[‘6’],);/****把数组按指定的个数分隔*@paramarray$array要分割的数组*@par......
  • PHP LFI/RFI Vulnerability attack bypassing remote URL inclusion restriction
    FileInclusionvulnerabilityInthePHPConfiguration,"allow_url_include" wrapperby-defaultsetto"Off"whichinstructPHPnototloadremoteHTTPorFTPurls.HencepreventRemoteFileInclusionattack.ButPHPdoesnotblockSMBURL......
  • thinkphp 操作mysql数据库
    获取当前路由信息useapp\BaseController;//引入控制器publicfunctionindex(){//返回当前实际路径return$this->app->getAppPath();//返回当前方法名//return$this->request->action();}载入的控制器不存在......
  • 开启php8的JIT 才能提现php8的速度
    找到php版本文件夹下面的php.ini文件,开启如下字段:zend_extension=opcache修改如下字段:[opcache];DeterminesifZendOPCacheisenabledopcache.enable=1;DeterminesifZendOPCacheisenabledfortheCLIversionofPHPopcache.enable_cli=0;TheOPcache......
  • thinkphp5详细使用阿里云短信最新版
    1.我们下载官方完整包,PHP版本 https://help.aliyun.com/document_detail/55359.html?spm=5176.doc55451.6.580.3rgXTq 解压后得到目录2.将目录里的api_sdk复制出来到tp5根目录的extend下面文件夹复制过去后,我们最好更改一下名称,比如我们更改为alisms。 3.使用方法直接......
  • Confluence Server && Confluence Data Center 远程代码执行漏洞预警
    影响产品ConfluenceServer、ConfluenceDataCenter漏洞类型远程代码执行危害等级高CVE编号CVE-2024-21672CVE-2024-21673CVE-2024-21674CVSS评分:CVE-2024-21672:8.3CVE-2024-21673:8CVE-2024-21674:8.6影响范围:CVE-2024-216727.13.0,7.19.0,8.0.0,8.1.0,8.......
  • php生成图片二维码
    使用php类库PHPQRCode地址:http://phpqrcode.sourceforge.net/下载:http://sourceforge.net/projects/phpqrcode/下载官网提供的类库后,只需要使用phpqrcode.php就可以生成二维码了,当然您的PHP环境必须开启支持GD2。phpqrcode.php提供了一个关键的png()方法,其中参数$frame表示......
  • PHP开发API接口签名生成及验证
    开发过程中,我们经常会与接口打交道,有的时候是调取别人网站的接口,有的时候是为他人提供自己网站的接口,但是在这调取的过程中都离不开签名验证。我们在设计签名验证的时候,请注意要满足以下几点:可变性:每次的签名必须是不一样的。时效性:每次请求的时效,过期作废等。唯一性:每次的签......
  • 在Linux上使用PHP-FPM与Nginx实现高效的HTTP处理
    当谈到高效的HTTP处理时,PHP-FPM(FastCGI进程管理器)与Nginx的结合是许多web开发者的首选。这种组合提供了出色的性能、可扩展性和稳定性,尤其适用于高流量的网站和应用程序。1.为什么选择PHP-FPM与Nginx?· 性能优化:PHP-FPM通过进程管理和缓存机制,显著提高了PHP脚本的执行效率。· ......
  • PHP面试常用的几种算法(建议收藏)
    1.冒泡排序,对像可以是数组functionbubble_sort($array){$count=count($array);if($count<=0){returnfalse;}for($i=0;$i<$count;$i++){for($j=$count-1;$j>$i;$j--){if($array[$j]<$array[$j-1]){......