
GNOME gThumb 및 Linux Mint Pix의 힙 버퍼 오버플로
GNOME gThumb과 Linux Mint Pix는 Cairo 그래픽 라이브러리로 여러 이미지 형식을 표시하기 위해 cairo_io 모듈을 사용합니다. gThumb 3.8.3 미만 및 Pix 2.4.5 미만 버전에서 cairo_io는 너비 또는 높이가 32767픽셀을 초과하는 JPEG 이미지를 통해 힙 버퍼 오버플로에 취약합니다. 이 취약점은 extensions/cairo_io/cairo-image-surface-jpeg.c의 _cairo_image_surface_create_from_jpeg() 함수에 존재합니다.
cairo_io는 최대 JPEG 크기인 32767 x 32767(CAIRO_MAX_IMAGE_SIZE)을 지원합니다.1 Cairo 표면을 할당할 때 _cairo_image_surface_create_from_jpeg()는 너비와 높이 모두에 대해 CAIRO_MAX_IMAGE_SIZE와 파일의 SOF0 세그먼트에 지정된 길이 중 최솟값을 선택합니다. 예를 들어 JPEG 파일이 40000 x 30000 크기라고 명시하면 cairo_io는 32767 x 30000픽셀에 대해서만 유효한 cairo_surface_t 객체를 할당합니다.
아래 코드 조각에서 srcinfo.output_width와 srcinfo.output_height는 원본 이미지 크기이고, destination_width와 destination_height는 상한이 적용된 크기입니다. 후자는 표면 생성을 위해 _cairo_image_surface_create()에 전달되는 값입니다.2
_cairo_image_surface_transform_get_steps (CAIRO_FORMAT_ARGB32,
MIN (srcinfo.output_width, CAIRO_MAX_IMAGE_SIZE),
MIN (srcinfo.output_height, CAIRO_MAX_IMAGE_SIZE),
orientation,
&destination_width,
&destination_height,
&line_start,
&line_step,
&pixel_step);
// ...
surface = _cairo_image_surface_create (CAIRO_FORMAT_ARGB32, destination_width, destination_height);
그러나 할당된 표면에 픽셀 데이터를 쓸 때 _cairo_image_surface_create_from_jpeg()는 적절한 destination_width 및 destination_height 대신 JPEG에 지정된 원본 크기인 srcinfo.output_width와 srcinfo.output_height를 기준으로 반복합니다. 아래의 중첩 루프 구조는 각각 서로 다른 색상 공간을 처리하는 cairo-image-surface-jpeg.c의 다섯 위치에 존재합니다.3 4 5 6 7
while (srcinfo.output_scanline < srcinfo.output_height) {
// ...
for (x = 0; x < srcinfo.output_width; x++) {
// ...
memcpy (p_surface, &pixel, sizeof (guint32));
원본 JPEG 크기가 표면용으로 지정된 메모리 영역보다 클 수 있으므로 이러한 불일치로 인해 공격자가 제어하는 픽셀 데이터가 cairo_surface_t 구조체의 data 버퍼 경계를 벗어나 기록될 수 있습니다.
최소화된 테스트 케이스인 poc.min.jpg를 참조하십시오. 이 파일은 107바이트이며 1 x 33000 크기를 지정합니다.
$ gthumb ./poc.min.jpg
=================================================================
==20729==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x7f49fdc587fc at pc 0x7f4a12200534 bp 0x7f49fe46e240 sp 0x7f49fe46e230
WRITE of size 4 at 0x7f49fdc587fc thread T5 (pool-gthumb)
#0 0x7f4a12200533 in _cairo_image_surface_create_from_jpeg ../extensions/cairo_io/cairo-image-surface-jpeg.c:372
#1 0x55b8e24aad9b in load_image_thread ../gthumb/gth-image-loader.c:241
#2 0x7f4a1a1a5d21 (/lib/x86_64-linux-gnu/libgio-2.0.so.0+0xb2d21)
#3 0x7f4a1a34f853 (/lib/x86_64-linux-gnu/libglib-2.0.so.0+0x7b853)
#4 0x7f4a1a34f110 (/lib/x86_64-linux-gnu/libglib-2.0.so.0+0x7b110)
#5 0x7f4a19668668 in start_thread /build/glibc-4WA41p/glibc-2.30/nptl/pthread_create.c:479
#6 0x7f4a19590322 in clone (/lib/x86_64-linux-gnu/libc.so.6+0x122322)
0x7f49fdc587fc is located 0 bytes to the right of 131068-byte region [0x7f49fdc38800,0x7f49fdc587fc)
allocated by thread T5 (pool-gthumb) here:
#0 0x7f4a1a658ce6 in calloc (/lib/x86_64-linux-gnu/libasan.so.5+0x10dce6)
#1 0x7f4a18aba5a1 (/lib/x86_64-linux-gnu/libpixman-1.so.0+0x1a5a1)
Thread T5 (pool-gthumb) created by T0 here:
#0 0x7f4a1a585805 in pthread_create (/lib/x86_64-linux-gnu/libasan.so.5+0x3a805)
#1 0x7f4a1a371a16 (/lib/x86_64-linux-gnu/libglib-2.0.so.0+0x9da16)
SUMMARY: AddressSanitizer: heap-buffer-overflow ../extensions/cairo_io/cairo-image-surface-jpeg.c:372 in _cairo_image_surface_create_from_jpeg
Shadow bytes around the buggy address:
0x0fe9bfb830a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0fe9bfb830b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0fe9bfb830c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0fe9bfb830d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0fe9bfb830e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=>0x0fe9bfb830f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00[04]
0x0fe9bfb83100: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0fe9bfb83110: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0fe9bfb83120: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0fe9bfb83130: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0fe9bfb83140: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
Shadow byte legend (one shadow byte represents 8 application bytes):
Addressable: 00
Partially addressable: 01 02 03 04 05 06 07
Heap left redzone: fa
Freed heap region: fd
Stack left redzone: f1
Stack mid redzone: f2
Stack right redzone: f3
Stack after return: f5
Stack use after scope: f8
Global redzone: f9
Global init order: f6
Poisoned by user: f7
Container overflow: fc
Array cookie: ac
Intra object redzone: bb
ASan internal: fe
Left alloca redzone: ca
Right alloca redzone: cb
Shadow gap: cc
==20729==ABORTING