ImageMagick CLAHE漏洞:无符号下溢与除零导致越界指针运算及进程崩溃

本文详细分析了CVE-2025-62594漏洞,该漏洞位于ImageMagick的CLAHE实现中。由于未对分块宽度/高度为零的情况进行验证,会导致无符号整数下溢和除零错误,进而引发越界内存访问和拒绝服务攻击。

ImageMagick CLAHE : Unsigned underflow and division-by-zero lead to OOB pointer arithmetic and process crash (DoS) · CVE-2025-62594

漏洞详情

摘要 CLAHE 实现中的一个根本原因——分块宽度/高度变为零——导致了两种不同但相关的危险行为。漏洞存在于 ImageMagick 的 MagickCore/enhance.c 文件的 CLAHEImage() 函数中。

  1. 无符号整数下溢 → 越界指针运算:当 tile_info.height == 0 时,表达式 tile_info.height - 1(无符号)会回绕为一个非常大的值;在指针运算中使用该值会产生巨大的偏移量,导致越界内存访问(进而导致内存损坏、SIGSEGV 或资源耗尽)。
  2. 除零/模零错误:在代码执行 ... / tile_info.width... % tile_info.height 时,未重新检查零值,导致在启用检测工具时立即发生除零崩溃,或在运行时异常终止。

这两种行为都由相同的无效分块条件触发(例如,命令行使用精确参数 -clahe 0x0!,或对于非常小的图像,自动分块推导 dim >> 3 == 0)。

详情

无符号下溢(可导致越界访问)

  • 位置:MagickCore/enhance.c,大约第609行
  • 测试版本:7.1.2-8(本地 ASan/UBSan 构建)
  • 易受攻击的代码
    1
    2
    
    enhance.c: 609
    p += (ptrdiff_t) clahe_info->width * (tile.height - 1);
    
  • 根本原因 如果 tile.height == 0,则 (tile.height - 1) 下溢为 UINT_MAX。 与 clahe_info->width 相乘会产生一个接近 SIZE_MAX 的巨大值。 将此值加到 p 会导致指针算术下溢。

除零错误

  • 文件/位置:MagickCore/enhance.c,大约第669-673行
  • 测试版本:7.1.2-8(本地 ASan/UBSan 构建)
  • 易受攻击的代码
    1
    2
    3
    4
    5
    6
    
    enhance.c: 669-673
    if ((image->columns % tile_info.width) != 0)
        tile_info.x=(ssize_t) (tile_info.width-(image->columns % tile_info.width));
    tile_info.y=0;
    if ((image->rows % tile_info.height) != 0)
        tile_info.y=(ssize_t) (tile_info.height-(image->rows % tile_info.height));
    
  • 根本原因 在计算默认分块尺寸后,缺少输入验证/边界检查: 如果 tile_info.widthtile_info.height 为 0,则会触发除零错误。零值可以通过以下方式到达此处:
    • 精确分块:命令行 clahe 0x0!! 强制直接使用零值)。
    • 微小图像的自动分块:当请求的分块为 0(没有 !)时,代码会从图像尺寸推导默认值(例如,dim >> 3)。对于 dim < 8 的图像,除非进行钳制,否则结果为 0。

复现步骤

无符号下溢

  • 环境:启用 AddressSanitizer 和 UndefinedBehaviorSanitizer 构建。
    1
    2
    
    export UBSAN_OPTIONS=print_stacktrace=1:halt_on_error=1
    export ASAN_OPTIONS=abort_on_error=1:allocator_may_return_null=1:detect_leaks=0
    
  • 命令
    1
    
    ./magick xc:black -clahe 0x0 null:
    
  • 输出
    1
    2
    
    MagickCore/enhance.c:609:6: runtime error: addition of unsigned offset overflowed
    SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior MagickCore/enhance.c:609:6 in CLAHEImage
    
    使用不同尺寸图像(如 10x102000x20004000x40008000x8000)会观察到内存区域损坏、内存消耗显著增加,并可能最终导致进程崩溃(DoS)。

除零错误

  • 环境:启用 ASan/UBSan 的构建。
    1
    2
    
    export UBSAN_OPTIONS=print_stacktrace=1:halt_on_error=1
    export ASAN_OPTIONS=abort_on_error=1:allocator_may_return_null=1:detect_leaks=0
    
  • 命令
    1
    
    ./magick -size 16x2 gradient: -type TrueColor -depth 8 -clahe 0x0! null:
    
  • 输出:触发除零异常。

影响

  • 主要影响拒绝服务——在处理通过命令行或 API 构造的参数或小图像时,导致崩溃或持续的资源耗尽(内存/缓存抖动)。攻击者可以通过 clahe 0x0! 或向使用 ImageMagick 的服务上传极小的图像来轻易触发。
  • 次要(理论上的)影响:越界内存访问和内存损坏可能与其他漏洞结合,导致更严重的后果;然而,仅凭这些 PoC 未证明能实现可靠的代码执行。

建议的补丁片段

在 CLAHEImage() 中,在 tile_info 计算之后,但在任何除法/模运算/指针运算之前应用:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
if (exact_tiles_requested && (tile_info.width == 0 || tile_info.height == 0)) {
    ThrowMagickException(exception, GetMagickModule(), OptionError,
                         "CLAHEInvalidTile", "%lux%lu",
                         (unsigned long) tile_info.width,
                         (unsigned long) tile_info.height);
    return (Image *) NULL;
}

if (!exact_tiles_requested) {
    tile_info.width  = (tile_info.width  == 0) ? MagickMax((size_t)1, image->columns >> 3) : tile_info.width;
    tile_info.height = (tile_info.height == 0) ? MagickMax((size_t)1, image->rows    >> 3) : tile_info.height;
}

if (tile_info.width == 0 || tile_info.height == 0) {
    ThrowMagickException(exception, GetMagickModule(), OptionError,
                         "CLAHEInvalidTile", "%lux%lu",
                         (unsigned long) tile_info.width,
                         (unsigned long) tile_info.height);
    return (Image *) NULL;
}

ssize_t tile_h_minus1 = (ssize_t)tile_info.height - 1;
if (tile_h_minus1 < 0) {
    ThrowMagickException(exception, GetMagickModule(), OptionError,
                         "CLAHEInvalidTile", "%lux%lu",
                         (unsigned long) tile_info.width,
                         (unsigned long) tile_info.height);
    return (Image *) NULL;
}
p += (ptrdiff_t) clahe_info->width * tile_h_minus1;

关于 exact_tiles_requested 的说明:如果 CLI/Wand 解析器已经暴露了是否存在 !,则使用它。如果没有,则添加一个解析时标志,以便 CLAHEImage 能够知道 0 是字面值还是自动推导值。

致谢

Team Whys Bug Hunting Master Program, HSpace/Findthegap Youngmin Kim kunshim@naver.com Woojin Park @jin-156 1203kids@gmail.com Youngin Won @amethyst0225 youngin04@korea.ac.kr Siyeon Han @hanbunny kokosyeon@gmail.com Shinyoung Won @yosiimich yosimich123@gmail.com

参考链接

安全信息

严重程度:中危 CVSS 总体评分:4.7 (AV:L/AC:H/PR:N/UI:R/S:U/C:N/I:N/A:H) 相关弱点

  • CWE-119:内存缓冲区边界内操作的限制不当
  • CWE-191:整数下溢(回绕)
  • CWE-369:除零错误
comments powered by Disqus
使用 Hugo 构建
主题 StackJimmy 设计