专栏名称: 独眼情报
分享有价值的网络安全威胁情报!情报有时效性,加星标可以及时收到推送。
目录
相关文章推荐
芋道源码  ·  负载均衡 LVS vs Nginx ... ·  12 小时前  
黑马程序员  ·  Java革命,来了! ·  16 小时前  
混在邯郸  ·  邯郸成立1个新组织! ·  昨天  
混在邯郸  ·  邯郸成立1个新组织! ·  昨天  
ImportNew  ·  亚马逊程序员破防:AI ... ·  2 天前  
51好读  ›  专栏  ›  独眼情报

攻击 FastCGI 库:CVE-2025-23016

独眼情报  · 公众号  ·  · 2025-04-24 11:57

正文

请到「今天看啥」查看全文



}

到目前为止一切顺利,问题出在对 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 中作为参数传递了大小。我们需要确保使用的参数是流中的最后一个参数。

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

演示环境







请到「今天看啥」查看全文