CVE-2021-21794
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.
Accusoft ImageGear 19.9
https://www.accusoft.com/products/imagegear-collection/
9.8 - CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H
CWE-119 - Improper Restriction of Operations within the Bounds of a Memory Buffer
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.
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
---------
2021-03-05 - Vendor Disclosure
2021-05-31 - Vendor Patched
2021-06-01 - Public Release
Discovered by Emmanuel Tacheau of Cisco Talos.