Talos Vulnerability Report

TALOS-2021-1261

Accusoft ImageGear TIF bits_per_sample processing out-of-bounds write vulnerability

June 1, 2021
CVE Number

CVE-2021-21794

Summary

An out-of-bounds write vulnerability exists in the TIF bits_per_sample processing functionality of Accusoft ImageGear 19.9. A specially crafted malformed file can lead to memory corruption. An attacker can provide a malicious file to trigger this vulnerability.

Tested Versions

Accusoft ImageGear 19.9

Product URLs

https://www.accusoft.com/products/imagegear-collection/

CVSSv3 Score

9.8 - CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H

CWE

CWE-119 - Improper Restriction of Operations within the Bounds of a Memory Buffer

Details

The ImageGear library is a document-imaging developer toolkit that offers image conversion, creation, editing, annotation and more. It supports more than 100 formats such as DICOM, PDF, Microsoft Office and others.

A specially crafted TIF file can lead to an out-of-bounds write in memcpy function, due to a buffer overflow caused by a missing size check for a buffer memory.
Trying to load a malformed TIF file, we end up in the following situation:

This exception may be expected and handled.
eax=0e1dafdd ebx=0d9ecfe0 ecx=00000005 edx=00000005 esi=0e1dafd8 edi=05a35000
eip=5dbedf22 esp=0019f480 ebp=0019f498 iopl=0         nv up ei ng nz ac pe cy
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00010297
MSVCR110!memcpy+0x2a:
5dbedf22 f3a4            rep movs byte ptr es:[edi],byte ptr [esi]

The crash is happening in this function DIB_RASTER_CallbackEx_2 through the wrapper_memcpy call in LINE60.
The destination_buffer is an address value resulting from the call to the function wrapper_image_DIB_raster_pntr_get in LINE56.

LINE1   int DIB_RASTER_CallbackEx_2
LINE2                 (DIB_RASTER_CallbackEx *dib_raster,byte *src_buffer,AT_PIXPOS pixpos,uint size)
LINE3   {
        [...]
LINE52    SamplePerPixel = GetSamplePerPixelFromHigear(higear);
LINE53    Width = GetWidthFromHigear(higear);
LINE54    FromColorTable = GetTableColorTableRelatedFromHigear(higear);
LINE55    max_size = FromColorTable * Width * (SamplePerPixel >> 3);
LINE56    destination_buffer = wrapper_image_DIB_raster_pntr_get(higear,pixpos);
LINE57    if (max_size < size) {
LINE58      size = max_size;
LINE59    }
LINE60    wrapper_memcpy(destination_buffer,src_buffer,size);
LINE61    DIB_flushes(higear,pixpos);
LINE62    return_status = AF_error_check();
LINE63    return return_status;
LINE64  }

The following pseudo-code of the wrapped function image_DIB_raster_pntr_get is showing in LINE108 the address returned is the result from the virtual call to the function IGDIBStd::GetCopyBufferAllocatedWithPixpos

LINE65   void * image_DIB_raster_pntr_get(HIGEAR higear,AT_PIXPOS AT_PIXPOS,uint param_3)
LINE66   {
    [...]
LINE108    lplpRaster = (void *)(*(code *)IGDIBStd_Obj->vptr->IGDIBStd::GetCopyBufferAllocatedWithPixpos)();
LINE109    *in_FS_OFFSET = local_10;
LINE110    return lplpRaster;
LINE111  }

Below the pseudo code for the function GetCopyBufferAllocatedWithPixpos:

LINE112  byte * __thiscall IGDIBStd::GetCopyBufferAllocatedWithPixpos(IGDIBStd *this,AT_PIXPOS pixpos)
LINE113  {
LINE114    uint raster_size;
LINE115    
LINE116    this->field_0x48 = 1;
LINE117    raster_size = (*this->vptr->IGDIBStd::compute_raster_size)(this);
LINE118    return this->copy_buffer_allocated + raster_size * pixpos;
LINE119  }

The vulnerability is happening in LINE118 on this function GetCopyBufferAllocatedWithPixpos. The address returned can be outside of boundaries of the buffer pointed by the variable copy_buffer_allocated as there is no check against the address computed. If raster_size * pixpos is greater than the buffer allocated then it will enable an out-of-bounds write.

We can control the raster_size, the size of copy_buffer_allocated buffer and the pixpos, from the file.
To trigger this vulnerability, two TIF tags must be present in the file: a bits_per_sample tag and a T4options tag. The value for the bits_per_sample tag must be null.

Crash Information

0:000> !analyze -v
*******************************************************************************
*                                                                             *
*                        Exception Analysis                                   *
*                                                                             *
*******************************************************************************


KEY_VALUES_STRING: 1

    Key  : AV.Fault
    Value: Write

    Key  : Analysis.CPU.mSec
    Value: 2796

    Key  : Analysis.DebugAnalysisProvider.CPP
    Value: Create: 8007007e on DESKTOP-4DAOCFH

    Key  : Analysis.DebugData
    Value: CreateObject

    Key  : Analysis.DebugModel
    Value: CreateObject

    Key  : Analysis.Elapsed.mSec
    Value: 30516

    Key  : Analysis.Memory.CommitPeak.Mb
    Value: 192

    Key  : Analysis.System
    Value: CreateObject

    Key  : Timeline.OS.Boot.DeltaSec
    Value: 885046

    Key  : Timeline.Process.Start.DeltaSec
    Value: 72

    Key  : WER.OS.Branch
    Value: vb_release

    Key  : WER.OS.Timestamp
    Value: 2019-12-06T14:06:00Z

    Key  : WER.OS.Version
    Value: 10.0.19041.1

    Key  : WER.Process.Version
    Value: 1.0.1.1


ADDITIONAL_XML: 1

OS_BUILD_LAYERS: 1

NTGLOBALFLAG:  2100000

APPLICATION_VERIFIER_FLAGS:  0

APPLICATION_VERIFIER_LOADED: 1

EXCEPTION_RECORD:  (.exr -1)
ExceptionAddress: 5dbedf22 (MSVCR110!memcpy+0x0000002a)
   ExceptionCode: c0000005 (Access violation)
  ExceptionFlags: 00000000
NumberParameters: 2
   Parameter[0]: 00000001
   Parameter[1]: 05a35000
Attempt to write to address 05a35000

FAULTING_THREAD:  0000589c

PROCESS_NAME:  Fuzzme.exe

WRITE_ADDRESS:  05a35000 

ERROR_CODE: (NTSTATUS) 0xc0000005 - The instruction at 0x%p referenced memory at 0x%p. The memory could not be %s.

EXCEPTION_CODE_STR:  c0000005

EXCEPTION_PARAMETER1:  00000001

EXCEPTION_PARAMETER2:  05a35000

STACK_TEXT:  
0019f484 5dccf9c6     05a35000 0e1dafd8 00000005 MSVCR110!memcpy+0x2a
WARNING: Stack unwind information not available. Following frames may be wrong.
0019f498 5dd3d30a     05a35000 0e1dafd8 00000005 igCore19d+0xf9c6
0019f4b8 5dd19dae     0019fca4 0e1dafd8 00000012 igCore19d!IG_mpi_page_set+0x115ba
0019f4d8 5ddcbbbf     0019fb30 0e1dafd8 00000012 igCore19d!IG_cpm_profiles_reset+0xef9e
0019f500 5de38334     0019fb30 10000021 09f15000 igCore19d!IG_mpi_page_set+0x9fe6f
0019f570 5de3c363     0019fb30 10000021 00000003 igCore19d!IG_mpi_page_set+0x10c5e4
0019f594 5de362cb     0019fb30 10000021 0c242d68 igCore19d!IG_mpi_page_set+0x110613
0019faa8 5dd010d9     0019fb30 0c242d68 00000001 igCore19d!IG_mpi_page_set+0x10a57b
0019fae0 5dd40557     00000000 0c242d68 0019fb30 igCore19d!IG_image_savelist_get+0xb29
0019fd5c 5dd3feb9     00000000 05424f68 00000001 igCore19d!IG_mpi_page_set+0x14807
0019fd7c 5dcd5777     00000000 05424f68 00000001 igCore19d!IG_mpi_page_set+0x14169
0019fd9c 00498a3a     05424f68 0019fe0c 004801a4 igCore19d!IG_load_file+0x47
0019fe14 00498e36     05424f68 0019fe8c 004801a4 Fuzzme!fuzzme+0x4a
0019fee4 004daa53     00000005 05364f00 0536df20 Fuzzme!main+0x376
0019ff04 004da8a7     b8f1a89f 004801a4 004801a4 Fuzzme!invoke_main+0x33
0019ff60 004da73d     0019ff70 004daad8 0019ff80 Fuzzme!__scrt_common_main_seh+0x157
0019ff68 004daad8     0019ff80 763afa29 00227000 Fuzzme!__scrt_common_main+0xd
0019ff70 763afa29     00227000 763afa10 0019ffdc Fuzzme!mainCRTStartup+0x8
0019ff80 777076b4     00227000 9a8f15ce 00000000 KERNEL32!BaseThreadInitThunk+0x19
0019ffdc 77707684     ffffffff 7772742e 00000000 ntdll!__RtlUserThreadStart+0x2f
0019ffec 00000000     004801a4 00227000 00000000 ntdll!_RtlUserThreadStart+0x1b


STACK_COMMAND:  ~0s ; .cxr ; kb

SYMBOL_NAME:  MSVCR110!memcpy+2a

MODULE_NAME: MSVCR110

IMAGE_NAME:  MSVCR110.dll

FAILURE_BUCKET_ID:  INVALID_POINTER_WRITE_STRING_DEREFERENCE_AVRF_c0000005_MSVCR110.dll!memcpy

OS_VERSION:  10.0.19041.1

BUILDLAB_STR:  vb_release

OSPLATFORM_TYPE:  x86

OSNAME:  Windows 10

IMAGE_VERSION:  11.0.51106.1

FAILURE_ID_HASH:  {77975e19-9d4d-daf1-6c0e-6a3a4c334a80}

Followup:     MachineOwner
---------

Timeline

2021-03-05 - Vendor Disclosure

2021-05-31 - Vendor Patched
2021-06-01 - Public Release

Credit

Discovered by Emmanuel Tacheau of Cisco Talos.