
摘要
本報告詳細描述了在 ImageMagick 的
magick mogrify
指令中發現的堆疊緩衝區溢位漏洞。此漏洞被歸類為 CWE-124(緩衝區下溢),其原因來自於
InterpretImageFilename()
函數在處理連續格式說明符(Format specifiers)的檔案名稱模板時的錯誤指標運算。這可能導致記憶體損壞,並可能引發任意程式碼執行。本報告提供了漏洞根本原因的技術分析、重現步驟,並討論了此類漏洞的影響。

1. 簡介
ImageMagick 是一個廣泛使用的開源軟體套件,用於顯示、轉換和編輯點陣圖檔案。其廣泛的功能使其成為從網頁服務到桌面工具等各種應用的關鍵組件。由於其普遍使用,ImageMagick 中的任何安全漏洞都可能帶來重大影響。本報告聚焦於近期披露的堆疊緩衝區溢位漏洞,影響 ImageMagick 7.1.1-47 及 6.9.13-25 之前的版本 [1]。該漏洞源於檔案名稱模板中格式說明符的錯誤處理,導致緩衝區下溢(Buffer underwrite)狀況。了解此漏洞的技術細節對於開發者和安全專業人員至關重要,以防止其他軟體中出現類似問題,並確保依賴 ImageMagick 的系統完整性。
2. 漏洞技術分析
漏洞的核心位於
MagickCore/image.c
中的
InterpretImageFilename()
函數。此函數負責解析和展開檔案名稱模板,這些模板可能包含像
%d
、
%o
和
%x
的格式說明符。這些說明符旨在在檔案名稱生成時被替換為整數值。關鍵缺陷在於輸出緩衝區位置的計算方式,特別是透過表達式
filename + (p - format - offset)
[1]。
offset
變數旨在根據格式說明符引入的長度變化來累計調整緩衝區位置。然而,實作中使用了靜態值來遞增
offset
:
offset += (4 - field_width)
。這個常數
4
可能是假設典型的四字元格式說明符(例如
%03d
)而選定的。當處理較少字元的格式說明符(如簡單的
%d
,兩個字元)或更長寬度規格(如
%010d
)時,這種假設會產生問題 [1]。
當檔案名稱模板中連續使用多個
%
說明符時,
offset
的累計遞增可能過大。這導致
offset
超過模板中的相對位置
p - format
。因此,計算出的寫入目標地址
filename + (p - format - offset)
指向了預定緩衝區開始之前的記憶體位置。這種狀況被稱為緩衝區下溢,具體分類為 CWE-124 [1, 2]。
緩衝區下溢發生在程式試圖將資料寫入分配緩衝區之前的記憶體地址時。這可能發生在索引或指標被減到緩衝區開始之前的位置,或當指標運算導致無效記憶體位置時 [2]。在此 ImageMagick 漏洞中,錯誤的偏移計算產生的負索引導致
vsnprintf()
函數寫入堆疊緩衝區之外的範圍。這種越界寫入可能損壞相鄰的記憶體區域,導致應用程式 Crash、拒絕服務,或在更嚴重的情況下,若攻擊者能控制損壞的記憶體,可能實現任意程式碼執行 [2]。
2.1 受影響的程式碼片段
以下來自
MagickCore/image.c
的程式碼片段展示了
InterpretImageFilename()
函數中的問題部分 [1]:
- MagickExport size_t InterpretImageFilename(const ImageInfo *image_info,
- Image *image,const char *format,int value,char *filename,
- ExceptionInfo *exception)
- {
- ...
- for (p=strchr(format,'%'); p != (char *) NULL; p=strchr(p+1,'%'))
- {
- q=(char *) p+1;
- if (*q == '%')
- {
- p=q+1;
- continue;
- }
- field_width=0;
- if (*q == '0')
- field_width=(ssize_t) strtol(q,&q,10);
- switch (*q)
- {
- case 'd':
- case 'o':
- case 'x':
- {
- q++;
- c=(*q);
- *q='\0';
- /*--------Affected--------*/
- (void) FormatLocaleString(filename+(p-format-offset),(size_t)
- (MagickPathExtent-(p-format-offset)),p,value);
- offset+=(4-field_width);
- /*--------Affected--------*/
- *q=c;
- (void) ConcatenateMagickString(filename,q,MagickPathExtent);
- canonical=MagickTrue;
- if (*(q-1) != '%')
- break;
- p++;
- break;
- }
- case '[':
- {
- ...
- }
- default:
- break;
- }
- }
標記為
/*--------Affected--------*/
的行突顯了
FormatLocaleString()
函數被呼叫時使用了可能為負的偏移,以及
offset
變數被錯誤遞增的位置。這種靜態且與模板無關的校正處理設計是此漏洞的根本原因 [1]。
3. 重現步驟
在受控環境中,可以透過以下步驟重現該漏洞 [1]:
3.1 測試環境
- 作業系統: Ubuntu 22.04 LTS
- 架構: x86_64
- 編譯器: 帶有 AddressSanitizer 的 gcc(gcc 版本:11.4.0)
3.2 重現步驟
- # Clone source
- git clone --depth 1 --branch 7.1.1-47 https://github.com/ImageMagick/ImageMagick.git ImageMagick-7.1.1
- cd ImageMagick-7.1.1
- # Build with ASan
- CFLAGS="-g -O0 -fsanitize=address -fno-omit-frame-pointer" CXXFLAGS="$CFLAGS" LDFLAGS="-fsanitize=address" ./configure --enable-maintainer-mode --enable-shared && make -j$(nproc) && make install
- # Trigger crash
- ./utilities/magick mogrify %d%d
3.3 預期輸出(AddressSanitizer 報告)
執行
magick mogrify %d%d
指令後,AddressSanitizer(ASan)將檢測到堆疊緩衝區溢位,並產生類似以下的輸出 [1]:
==4155==ERROR: AddressSanitizer: stack-buffer-overflow on address 0x7ffda834caae at pc 0x7f1ea367fb27 bp 0x7ffda834b680 sp 0x7ffda834ae10 WRITE of size 2 at 0x7ffda834caae thread T0 #0 0x7f1ea367fb26 in __interceptor_vsnprintf ../../../../src/libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc:1668 #1 0x7f1ea2dc9e3e in FormatLocaleStringList MagickCore/locale.c:470 #2 0x7f1ea2dc9fd9 in FormatLocaleString MagickCore/locale.c:495 #3 0x7f1ea2da0ad5 in InterpretImageFilename MagickCore/image.c:1696 #4 0x7f1ea2c6126b in ReadImages MagickCore/constitute.c:1051 #5 0x7f1ea27ef29b in MogrifyImageCommand MagickWand/mogrify.c:3858 #6 0x7f1ea278e95d in MagickCommandGenesis MagickWand/magick-cli.c:177 #7 0x560813499a0c in MagickMain utilities/magick.c:153 #8 0x560813499cba in main utilities/magick.c:184 #9 0x7f1ea1c0bd8f in __libc_start_call_main ../sysdeps/nptl/libc_start_call_main.h:58 #10 0x7f1ea1c0be3f in __libc_start_main_impl ../csu/libc-start.c:392 #11 0x560813499404 in _start (/root/workdir/ImageMagick/utilities/.libs/magick+0x2404) Address 0x7ffda834caae is located in stack of thread T0 at offset 62 in frame #0 0x7f1ea2c60f62 in ReadImages MagickCore/constitute.c:1027 This frame has 2 object(s): [32, 40) 'images' (line 1033) [64, 4160) 'read_filename' (line 1029) <== Memory access at offset 62 underflows this variable HINT: this may be a false positive if your program uses some custom stack unwind mechanism, swapcontext or vfork (longjmp and C++ exceptions *are* supported) SUMMARY: AddressSanitizer: stack-buffer-overflow ../../../../src/libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc:1668 in __interceptor_vsnprintf
ASan 報告清楚顯示來自
__interceptor_vsnprintf
的
stack-buffer-overflow
,問題記憶體存取發生在
read_filename
變數下溢的偏移處 [1]。這證實了緩衝區下溢狀況及其對記憶體完整性的影響。
4. 影響與緩解措施
堆疊緩衝區溢位,特別是緩衝區下溢,可能造成嚴重影響。如所示,它導致記憶體損壞,可能引發應用程式不穩定、Crash或拒絕服務。更嚴重的是,若攻擊者能控制寫入下溢緩衝區的資料,他們可能實現任意程式碼執行。這將允許他們在有漏洞的應用程式環境中執行 malicious payload,潛在導致系統完全被入侵 [2]。
已修補的版本 7.1.2-0 和 6.9.13-26 解決了此漏洞 [1]。強烈建議 ImageMagick 使用者立即升級到這些或更新版本以降低風險。從開發角度看,此漏洞凸顯了謹慎進行指標運算和穩健處理緩衝區的重要性,特別是在處理動態字串格式化和使用者控制的輸入時。開發者應採用安全的程式設計實務,包括徹底的輸入驗證和使用防止緩衝區溢位的函數(例如帶有適當大小檢查的
snprintf
)[3]。靜態分析工具和動態分析工具(如 AddressSanitizer)在開發和測試階段識別此類記憶體安全問題方面極具價值。
5. 結論
ImageMagick 的
InterpretImageFilename()
函數中的堆疊緩衝區溢位是一個關鍵提醒,記憶體安全漏洞的微妙但危險性質。該缺陷源於檔案名稱模板展開期間的錯誤偏移計算,突顯了指標運算中的看似微小的邏輯錯誤可能導致嚴重的安全影響。透過了解此 CWE-124 漏洞的技術細節並採用安全的程式設計實務,開發者可顯著提升應用程式對類似攻擊的韌性。定期更新軟體依賴項和全面的安全測試對於維持安全的軟體生態系統至關重要。