Security
Headlines
HeadlinesLatestCVEs

Headline

CVE-2020-13561: TALOS-2020-1176 || Cisco Talos Intelligence Group

An out-of-bounds write vulnerability exists in the TIFF parser of Accusoft ImageGear 19.8. A specially crafted malformed file can lead to code execution. An attacker can provide a malicious file to trigger this vulnerability.

CVE
#vulnerability#mac#windows#microsoft#cisco#intel#pdf#buffer_overflow

Summary

An out-of-bounds write vulnerability exists in the TIFF parser of Accusoft ImageGear 19.8. A specially crafted malformed file can lead to code execution. An attacker can provide a malicious file to trigger this vulnerability.

Tested Versions

Accusoft ImageGear 19.8

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, including many image formats, DICOM, PDF, Microsoft Office and others.

There is a vulnerability in the sigread function, due to a buffer overflow caused by a missing check of the input size. A specially crafted TIFF file can lead to an out-of-bounds write which can result in a memory corruption.

Trying to load a malformed TIFF file, we end up in the following situation:

(4c0c.82e8): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=00000001 ebx=00000003 ecx=000003fa edx=00000400 esi=00000002 edi=19f11000
eip=7b4f0203 esp=00cfed7c ebp=00cfed90 iopl=0         nv up ei pl nz na pe cy
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00010207
MSVCR110!memset+0x24:
7b4f0203 f3aa            rep stos byte ptr es:[edi]

0:000> dd edi
19f11000  ???????? ???????? ???????? ????????
19f11010  ???????? ???????? ???????? ????????
19f11020  ???????? ???????? ???????? ????????
19f11030  ???????? ???????? ???????? ????????   

An out-of-bounds write operation occurred during the memset above.

Further analysis reveals that if the file contains a malformed record, in our case it is :

00F6h: 41 41 41 41 41 41 41 41 41 41 41 41              AAAAAAAAAAAA

then the next 0x10 bytes are treated in a special way. In our PoC mentioned 0x10 bytes present as follow:

0102h: 05 00 00 00 00 00 00 00 00 00 00 00 00 00 41 41  ..............AA 

Let’s call this the index record. Based on the values in this index record, the amount of indexes are stored into an index_values buffer. Let’s take a closer look at the code where all this happens:

igCore19d - image base : 0x79D10000

.text:79E30852 loc_79E30852:                           ; CODE XREF: sub_79E304B0+3E7↓j
.text:79E30852                 movzx   eax, byte ptr [esi+ebx] ; ebx = record beg ( 5 )
.text:79E30852                                         ; esi = 1
.text:79E30856                 mov     [ebp+var_518], eax
.text:79E3085C                 cmp     eax, 1
.text:79E3085F                 jl      short loc_79E30893
.text:79E30861                 lea     edi, [ebp+index_values]
.text:79E30867                 lea     edi, [edi+ecx*2]
.text:79E3086A                 mov     ecx, eax
.text:79E3086C                 mov     eax, esi
.text:79E3086E                 movzx   edx, ax
.text:79E30871                 mov     eax, edx
.text:79E30873                 shl     edx, 10h
.text:79E30876                 or      eax, edx
.text:79E30878                 shr     ecx, 1
.text:79E3087A                 rep stosd
.text:79E3087C                 adc     ecx, ecx
.text:79E3087E                 rep stosw
.text:79E30881                 mov     ecx, [ebp+var_528]
.text:79E30887                 add     ecx, [ebp+var_518]
.text:79E3088D                 mov     [ebp+var_528], ecx
.text:79E30893
.text:79E30893 loc_79E30893:                           ; CODE XREF: sub_79E304B0+3AF↑j
.text:79E30893                 inc     esi
.text:79E30894                 cmp     esi, 10h
.text:79E30897                 jle     short loc_79E30852 ; ebx = record beg ( 5 )                       

The code above iterates through all of the elements in the index record and for each of these elements it copies the loop counter to the index_values address an amount of times that’s equal to the value of the index record element value.

For example:

If the first index record value is : 0x5 and its at position 1 (loop counter 1 (esi)), then 5 times the value 0x1 (WORD length) will be stored in successive positions of the index_values “array”. So, after the first iteration the index_values array will look as follows:

index_values = {0x0001,0x0001,0x0001,0x0001,0x0001 }

and so on.

The vulnerability exists in the code below:

.text:79E30990 loc_79E30990:                           ; CODE XREF: sub_79E304B0+56B↓j
.text:79E30990                 lea     ecx, [ebx+ebx]
.text:79E30993                 movzx   edx, di
.text:79E30996                 movzx   eax, [ebp+ecx+index_values] ; [WORD]index values
.text:79E3099E                 mov     [ebp+var_518], edx
.text:79E309A4                 cmp     eax, edx
.text:79E309A6                 jnz     short loc_79E30A00
.text:79E309A8                 jmp     short loc_79E309B0 ; ebx = counter
.text:79E309A8 ; ---------------------------------------------------------------------------
.text:79E309AA                 align 10h
.text:79E309B0
.text:79E309B0 loc_79E309B0:                           ; CODE XREF: sub_79E304B0+4F8↑j
.text:79E309B0                                         ; sub_79E304B0+54E↓j
.text:79E309B0                 inc     ebx             ; ebx = counter
.text:79E309B1                 mov     [ebp+ecx+var_50C], si
.text:79E309B9                 cmp     di, 0Ch
.text:79E309BD                 jnb     short loc_79E309F0
.text:79E309BF                 mov     ecx, edx
.text:79E309C1                 mov     eax, 800h
.text:79E309C6                 shr     eax, cl
.text:79E309C8                 mov     ecx, 0Bh
.text:79E309CD                 sub     ecx, edx
.text:79E309CF                 push    eax             ; size_t
.text:79E309D0                 movzx   eax, si
.text:79E309D3                 shl     eax, cl
.text:79E309D5                 mov     ecx, [ebp+buffer]
.text:79E309DB                 add     ecx, 282h
.text:79E309E1                 push    edi             ; char
.text:79E309E2                 add     eax, ecx
.text:79E309E4                 push    eax             ; void *
.text:79E309E5                 call    memset_wrapper
.text:79E309EA                 mov     edx, [ebp+var_518]
.text:79E309F0
.text:79E309F0 loc_79E309F0:                           ; CODE XREF: sub_79E304B0+50D↑j
.text:79E309F0                 lea     ecx, [ebx+ebx]
.text:79E309F3                 inc     esi
.text:79E309F4                 movzx   eax, [ebp+ecx+index_values]
.text:79E309FC                 cmp     eax, edx
.text:79E309FE                 jz      short loc_79E309B0 ; ebx = counter

We can try to present it as a pesudo-code:

Line 1  edi = index_values[0];
Line 2  esi = 0;
Line 3  for(ebx = 0; all_elements ;ebx+=2)
Line 4  {
Line 5      if(edi == index_values[ebx])
Line 6      {
Line 7          do
Line 8          {
Line 9              ebx++;
Line 10             
Line 11             memset(buffer+0x282+(esi<<(0xB-edi)),edi,0x800>>edi);
Line 12             esi++;
Line 13             
Line 14         }while( edi == index_values[ebx*2]);
Line 15         
Line 16         
Line 17     }
Line 18     esi +=2;
Line 19     edi++;
Line 20 }

The code will loop over index_values and will load the stored value in the edi register. As we can see, inside the loop at line 11, memset writes edi to buffer and the size of the write is based on shifting 0x800 right with the edi register. The offset of the buffer to write to is also moved ahead by the esi right shifted by 0xB - edi. This means that both the content the size of the write and the offset from the destination buffer are controlled by the attacker.

Buffer is allocated as shown below:

0:000> !heap -p -a 128817fa
    address 128817fa found in
    _DPH_HEAP_ROOT @ 3581000
    in busy allocation (  DPH_HEAP_BLOCK:         UserAddr         UserSize -         VirtAddr         VirtSize)
                                127b2f70:         12881578              a82 -         12881000             2000
    78dfa8b0 verifier!AVrfDebugPageHeapAllocate+0x00000240
    770cec5e ntdll!RtlDebugAllocateHeap+0x00000039
    770360f0 ntdll!RtlpAllocateHeap+0x000000f0
    7703579e ntdll!RtlpAllocateHeapInternal+0x000003ee
    7703539e ntdll!RtlAllocateHeap+0x0000003e
    7b4cdaff MSVCR110!malloc+0x00000049
    79d761de igCore19d!AF_memm_alloc+0x0000001e
    79e30643 igCore19d!IG_mpi_page_set+0x000b48f3
    79e80b6e igCore19d!IG_mpi_page_set+0x00104e1e
    79e83918 igCore19d!IG_mpi_page_set+0x00107bc8
    79e8c0e9 igCore19d!IG_mpi_page_set+0x00110399
    79e8604b igCore19d!IG_mpi_page_set+0x0010a2fb
    79d510d9 igCore19d!IG_image_savelist_get+0x00000b29
    79d90557 igCore19d!IG_mpi_page_set+0x00014807
    79d8feb9 igCore19d!IG_mpi_page_set+0x00014169
    79d25777 igCore19d!IG_load_file+0x00000047
    005220d0 Fuzzme!fuzzme+0x000000b0
    00522502 Fuzzme!fuzzme+0x000004e2
    00527a5a Fuzzme!fuzzme+0x00005a3a
    75d9f989 KERNEL32!BaseThreadInitThunk+0x00000019
    770574a4 ntdll!__RtlUserThreadStart+0x0000002f
    77057474 ntdll!_RtlUserThreadStart+0x0000001b

and is size is constant 0A82h:

.text:79E3059D                 push    296h            ; int
.text:79E305A2                 push    offset aCommonFormatsJ ; "..\\..\\..\\..\\Common\\Formats\\jpeg_d"...
.text:79E305A7                 push    0A82h           ; size_t
.text:79E305AC                 push    edi             ; int
.text:79E305AD                 call    AF_memm_alloc
.text:79E305B2                 mov     [ebp+esi*4+var_540], eax

Tracing subsequent loop executions we will see that memset will be called with the following values:

Loop values during iterations:

#1
memset(buffer+0x282,1,0x400)

#2
memset(buffer+0x282+0x400,1,0x400)

#3
memset(buffer+0x282+0x800,1,0x400) <=== overflow

Since the size of the memset is 0x800 shifted right by the value stored in index_values, in our example above this is 0x0001, so after 2 iterations, the buffer will be set at the end of the allocated memory, meaning the 3rd memset will result in an out-of-bounds wite.

Crash Information

(d344.7590): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=00000001 ebx=00000003 ecx=000003fa edx=00000400 esi=00000002 edi=1a69d000
eip=7b4f0203 esp=010fe92c ebp=010fe940 iopl=0         nv up ei pl nz na pe cy
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00010207
MSVCR110!memset+0x24:
7b4f0203 f3aa            rep stos byte ptr es:[edi]
0:000> !analyze -v
*******************************************************************************
*                                                                             *
*                        Exception Analysis                                   *
*                                                                             *
*******************************************************************************


KEY_VALUES_STRING: 1

    Key  : AV.Fault
    Value: Write

    Key  : Analysis.CPU.mSec
    Value: 5062

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

    Key  : Analysis.DebugData
    Value: CreateObject

    Key  : Analysis.DebugModel
    Value: CreateObject

    Key  : Analysis.Elapsed.mSec
    Value: 251661

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

    Key  : Analysis.System
    Value: CreateObject

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

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

    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.0.2


ADDITIONAL_XML: 1

OS_BUILD_LAYERS: 1

NTGLOBALFLAG:  2000000

APPLICATION_VERIFIER_FLAGS:  0

APPLICATION_VERIFIER_LOADED: 1

EXCEPTION_RECORD:  (.exr -1)
ExceptionAddress: 7b4f0203 (MSVCR110!memset+0x00000024)
   ExceptionCode: c0000005 (Access violation)
  ExceptionFlags: 00000000
NumberParameters: 2
   Parameter[0]: 00000001
   Parameter[1]: 1a69d000
Attempt to write to address 1a69d000

FAULTING_THREAD:  00007590

PROCESS_NAME:  Fuzzme.exe

WRITE_ADDRESS:  1a69d000 

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:  1a69d000

STACK_TEXT:  
010fe92c 79d1fc03     1a69cffa 00000001 00000400 MSVCR110!memset+0x24
WARNING: Stack unwind information not available. Following frames may be wrong.
010fe940 79e309ea     1a69cffa 00000001 00000400 igCore19d+0xfc03
010feeb0 79e80b6e     1a6aef60 010ff554 00000010 igCore19d!IG_mpi_page_set+0xb4c9a
010feed8 79e83918     010ff554 00000000 1a60ef90 igCore19d!IG_mpi_page_set+0x104e1e
010fef94 79e8c0e9     010ff554 1a576d68 010fefe8 igCore19d!IG_mpi_page_set+0x107bc8
010fefb8 79e8604b     010ff554 1000002f 1a576d68 igCore19d!IG_mpi_page_set+0x110399
010ff4cc 79d510d9     010ff554 1a576d68 00000001 igCore19d!IG_mpi_page_set+0x10a2fb
010ff504 79d90557     00000000 1a576d68 010ff554 igCore19d!IG_image_savelist_get+0xb29
010ff780 79d8feb9     00000000 0a1c2f80 00000001 igCore19d!IG_mpi_page_set+0x14807
010ff7a0 79d25777     00000000 0a1c2f80 00000001 igCore19d!IG_mpi_page_set+0x14169
010ff7c0 005220d0     0a1c2f80 010ff7d4 0a102f48 igCore19d!IG_load_file+0x47
010ff7e0 00522502     0a1c2f80 010ff848 00000021 Fuzzme!fuzzme+0xb0
010ff870 00527a5a     00000005 0a102f48 0a109f18 Fuzzme!fuzzme+0x4e2
010ff8b8 75d9f989     00ea6000 75d9f970 010ff924 Fuzzme!fuzzme+0x5a3a
010ff8c8 770574a4     00ea6000 ef6ddc25 00000000 KERNEL32!BaseThreadInitThunk+0x19
010ff924 77057474     ffffffff 77077354 00000000 ntdll!__RtlUserThreadStart+0x2f
010ff934 00000000     00527ae2 00ea6000 00000000 ntdll!_RtlUserThreadStart+0x1b


STACK_COMMAND:  ~0s ; .cxr ; kb

SYMBOL_NAME:  MSVCR110!memset+24

MODULE_NAME: MSVCR110

IMAGE_NAME:  MSVCR110.dll

FAILURE_BUCKET_ID:  INVALID_POINTER_WRITE_STRING_DEREFERENCE_AVRF_c0000005_MSVCR110.dll!memset

OS_VERSION:  10.0.19041.1

BUILDLAB_STR:  vb_release

OSPLATFORM_TYPE:  x86

OSNAME:  Windows 10

IMAGE_VERSION:  11.0.50727.1

FAILURE_ID_HASH:  {56b0676a-0fb6-0730-2b71-15517df752d2}

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

0:000> lmv a 79e80b6e
Browse full module list
start    end        module name
79d10000 7a059000   igCore19d   (export symbols)       d:\projects\ImageGear\v19\Build\Bin\x86\igCore19d.dll
    Loaded symbol image file: d:\projects\ImageGear\v19\Build\Bin\x86\igCore19d.dll
    Image path: d:\projects\ImageGear\v19\Build\Bin\x86\igCore19d.dll
    Image name: igCore19d.dll
    Browse all global symbols  functions  data
    Timestamp:        Thu Aug 20 20:45:15 2020 (5F3EC4BB)
    CheckSum:         003494E0
    ImageSize:        00349000
    File version:     19.8.0.0
    Product version:  19.8.0.0
    File flags:       0 (Mask 3F)
    File OS:          4 Unknown Win32
    File type:        2.0 Dll
    File date:        00000000.00000000
    Translations:     0409.04b0
    Information from resource tables:
        CompanyName:      Accusoft Corporation
        ProductName:      Accusoft ImageGear
        InternalName:     igcore19d.dll
        OriginalFilename: igcore19d.dll
        ProductVersion:   19.8.0.0
        FileVersion:      19.8.0.0
        FileDescription:  Accusoft ImageGear CORE DLL 
        LegalCopyright:   Copyright 1996-2020 Accusoft Corporation. All rights reserved.
        LegalTrademarks:  ImageGear® and Accusoft® are registered trademarks of Accusoft Corporation

Timeline

2020-10-26 - Vendor Disclosure
2021-02-05 - Vendor patched
2021-02-09 - Public Release

Discovered by Emmanuel Tacheau and a member of Cisco Talos.

CVE: Latest News

CVE-2023-50976: Transactions API Authorization by oleiman · Pull Request #14969 · redpanda-data/redpanda
CVE-2023-6905
CVE-2023-6903
CVE-2023-6904
CVE-2023-3907