您当前的位置: 首页 > 

Z3eyOnd

暂无认证

  • 2浏览

    0关注

    117博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

SSRF--gopher协议打FastCGI

Z3eyOnd 发布时间:2021-11-30 21:16:08 ,浏览量:2

文章目录
    • FastCGI
      • 定义:
        • 什么是CGI
        • 什么是FastCGI
        • 什么是web服务器(web中间件)
        • 运行原理
      • FastCGI攻击原理
        • FastCGI协议
        • 漏洞原理
      • SSRF攻击FastCGI和PHP-FPM
        • 方法一:
        • 方法二:
      • 参考链接

FastCGI 定义: 什么是CGI
CGI全称"通用网关接口"(Common Gateway Interface),用于HTTP服务器与其它机器上的程序服务通信
交流的一种工具,CGI程序须运行在网络服务器上。

传统CGI接口方式的主要缺点是性能较差,因为每次HTTP服务器遇到动态程序时都需要重启解析器来执行
解析,然后结果被返回给HTTP服务器。这在处理高并发访问几乎是不可用的,因此就诞生了FastCGI。另
外传统的CGI接口方式安全性也很差。
什么是FastCGI
FastCGI是一个可伸缩地、高速地在HTTP服务器和动态脚本语言间通信的接口(FastCGI接口在Linux下是
socket(可以是文件socket,也可以是ip socket)),主要优点是把动态语言和HTTP服务器分离开来。多
数流行的HTTP服务器都支持FastCGI,包括Apache、Nginx和lightpd。

同时,FastCGI也被许多脚本语言所支持,比较流行的脚本语言之一为PHP。FastCGI接口方式采用C/S架
构,可以将HTTP服务器和脚本解析服务器分开,同时在脚本解析服务器上启动一个或多个脚本解析守护进
程。当HTTP服务器每次遇到动态程序时,可以将其直接交付给FastCGI进程执行,然后将得到的结构返回
给浏览器。这种方式可以让HTTP服务器专一地处理静态请求或者将动态脚本服务器的结果返回给客户端,
这在很大程度上提高了整个应用系统的性能。
什么是web服务器(web中间件)
Web服务器一般指网站服务器,是指驻留于因特网上某种类型计算机的程序,可以处理浏览器等Web客户端
的请求并返回相应响应,也可以放置网站文件,让全世界浏览;可以放置数据文件,让全世界下载。目前最
主流的三个Web服务器是Apache、 Nginx 、IIS。
运行原理

1.浏览器访问静态网页过程:

在整个网页的访问过程中,Web容器(例如Apache、Nginx)只担任着内容分发者的身份,当访问静态网站的
主页时,Web容器会到网站的相应目录中查找主页文件,然后发送给用户的浏览器

img

2.浏览器访问动态页面

当访问动态网站的主页时,根据容器的配置文件,它知道这个页面不是静态页面,web容器就会去找PHP解
析器来进行处理(这里以Apache为例),它会把这个请求进行简单的处理,然后交给PHP解释器

img

当Apache收到用户对 index.php 的请求后,如果使用的是CGI,会启动对应的 CGI 程序,对应在这里就是
PHP的解析器。接下来PHP解析器会解析php.ini文件,初始化执行环境,然后处理请求,再以规定CGI规定
的格式返回处理后的结果,退出进程,Web server再把结果返回给浏览器。这就是一个完整的动态PHP 
Web访问流程。

对于php中,web访问顺序:

web浏览器------>web中间件(web服务器)------->php服务器----->数据库

关于CGI和FastCGI的运行原理

下面是Nginx FastCGI的运行原理

Nginx不支持对外部动态程序的直接调用或者解析,所有的外部程序(包括PHP)必须通过FastCGI接口来
调用。FastCGI接口在Linux下是socket(可以是文件socket,也可以是ip socket)。为了调用CGI程序,还
需要一个FastCGI的wrapper,这个wrapper绑定在某个固定socket上,如端口或者文件socket。当Nginx将
CGI请求发送给这个socket的时候,通过FastCGI接口,wrapper接收到请求,然后派生出一个新的线程,这
个线程调用解释器或者外部程序处理脚本并读取返回数据;接着,wrapper再将返回的数据通过FastCGI接
口,沿着固定的socket传递给Nginx;最后,Nginx将返回的数据发送给客户端,这就是Nginx+FastCGI的整
个运作过程。

img

关于Java的: Java中常用WEB服务器和应用服务器_ZCC的专栏-CSDN博客_应用服务器

那什么又是FPM?

FPM(FastCGI 进程管理器)用于替换 PHP FastCGI 的大部分附加功能,对于高负载网站是非常有用的。

也就是说php-fpm是FastCGI的一个具体实现,并且提供了进程管理的功能,在其中的进程中,包含了
master和worker进程,这个在后面我们进行环境搭建的时候可以通过命令查看。其中master 进程负责与 
Web 服务器进行通信,接收 HTTP 请求,再将请求转发给 worker 进程进行处理,worker 进程主要负责动
态执行 PHP 代码,处理完成后,将处理结果返回给 Web 服务器,再由 Web 服务器将结果发送给客户端。

FastCGI攻击原理 FastCGI协议
HTTP协议是浏览器和服务器中间件进行数据交换的协议,类比HTTP协议来说,fastcgi协议则是服务器中间
件和某个语言后端(如PHP-FPM)进行数据交换的协议。

Fastcgi协议由多个record组成,record也有header和body一说,服务器中间件将这二者按照fastcgi的规则封
装好发送给语言后端(PHP-FPM),语言后端(PHP-FPM)解码以后拿到具体数据,进行指定操作,并将
结果再按照该协议封装好后返回给服务器中间件。

record的头固定8个字节,body是由头中的contentLength指定,其结构如下:

typedef struct {
  /* Header */
  unsigned char version; // 版本
  unsigned char type; // 本次record的类型
  unsigned char requestIdB1; // 本次record对应的请求id
  unsigned char requestIdB0;
  unsigned char contentLengthB1; // body体的大小
  unsigned char contentLengthB0;
  unsigned char paddingLength; // 额外块大小
  unsigned char reserved; 

  /* Body */
  unsigned char contentData[contentLength];
  unsigned char paddingData[paddingLength];
} FCGI_Record;
语言端(PHP-FPM)解析了FastCGI头以后,拿到contentLength,然后再在TCP流里读取大小等于
contentLength的数据,这就是body体

Body后面还有一段额外的数据(Padding),其长度由头中的paddingLength指定,起保留作用不需要该
Padding的时候,将其长度设置为0即可

注意:一个FastCGI record结构最大支持的body大小是2^16,也就是65536字节

type就是指定该record的作用。因为fastcgi一个record的大小是有限的,作用也是单一的, 所以我们需要在一个TCP流里传输多个record。通过type来标志每个record的作用,用 requestId作为同一次请求的id。

也就是说,每次请求,会有多个record,他们的requestId是相同的。

列出最主要的几种type

img

服务器中间件和后端语言(PHP-FPM)通信,第一个数据包就是type为1的record,后续互 相交流,发送type为4、5、6、7的record,结束时发送type为2、3的record

当后端语言接收到一个type为4的record后,就会把这个record的body按照对应的结构解析 成key-value对,这就是环境变量。环境变量的结构如下:

typedef struct {
  unsigned char nameLengthB0;  /* nameLengthB0  >> 7 == 0 */
  unsigned char valueLengthB0; /* valueLengthB0 >> 7 == 0 */
  unsigned char nameData[nameLength];
  unsigned char valueData[valueLength];
} FCGI_NameValuePair11;
 
typedef struct {
  unsigned char nameLengthB0;  /* nameLengthB0  >> 7 == 0 */
  unsigned char valueLengthB3; /* valueLengthB3 >> 7 == 1 */
  unsigned char valueLengthB2;
  unsigned char valueLengthB1;
  unsigned char valueLengthB0;
  unsigned char nameData[nameLength];
  unsigned char valueData[valueLength
          ((B3 & 0x7f) > 7 == 0 */
  unsigned char nameData[nameLength
          ((B3 & 0x7f) > 7 == 1 */
  unsigned char valueLengthB2;
  unsigned char valueLengthB1;
  unsigned char valueLengthB0;
  unsigned char nameData[nameLength
          ((B3 & 0x7f)             
关注
打赏
1651657201
查看更多评论
0.0373s