Vulnerabilities > CVE-2017-2813 - Integer Overflow or Wraparound vulnerability in Irfanview 4.44
Attack vector
LOCAL Attack complexity
LOW Privileges required
NONE Confidentiality impact
HIGH Integrity impact
HIGH Availability impact
HIGH Summary
An exploitable integer overflow vulnerability exists in the JPEG 2000 parser functionality of IrfanView 4.44. A specially crafted jpeg2000 image can cause an integer overflow leading to wrong memory allocation resulting in arbitrary code execution. Vulnerability can be triggered by viewing the image in via the application or by using thumbnailing feature of IrfanView.
Vulnerable Configurations
Part | Description | Count |
---|---|---|
Application | 1 |
Common Weakness Enumeration (CWE)
Common Attack Pattern Enumeration and Classification (CAPEC)
- Forced Integer Overflow This attack forces an integer variable to go out of range. The integer variable is often used as an offset such as size of memory allocation or similarly. The attacker would typically control the value of such variable and try to get it out of range. For instance the integer in question is incremented past the maximum possible value, it may wrap to become a very small, or negative number, therefore providing a very incorrect value which can lead to unexpected behavior. At worst the attacker can execute arbitrary code.
Seebug
bulletinFamily | exploit |
description | ### Summary An exploitable integer overflow vulnerability exists in the JPEG 2000 parser functionality of IrfanView 4.44. A specially crafted jpeg2000 image can cause an integer overflow leading to wrong memory allocation resulting in arbitrary code execution. Vulnerability can be triggered by viewing the image in via the application or by using thumbnailing feature of IrfanView. ### Tested Versions IrfanView 4.44 ### Product URLs http://www.irfanview.com/ ### CVSSv3 Score 8.8 - CVSS:3.0/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H ### CWE CWE-190: Integer Overflow or Wraparound ### Details IrfanView is a popular image viewer application for Windows due to its support for large number of file formats through its plugins and numerous image manipulation options. While parsing a JPEG 2000 file, IrfanView will use the reference tile width value in a buffer size calculation. Due to insufficient checks for integer wraparound, these calculations can result in a small buffer being allocated for a seemingly large tile which later results in a controlled out-of-bounds write vulnerability which can be further abused to achieve arbitrary code execution in the context of the application. Erroneous allocation happens in function sub_10027E40 (image base of unpacked JPEG2000.dll is at 0x10001000) and the condition for the integer overflow can be observed at the following breakpoint: ``` eax=00000000 ebx=000000c8 ecx=0019ed74 edx=0ccccccf esi=0a521da0 edi=00000001 eip=516f7e67 esp=0019ed80 ebp=0019ed8c iopl=0 nv up ei pl zr na pe nc cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000246 JPEG2000!ShowPlugInSaveOptions+0x23937: 516f7e67 e8d413ffff call JPEG2000!ShowPlugInSaveOptions+0x14d10 (516e9240) 0:000> dd esp 0019ed80 0a513fe8 00000050 0a521da0 0019eda4 0019ed90 516e84d3 00000050 3da65ff8 00000000 0019eda0 00000008 0019edd0 516e8366 0a521da0 0019edb0 00000000 00000001 00000000 00000001 0019edc0 00000000 00000000 00000000 00000000 0019edd0 0019eec0 516d35a9 0a521da0 0056602c 0019ede0 0019f06c 00000000 00000001 00000009 0019edf0 516d0000 3da65ff8 00000000 0054fdb0 0:000> ``` Second argument to the above call is 0x50 which ends up being a size argument to `malloc` call, and is actually derived from `xTsiz` value in the `siz` marker of the sample file which in this case is 0x0CCCCCCF, the smallest value that will trigger the integer overflow. Notice that the `edx` register holds the same value, before buffer size calculations are done. Buffer size calculations basically boil down to multiplying the value by 20 plus a small value. Therefore, instead of allocating a large enough buffer, a small memory region will be reserved after the call: ``` 0:000> !heap -p -a eax address 0a6e6fb0 found in _DPH_HEAP_ROOT @ 3f01000 in busy allocation ( DPH_HEAP_BLOCK: UserAddr UserSize - VirtAddr VirtSize) 3da70a90: a6e6fa8 58 - a6e6000 2000 56a89abc verifier!AVrfDebugPageHeapAllocate+0x0000023c 779ed816 ntdll!RtlDebugAllocateHeap+0x0000003c 7794fb40 ntdll!RtlpAllocateHeap+0x000000f0 7794decb ntdll!RtlpAllocateHeapInternal+0x0000027b 7794dc2e ntdll!RtlAllocateHeap+0x0000002e 516d45e6 JPEG2000!ShowPlugInSaveOptions+0x000000b6 516e921b JPEG2000!ShowPlugInSaveOptions+0x00014ceb 516e9269 JPEG2000!ShowPlugInSaveOptions+0x00014d39 516f7e6c JPEG2000!ShowPlugInSaveOptions+0x0002393c 516e84d3 JPEG2000!ShowPlugInSaveOptions+0x00013fa3 516e8366 JPEG2000!ShowPlugInSaveOptions+0x00013e36 516d35a9 JPEG2000!ReadJPG2000+0x00000c09 *** ERROR: Module load completed but symbols could not be loaded for image00400000 0043c3bc image00400000+0x0003c3bc ``` Later, when actual values are to be written in this buffer, a controlled out-of-bounds write will happen potentially overwriting sensitive memory. Note that due to different memory layouts, an out-of-bounds write can happen on actually accessible memory and in general won’t result in a crash. By modifying the `xTsiz` value slightly (to 0x0dcccccf), to force a crash, we can observe the following: Breakpoint 0 hit ``` eax=00000000 ebx=000000c8 ecx=0019ed74 edx=0dcccccf esi=0a427da0 edi=00000001 eip=516f7e67 esp=0019ed80 ebp=0019ed8c iopl=0 nv up ei pl zr na pe nc cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000246 JPEG2000!ShowPlugInSaveOptions+0x23937: 516f7e67 e8d413ffff call JPEG2000!ShowPlugInSaveOptions+0x14d10 (516e9240) 0:000> dd esp 0019ed80 0a419fe8 14000050 0a427da0 0019eda4 0019ed90 516e84d3 14000050 41965ff8 00000000 0019eda0 00000008 0019edd0 516e8366 0a427da0 0019edb0 00000000 00000001 00000000 00000001 0019edc0 00000000 00000000 00000000 00000000 0019edd0 0019eec0 516d35a9 0a427da0 0056602c 0019ede0 0019f06c 00000000 00000001 00000009 0019edf0 516d0000 41965ff8 00000000 0054fdb0 0:000> ``` In the above debugging output, we can again see `edx` having the original `xTsiz` value from the file, and an overflowed value pushed as a second argument on the stack (0x14000050, overflown by multiplying edx by 20). After this call we can see our buffer being allocated: ``` Breakpoint 1 hit eax=7fff0fb0 ebx=000000c8 ecx=7fff0fa8 edx=01000002 esi=0a487da0 edi=00000001 eip=516f7e6c esp=0019ed80 ebp=0019ed8c iopl=0 nv up ei pl nz ac po nc cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000212 JPEG2000!ShowPlugInSaveOptions+0x2393c: 516f7e6c 83c408 add esp,8 0:000> !heap -p -a eax address 7fff0fb0 found in _DPH_HEAP_ROOT @ 4fd1000 in busy allocation ( DPH_HEAP_BLOCK: UserAddr UserSize - VirtAddr VirtSize) 419d098c: 7fff0fa8 14000058 - 7fff0000 14002000 56a89abc verifier!AVrfDebugPageHeapAllocate+0x0000023c 779ed816 ntdll!RtlDebugAllocateHeap+0x0000003c 7794fb40 ntdll!RtlpAllocateHeap+0x000000f0 7794decb ntdll!RtlpAllocateHeapInternal+0x0000027b 7794dc2e ntdll!RtlAllocateHeap+0x0000002e 516d45e6 JPEG2000!ShowPlugInSaveOptions+0x000000b6 516e921b JPEG2000!ShowPlugInSaveOptions+0x00014ceb 516e9269 JPEG2000!ShowPlugInSaveOptions+0x00014d39 516f7e6c JPEG2000!ShowPlugInSaveOptions+0x0002393c 516e84d3 JPEG2000!ShowPlugInSaveOptions+0x00013fa3 516e8366 JPEG2000!ShowPlugInSaveOptions+0x00013e36 516d35a9 JPEG2000!ReadJPG2000+0x00000c09 *** ERROR: Module load completed but symbols could not be loaded for image00400000 0043c3bc image00400000+0x0003c3bc ``` So, a buffer of size 0x14000058 has been successfully allocated. Continuing the execution results in the following crash: ``` (2778.3b14): Access violation - code c0000005 (first chance) First chance exceptions are reported before any exception handling. This exception may be expected and handled. eax=b7324300 ebx=00000000 ecx=b73242f0 edx=00000000 esi=0a487da0 edi=00000000 eip=516f82ea esp=0019ed64 ebp=0019ed78 iopl=0 nv up ei ng nz ac po cy cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00010293 JPEG2000!ShowPlugInSaveOptions+0x23dba: 516f82ea 89040b mov dword ptr [ebx+ecx],eax ds:002b:b73242f0=???????? 0:000> dd ecx b73242f0 ???????? ???????? ???????? ???????? b7324300 ???????? ???????? ???????? ???????? b7324310 ???????? ???????? ???????? ???????? b7324320 ???????? ???????? ???????? ???????? b7324330 ???????? ???????? ???????? ???????? b7324340 ???????? ???????? ???????? ???????? b7324350 ???????? ???????? ???????? ???????? b7324360 ???????? ???????? ???????? ???????? 0:000> ``` The crash occurs in a function at offset 0x10028200, specifically while writing values in a loop controlled based on number of components. Upper bound for `ebx` in the above out-of-bounds write loop is the `numberOfComponents` value specified in the file which can be easily controlled to achieve multiple out of bounds writes. Also, backing up a bit in the crashing function reveals that `ecx` pointer is derived from the `xTsiz` value which causes the initial integer overflow: ``` .text:10028253 mov eax, [esi+8] [1] .text:10028256 mov ecx, [esi+2Ch] .text:10028259 mov edx, [eax+14h] [2] .text:1002825C imul edx, [ecx+8] [3] .text:10028260 mov eax, [ebp+arg_0] .text:10028263 lea eax, [eax+edx*4] [4] .text:10028266 mov [ebp+arg_0], eax ; [5] .text:10028269 jmp short loc_100 ``` An original `xTsiz` value twice dereferenced at [1] and [2] ends up in `edx`, multiplied by 1 at [3] and used as offset in pointer calculation at [4], with `eax` as a base being a start of our previously allocated buffer. This pointer is stored as arg_0 at [5] and because the offset is multiplied by 4, and the original buffer is smaller than that, this ends up causing the out-of-bounds write. This can be observed in the following debugging session: ``` 516f8253 8b4608 mov eax,dword ptr [esi+8] ds:002b:0a477da8=0a479430 0:000> dd poi(esi+8)+0x14 0a479444 0dcccccf 00000001 00000000 00000000 ``` Above, we see that the value at (esi+8)+0x14 is equal to original xTsiz value. ``` 0:000> t eax=0a479430 ebx=00000003 ecx=7fff0fb0 edx=00000000 esi=0a477da0 edi=0000001f eip=516f8256 esp=0019ed64 ebp=0019ed78 iopl=0 nv up ei pl nz na pe nc cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000206 JPEG2000!ShowPlugInSaveOptions+0x23d26: 516f8256 8b4e2c mov ecx,dword ptr [esi+2Ch] ds:002b:0a477dcc=0a477fd8 0:000> eax=0a479430 ebx=00000003 ecx=0a477fd8 edx=00000000 esi=0a477da0 edi=0000001f eip=516f8259 esp=0019ed64 ebp=0019ed78 iopl=0 nv up ei pl nz na pe nc cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000206 JPEG2000!ShowPlugInSaveOptions+0x23d29: 516f8259 8b5014 mov edx,dword ptr [eax+14h] ds:002b:0a479444=0dcccccf 0:000> eax=0a479430 ebx=00000003 ecx=0a477fd8 edx=0dcccccf esi=0a477da0 edi=0000001f eip=516f825c esp=0019ed64 ebp=0019ed78 iopl=0 nv up ei pl nz na pe nc cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000206 JPEG2000!ShowPlugInSaveOptions+0x23d2c: 516f825c 0faf5108 imul edx,dword ptr [ecx+8] ds:002b:0a477fe0=00000001 0:000> dd ecx+8 0a477fe0 00000001 00000001 00000001 00000000 0:000> t eax=0a479430 ebx=00000003 ecx=0a477fd8 edx=0dcccccf esi=0a477da0 edi=0000001f eip=516f8260 esp=0019ed64 ebp=0019ed78 iopl=0 nv up ei pl nz na pe nc cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000206 JPEG2000!ShowPlugInSaveOptions+0x23d30: 516f8260 8b4508 mov eax,dword ptr [ebp+8] ss:002b:0019ed80=7fff0fb0 0:000> t eax=7fff0fb0 ebx=00000003 ecx=0a477fd8 edx=0dcccccf esi=0a477da0 edi=0000001f eip=516f8263 esp=0019ed64 ebp=0019ed78 iopl=0 nv up ei pl nz na pe nc cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000206 JPEG2000!ShowPlugInSaveOptions+0x23d33: 516f8263 8d0490 lea eax,[eax+edx*4] ``` Stepping through this block shows how the value in `edx` is calculated as well as value in `eax` being retrieved. Last instruction above uses eax as base pointer and `edx*4` as an offset into it. ``` 0:000> dd eax 7fff0fb0 c0c0c0c0 c0c0c0c0 c0c0c0c0 c0c0c0c0 7fff0fc0 c0c0c0c0 c0c0c0c0 c0c0c0c0 c0c0c0c0 7fff0fd0 c0c0c0c0 c0c0c0c0 c0c0c0c0 c0c0c0c0 7fff0fe0 c0c0c0c0 c0c0c0c0 c0c0c0c0 c0c0c0c0 7fff0ff0 c0c0c0c0 c0c0c0c0 c0c0c0c0 c0c0c0c0 7fff1000 c0c0c0c0 c0c0c0c0 c0c0c0c0 c0c0c0c0 7fff1010 c0c0c0c0 c0c0c0c0 c0c0c0c0 c0c0c0c0 7fff1020 c0c0c0c0 c0c0c0c0 c0c0c0c0 c0c0c0c0 0:000> !heap -p -a eax address 7fff0fb0 found in _DPH_HEAP_ROOT @ 2e31000 in busy allocation ( DPH_HEAP_BLOCK: UserAddr UserSize - VirtAddr VirtSize) 419c098c: 7fff0fa8 14000058 - 7fff0000 14002000 56a89abc verifier!AVrfDebugPageHeapAllocate+0x0000023c 779ed816 ntdll!RtlDebugAllocateHeap+0x0000003c 7794fb40 ntdll!RtlpAllocateHeap+0x000000f0 7794decb ntdll!RtlpAllocateHeapInternal+0x0000027b 7794dc2e ntdll!RtlAllocateHeap+0x0000002e 516d45e6 JPEG2000!ShowPlugInSaveOptions+0x000000b6 516e921b JPEG2000!ShowPlugInSaveOptions+0x00014ceb 516e9269 JPEG2000!ShowPlugInSaveOptions+0x00014d39 516f7e6c JPEG2000!ShowPlugInSaveOptions+0x0002393c 516e84d3 JPEG2000!ShowPlugInSaveOptions+0x00013fa3 516e8366 JPEG2000!ShowPlugInSaveOptions+0x00013e36 516d35a9 JPEG2000!ReadJPG2000+0x00000c09 *** ERROR: Module load completed but symbols could not be loaded for image00400000 0043c3bc image00400000+0x0003c3bc ``` Before the `lea` instruction, we can see that `eax` points to our allocated buffer which is smaller than `edx*4`. This causes `eax` to point out-of-bounds: ``` 0:000> u JPEG2000!ShowPlugInSaveOptions+0x23d33: 516f8263 8d0490 lea eax,[eax+edx*4] 516f8266 894508 mov dword ptr [ebp+8],eax 516f8269 eb1d jmp JPEG2000!ShowPlugInSaveOptions+0x23d58 (516f8288) 516f826b 8b4e08 mov ecx,dword ptr [esi+8] 516f826e 8d4707 lea eax,[edi+7] 516f8271 99 cdq 516f8272 83e207 and edx,7 516f8275 03c2 add eax,edx 0:000> t eax=b73242ec ebx=00000003 ecx=0a477fd8 edx=0dcccccf esi=0a477da0 edi=0000001f eip=516f8266 esp=0019ed64 ebp=0019ed78 iopl=0 nv up ei pl nz na pe nc cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000206 JPEG2000!ShowPlugInSaveOptions+0x23d36: 516f8266 894508 mov dword ptr [ebp+8],eax ss:002b:0019ed80=7fff0fb0 0:000> dd eax b73242ec ???????? ???????? ???????? ???????? 0:000> ``` Continuing the process again leads to the crash when a value is written into memory pointed to by `eax` plus an offset based on other `SIZ` fields. The value that is being written out-of-bounds is based on `eax`. By carefully controlling the `xTsiz` value, and manipulating final arithmetics via other values in the `SIZ` marker, an attacker can overwrite a chosen memory location with its controlled value which can lead to arbitrary code execution. ### Crash Information ``` 0:000> r eax=b7324300 ebx=00000000 ecx=b73242f0 edx=00000000 esi=0a477da0 edi=00000000 eip=516f82ea esp=0019ed64 ebp=0019ed78 iopl=0 nv up ei ng nz ac po cy cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00010293 JPEG2000!ShowPlugInSaveOptions+0x23dba: 516f82ea 89040b mov dword ptr [ebx+ecx],eax ds:002b:b73242f0=???????? 0:000> u JPEG2000!ShowPlugInSaveOptions+0x23dba: 516f82ea 89040b mov dword ptr [ebx+ecx],eax 516f82ed 8b4608 mov eax,dword ptr [esi+8] 516f82f0 8b4814 mov ecx,dword ptr [eax+14h] 516f82f3 8b4508 mov eax,dword ptr [ebp+8] 516f82f6 8d0488 lea eax,[eax+ecx*4] 516f82f9 894508 mov dword ptr [ebp+8],eax 516f82fc 8d4508 lea eax,[ebp+8] 516f82ff 50 push eax 0:000> dd ecx b73242f0 ???????? ???????? ???????? ???????? b7324300 ???????? ???????? ???????? ???????? b7324310 ???????? ???????? ???????? ???????? b7324320 ???????? ???????? ???????? ???????? b7324330 ???????? ???????? ???????? ???????? b7324340 ???????? ???????? ???????? ???????? b7324350 ???????? ???????? ???????? ???????? b7324360 ???????? ???????? ???????? ???????? 0:000> k ChildEBP RetAddr WARNING: Stack unwind information not available. Following frames may be wrong. 0019ed78 516f7e80 JPEG2000!ShowPlugInSaveOptions+0x23dba 0019ed8c 516e84d3 JPEG2000!ShowPlugInSaveOptions+0x23950 0019eda4 516e8366 JPEG2000!ShowPlugInSaveOptions+0x13fa3 0019edd0 516d35a9 JPEG2000!ShowPlugInSaveOptions+0x13e36 0019eec0 0043c3bc JPEG2000!ReadJPG2000+0xc09 00000000 00000000 image00400000+0x3c3bc 0:000> ``` ### Timeline * 2017-04-18 - Vendor Disclosure * 2017-04-26 - Public Release ### CREDIT * Discovered by Aleksandar Nikolic of Cisco Talos. |
id | SSV:96527 |
last seen | 2017-11-19 |
modified | 2017-09-19 |
published | 2017-09-19 |
reporter | Root |
title | IrfanView JPEG 2000 Reference Tile Width Arbitrary Code Execution Vulnerability(CVE-2017-2813) |
Talos
id | TALOS-2017-0310 |
last seen | 2019-05-29 |
published | 2017-04-26 |
reporter | Talos Intelligence |
source | http://www.talosintelligence.com/vulnerability_reports/TALOS-2017-0310 |
title | IrfanView JPEG 2000 Reference Tile Width Arbitrary Code Execution Vulnerability |