php-fpm RCE的POC的理解剖析(CVE-2019-11043)
字数 1717 2025-08-26 22:11:28

PHP-FPM RCE漏洞分析(CVE-2019-11043)深度剖析

漏洞概述

CVE-2019-11043是一个PHP-FPM(FastCGI进程管理器)中的远程代码执行漏洞,影响PHP 7.x版本。该漏洞源于PHP-FPM在处理某些特殊构造的HTTP请求时存在路径解析问题,导致攻击者可以通过精心构造的请求实现任意代码执行。

漏洞环境要求

  • PHP版本:7.x
  • PHP-FPM配置要求:
    [global]
    error_log = /proc/self/fd/2
    daemonize = no
    [www]
    access.log = /proc/self/fd/2
    clear_env = no
    listen = 127.0.0.1:9000
    pm = dynamic
    pm.max_children = 5
    pm.start_servers = 1
    pm.min_spare_servers = 1
    pm.max_spare_servers = 1
    
  • Nginx配置要求:
    fastcgi_split_path_info ^(.+?\.php)(/.*)$;
    

漏洞原理分析

异常行为触发

当发送如下请求时:

GET /index.php/test%0atest HTTP/1.1
Host: 192.168.15.166

正常情况下,nginx传给php-fpm的变量中:

  • SCRIPT_NAME应为/index.php/test\ntest
  • PATH_INFO应为空

但实际$_SERVER["PATH_INFO"]却显示有值,这表明存在异常解析行为。

调试分析

fcgi_accept_request函数中,init_request_info函数负责初始化请求全局变量。关键问题出现在路径自动修复的代码中:

  1. script_path_translated指向SCRIPT_FILENAME(如/var/www/html/index.php/test\ntest
  2. tsrm_realpath尝试获取绝对路径,因路径不存在返回NULL
  3. 进入while循环尝试路径修复:
    while ((ptr = strrchr(pt, '/')) || (ptr = strrchr(pt, '\\'))) {
        *ptr = 0;
        if (stat(pt, &st) == 0 && S_ISREG(st.st_mode)) {
            // 路径修复逻辑
        }
    }
    

关键问题在于:

path_info = env_path_info ? env_path_info + pilen - slen : NULL;
tflag = (orig_path_info != path_info);

其中:

  • pilenPATH_INFO长度(初始为0)
  • slen/test\ntest的长度(攻击者可控)

这导致path_info指向env_path_infoslen字节的位置,造成内存越界访问。

漏洞利用点

漏洞本质是一个任意地址单字节置NULL的漏洞:

  1. 只能在env_path_info之前的某个位置修改一个字节为\x0
  2. 修改的影响必须在字节被改回前触发

利用的关键在于:

  1. 通过控制slen/test\ntest的长度)来精确控制修改位置
  2. 利用FCGI_PUTENV(request, "ORIG_SCRIPT_NAME", orig_script_name)或类似函数触发内存修改的影响

内存布局分析

PHP-FPM使用以下关键结构存储环境变量:

struct _fcgi_hash {
    fcgi_hash_bucket  *hash_table[FCGI_HASH_TABLE_SIZE];
    fcgi_hash_bucket  *list;
    fcgi_hash_buckets *buckets;
    fcgi_data_seg     *data;
};

typedef struct _fcgi_data_seg {
    char                  *pos;
    char                  *end;
    struct _fcgi_data_seg *next;
    char                   data[1];  // 实际存储环境变量的空间
} fcgi_data_seg;

环境变量存储在fcgi_data_seg.data中,布局如下:

+---------------------+
|        pos          |--------------------------------------------+  
+---------------------+                                            |
|        end          |                                            |
+---------------------+                                            |
|      next = 0       |                                            |
+---------------------+-------------------------|------------------+-------——+
|      data = xxxx    |SCRIPT_NAME\0/index.php\0|PATH_INFO\0/test\0|未使用空间 |
+---------------------+-------------------------|------------------+---------+

精妙的漏洞利用

利用步骤

  1. 触发malloc:通过发送大量查询参数使现有fcgi_data_seg空间不足,触发新chunk分配

    GET /index.php/PHP%0Ais_the_shittiest_lang.php?QQQQ...QQQ HTTP/1.1
    
  2. 精确控制偏移:当服务器返回404时,表明已触发malloc且PATH_INFO存储在新chunk首部

  3. 计算精确偏移

    • env_path_infofcgi_data_seg.pos的固定偏移为34字节
    • 通过控制/PHP%0Ais_the_shittiest_lang.php长度为30,使修改pos的第5字节
  4. 覆盖关键数据

    • 伪造HTTP_EBUT变量(与PHP_VALUE长度和hash相同)
    • 通过修改pos指针,使后续写入操作覆盖HTTP_EBUTPHP_VALUE
  5. 实现RCE

    • 设置PHP_VALUE为恶意配置,如:
      PHP_VALUE%0Aauto_prepend_file=php://input
      PHP_VALUE%0Asession.auto_start=1
      

完整利用请求示例

GET /index.php/PHP_VALUE%0Asession.auto_start=1;;;?QQQQ...QQQ HTTP/1.1
Host: localhost
User-Agent: Mozilla/5.0
D-Pisos: 8===========================================================D
Ebut: mamku tvoyu

其中:

  • D-Pisos头部用于调整内存布局,将HTTP_EBUT推到合适位置
  • 当响应中出现Set-Cookie头时,表明PHP_VALUE覆盖成功

漏洞修复

PHP官方在以下commit中修复了该漏洞:
https://github.com/php/php-src/commit/ab061f95ca966731b1c84cf5b7b20155c0a1c06a

修复方法:

  • 在路径修复逻辑中添加了更严格的边界检查
  • 防止了路径解析时的内存越界问题

总结

CVE-2019-11043是一个极其精巧的漏洞,其利用过程展示了:

  1. 如何将一个看似无害的单字节NULL写入转化为完整的RCE
  2. 如何通过精确控制内存布局实现漏洞利用
  3. Web漏洞与二进制漏洞的结合利用技巧

该漏洞的发现和利用过程体现了安全研究人员对PHP-FPM内部机制的深刻理解,以及创造性的漏洞利用思路。

PHP-FPM RCE漏洞分析(CVE-2019-11043)深度剖析 漏洞概述 CVE-2019-11043是一个PHP-FPM(FastCGI进程管理器)中的远程代码执行漏洞,影响PHP 7.x版本。该漏洞源于PHP-FPM在处理某些特殊构造的HTTP请求时存在路径解析问题,导致攻击者可以通过精心构造的请求实现任意代码执行。 漏洞环境要求 PHP版本:7.x PHP-FPM配置要求: Nginx配置要求: 漏洞原理分析 异常行为触发 当发送如下请求时: 正常情况下,nginx传给php-fpm的变量中: SCRIPT_NAME 应为 /index.php/test\ntest PATH_INFO 应为空 但实际 $_SERVER["PATH_INFO"] 却显示有值,这表明存在异常解析行为。 调试分析 在 fcgi_accept_request 函数中, init_request_info 函数负责初始化请求全局变量。关键问题出现在路径自动修复的代码中: script_path_translated 指向 SCRIPT_FILENAME (如 /var/www/html/index.php/test\ntest ) tsrm_realpath 尝试获取绝对路径,因路径不存在返回NULL 进入while循环尝试路径修复: 关键问题在于: 其中: pilen 是 PATH_INFO 长度(初始为0) slen 是 /test\ntest 的长度(攻击者可控) 这导致 path_info 指向 env_path_info 前 slen 字节的位置,造成内存越界访问。 漏洞利用点 漏洞本质是一个任意地址单字节置NULL的漏洞: 只能在 env_path_info 之前的某个位置修改一个字节为 \x0 修改的影响必须在字节被改回前触发 利用的关键在于: 通过控制 slen ( /test\ntest 的长度)来精确控制修改位置 利用 FCGI_PUTENV(request, "ORIG_SCRIPT_NAME", orig_script_name) 或类似函数触发内存修改的影响 内存布局分析 PHP-FPM使用以下关键结构存储环境变量: 环境变量存储在 fcgi_data_seg.data 中,布局如下: 精妙的漏洞利用 利用步骤 触发malloc :通过发送大量查询参数使现有 fcgi_data_seg 空间不足,触发新chunk分配 精确控制偏移 :当服务器返回404时,表明已触发malloc且PATH_ INFO存储在新chunk首部 计算精确偏移 : env_path_info 与 fcgi_data_seg.pos 的固定偏移为34字节 通过控制 /PHP%0Ais_the_shittiest_lang.php 长度为30,使修改 pos 的第5字节 覆盖关键数据 : 伪造 HTTP_EBUT 变量(与 PHP_VALUE 长度和hash相同) 通过修改 pos 指针,使后续写入操作覆盖 HTTP_EBUT 为 PHP_VALUE 实现RCE : 设置 PHP_VALUE 为恶意配置,如: 完整利用请求示例 其中: D-Pisos 头部用于调整内存布局,将 HTTP_EBUT 推到合适位置 当响应中出现 Set-Cookie 头时,表明 PHP_VALUE 覆盖成功 漏洞修复 PHP官方在以下commit中修复了该漏洞: https://github.com/php/php-src/commit/ab061f95ca966731b1c84cf5b7b20155c0a1c06a 修复方法: 在路径修复逻辑中添加了更严格的边界检查 防止了路径解析时的内存越界问题 总结 CVE-2019-11043是一个极其精巧的漏洞,其利用过程展示了: 如何将一个看似无害的单字节NULL写入转化为完整的RCE 如何通过精确控制内存布局实现漏洞利用 Web漏洞与二进制漏洞的结合利用技巧 该漏洞的发现和利用过程体现了安全研究人员对PHP-FPM内部机制的深刻理解,以及创造性的漏洞利用思路。