CVE-2023-28393
A stack-based buffer overflow vulnerability exists in the tif_processing_dng_channel_count functionality of Accusoft ImageGear 20.1. A specially crafted malformed file can lead to memory corruption. An attacker can provide a malicious file to trigger this vulnerability.
The versions below were either tested or verified to be vulnerable by Talos or confirmed to be vulnerable by the vendor.
Accusoft ImageGear 20.1
ImageGear - https://www.accusoft.com/products/imagegear-collection/
5.6 - CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:L/A:L
CWE-121 - Stack-based Buffer Overflow
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 TIFF file can lead to a stack-based buffer overflow in tif_processing_dng_channel_count
, due to a missing bounds check.
Trying to load a malformed TIFF, we end up in the following situation:
(c74.ec0): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=00000010 ebx=0ec9efe0 ecx=000003c8 edx=0ec9e000 esi=0ec9efe0 edi=001a0000
eip=6f579a03 esp=0019faf4 ebp=0019fb34 iopl=0 nv up ei pl nz na pe nc
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00010206
igCore20d!IG_mpi_page_set+0x2d8e3:
6f579a03 f3ab rep stos dword ptr es:[edi]
As we can see below the stack is overwritten with some constant value 0x10
:
0:000> kb
# ChildEBP RetAddr Args to Child
WARNING: Stack unwind information not available. Following frames may be wrong.
00 0019fb34 00000000 00000010 00000010 00000010 igCore20d!IG_mpi_page_set+0x2d8e3
The crash is happening in the function tif_processing_dng_channel_count
with the following pseudo code at LINE36:
LINE1 dword tif_processing_dng_channel_count
LINE2 (HIGEAR higear,int param_2,int param_3,int *param_4,int param_5)
LINE3 {
LINE4 int max_loop;
LINE5 double *pdVar1;
LINE6 int iVar2;
LINE7 uint uVar3;
LINE8 dword dVar4;
LINE9 int iVar5;
LINE10 int iVar6;
LINE11 short *psVar7;
LINE12 void **ppvVar8;
LINE13 int iVar9;
LINE14 int iVar10;
LINE15 AT_INT *p_loc_at_int;
LINE16 double dVar11;
LINE17 double dVar13;
LINE18 int local_28;
LINE19 int local_24;
LINE20 int local_20;
LINE21 void **local_1c;
LINE22 AT_INT _local_at_int [2];
LINE23 double local_10;
LINE24 uint local_8;
LINE25 undefined auVar12 [16];
LINE26
LINE27 local_8 = DAT_10319e74 ^ (uint)&stack0xfffffffc;
LINE28 max_loop = get_channel_count(higear);
LINE29 local_1c = (void **)0x0;
LINE30 _local_at_int[0] = 0;
LINE31 _local_at_int[1] = 0;
LINE32 local_10 = 0.0;
LINE33 if (0 < max_loop) {
LINE34 p_loc_at_int = _local_at_int;
LINE35 for (iVar5 = max_loop; iVar5 != 0; iVar5 = iVar5 + -1) {
LINE36 *p_loc_at_int = 0x10;
LINE37 p_loc_at_int = p_loc_at_int + 1;
LINE38 }
LINE39 }
LINE40 iIG_image_channel_depths_change(higear,_local_at_int,1);
[...]
LINE148 }
This is a for loop with a bound size controlled by the variable max_loop
LINE35.
The pointer p_loc_at_int
is pointing to a stack variable _local_at_int
, which is a table of two integers.
The max_loop
is returned by the function get_channel_count
LINE28, which is a wrapper, and returns a value directly read and controlled from the file. This can happen under specific circumstances with some malformed tags BitsPerSample
, the max_loop
corresponds to the SamplesPerPixel
value. The presence of some other tags like DNGVersion
and SubIFDs
is a prerequisite to make this happen.
As the loop is arbitrarily controlled and has no bounds checks, the command at LINE36 would write out-of-bounds on the stack, leading to memory corruption.
0:000> !analyze -v
*******************************************************************************
* *
* Exception Analysis *
* *
*******************************************************************************
*** WARNING: Unable to verify checksum for Fuzzme.exe
KEY_VALUES_STRING: 1
Key : AV.Fault
Value: Write
Key : Analysis.CPU.Sec
Value: 1
Key : Analysis.DebugAnalysisProvider.CPP
Value: Create: 8007007e on DESKTOP-I6GKV78
Key : Analysis.DebugData
Value: CreateObject
Key : Analysis.DebugModel
Value: CreateObject
Key : Analysis.Elapsed.Sec
Value: 1
Key : Analysis.Memory.CommitPeak.Mb
Value: 93
Key : Analysis.System
Value: CreateObject
Key : Timeline.OS.Boot.DeltaSec
Value: 1280404
Key : Timeline.Process.Start.DeltaSec
Value: 101
NTGLOBALFLAG: 2100000
PROCESS_BAM_CURRENT_THROTTLED: 0
PROCESS_BAM_PREVIOUS_THROTTLED: 0
APPLICATION_VERIFIER_FLAGS: 0
APPLICATION_VERIFIER_LOADED: 1
EXCEPTION_RECORD: (.exr -1)
ExceptionAddress: 6f579a03 (igCore20d!IG_mpi_page_set+0x0002d8e3)
ExceptionCode: c0000005 (Access violation)
ExceptionFlags: 00000000
NumberParameters: 2
Parameter[0]: 00000001
Parameter[1]: 001a0000
Attempt to write to address 001a0000
FAULTING_THREAD: 00000ec0
PROCESS_NAME: Fuzzme.exe
WRITE_ADDRESS: 001a0000
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: 001a0000
STACK_TEXT:
0019fb34 00000000 00000010 00000010 00000010 igCore20d!IG_mpi_page_set+0x2d8e3
STACK_COMMAND: ~0s ; .cxr ; kb
SYMBOL_NAME: igCore20d!IG_mpi_page_set+2d8e3
MODULE_NAME: igCore20d
IMAGE_NAME: igCore20d.dll
FAILURE_BUCKET_ID: INVALID_POINTER_WRITE_AVRF_c0000005_igCore20d.dll!IG_mpi_page_set
OS_VERSION: 10.0.19041.1
BUILDLAB_STR: vb_release
OSPLATFORM_TYPE: x86
OSNAME: Windows 10
FAILURE_ID_HASH: {fe8f80f8-683f-d41f-7c33-712a409d5fb5}
Followup: MachineOwner
---------
Release notes from the vendor can be found here:
https://help.accusoft.com/ImageGear/v20.3/Windows/DLL/webframe.html#release-notes.html
https://help.accusoft.com/ImageGear/v20.3/Linux/webframe.html#release-notes.html
2023-04-20 - Vendor Disclosure
2023-09-20 - Vendor Patch Release
2023-09-25 - Public Release
Discovered by Emmanuel Tacheau of Cisco Talos.