Talos Vulnerability Report

TALOS-2017-0459

Computerinsel Photoline PCX Parsing Code Execution Vulnerability

October 30, 2017
CVE Number

CVE-2017-12107

Summary

An memory corruption vulnerability exists in the .PCX parsing functionality of Computerinsel Photoline 20.02. A specially crafted .PCX file can cause a vulnerability resulting in potential code execution. An attacker can send a specific .PCX file to trigger this vulnerability.

Tested Versions

Computerinsel Photoline 20.02

Product URLs

https://www.pl32.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-787: Out-of-bounds Write

Details

The code responsible for the vulnerability is provided below:

    .text:00B8D3AA                 xor     edi, edi        ; ebp=loop1 max count | edi = counter
    .text:00B8D3AC                 test    ebp, ebp
    .text:00B8D3AE                 jle     short loop_done2
    .text:00B8D3B0
    .text:00B8D3B0 loc_B8D3B0:                             ; CODE XREF: pcx_bad_func+D5°j
    .text:00B8D3B0                 mov     al, [esi]       ; [esi] point to attacker's data
    .text:00B8D3B2                 mov     dl, al
    .text:00B8D3B4                 and     dl, 0C0h
    .text:00B8D3B7                 cmp     dl, 0C0h        ; condition 1
    .text:00B8D3BA                 jnz     short loc_B8D3DE
    .text:00B8D3BC                 and     al, 3Fh
    .text:00B8D3BE                 movzx   ax, al
    .text:00B8D3C2                 movzx   eax, ax
    .text:00B8D3C5                 cwde
    .text:00B8D3C6                 inc     esi
    .text:00B8D3C7                 test    eax, eax        ; condition 2 (and a loop2 counter)
    .text:00B8D3C9                 jle     short loc_B8D3DA
    .text:00B8D3CB                 jmp     short loc_B8D3D0 ; overwrite
    .text:00B8D3CB ; ---------------------------------------------------------------------------
    .text:00B8D3CD                 align 10h
    .text:00B8D3D0
    .text:00B8D3D0 loc_B8D3D0:                             ; CODE XREF: pcx_bad_func+BB^j
    .text:00B8D3D0                                         ; pcx_bad_func+C8°j
    .text:00B8D3D0                 mov     dl, [esi]       
    .text:00B8D3D2                 mov     [ecx], dl       ; copy attacker's data byte by byte
    .text:00B8D3D4                 inc     ecx
    .text:00B8D3D5                 sub     eax, 1
    .text:00B8D3D8                 jnz     short loc_B8D3D0 ; continue write (loop 2)
    .text:00B8D3DA
    .text:00B8D3DA loc_B8D3DA:                             ; CODE XREF: pcx_bad_func+B9^j
    .text:00B8D3DA                 inc     esi
    .text:00B8D3DB                 inc     edi
    .text:00B8D3DC                 jmp     short is_loop_done1
                    
    .text:00B8D3DE loc_B8D3DE:                             ; CODE XREF: pcx_bad_func+AA^j
    .text:00B8D3DE                 mov     [ecx], al
    .text:00B8D3E0                 inc     ecx
    .text:00B8D3E1                 inc     esi
    .text:00B8D3E2
    .text:00B8D3E2 is_loop_done1:                          ; CODE XREF: pcx_bad_func+CC^j
    .text:00B8D3E2                 inc     edi
    .text:00B8D3E3                 cmp     edi, ebp
    .text:00B8D3E5                 jl      short loc_B8D3B0       ; loop 1, again        

An attacker can control the number of “loop 2” iterations because the max loop iteration value is obtained directly from the PCX file (instruction at 0x00B8D3D0). This can cause a memory corruption where attacker controls the size and the source data.

Crash Information

    HEAP[PhotoLine32.exe]: Heap block at 06DEE068 modified at 06DEE3A1 past requested size of 331
    (89c.3698): Break instruction exception - code 80000003 (first chance)
    eax=06dee068 ebx=06dee3a1 ecx=778e3733 edx=0018e2d5 esi=06dee068 edi=00000331
    eip=7794071c esp=0018e51c ebp=0018e51c iopl=0         nv up ei pl nz na po nc
    cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000202
    ntdll!RtlpBreakPointHeap+0x23:
    7794071c cc              int     3
    0:000> !heap
    NtGlobalFlag enables following debugging aids for new heaps:    tail checking
        free checking
        validate parameters
    Stop inside heap manager...validating heap address 0x06dee068
    Index   Address  Name      Debugging options enabled
      1:   01760000 
        Segment at 01760000 to 01860000 (000a1000 bytes committed)
      2:   00350000 
        Segment at 00350000 to 00360000 (0000a000 bytes committed)
        Segment at 03a30000 to 03b30000 (000bd000 bytes committed)
      3:   030a0000 
        Segment at 030a0000 to 030b0000 (00001000 bytes committed)
      4:   032a0000 
        Segment at 032a0000 to 032b0000 (00010000 bytes committed)
        Segment at 02f80000 to 03080000 (00100000 bytes committed)
        Segment at 03b30000 to 03d30000 (00200000 bytes committed)
        Segment at 04110000 to 04510000 (00400000 bytes committed)
        Segment at 05100000 to 05900000 (00800000 bytes committed)
        Segment at 05ea0000 to 06e70000 (00fd0000 bytes committed)
        Segment at 07190000 to 08160000 (0008f000 bytes committed)
        Flags:                40001062
        ForceFlags:           40000060
        Granularity:          8 bytes
        Segment Reserve:      02fa0000
        Segment Commit:       00002000
        DeCommit Block Thres: 00000200
        DeCommit Total Thres: 00002000
        Total Free Size:      0000c9f3
        Max. Allocation Size: 7ffdefff
        Lock Variable at:     032a0138
        Next TagIndex:        0000
        Maximum TagIndex:     0000
        Tag Entries:          00000000
        PsuedoTag Entries:    00000000
        Virtual Alloc List:   032a00a0
        Unable to read nt!_HEAP_VIRTUAL_ALLOC_ENTRY structure at 05be0000
        Uncommitted ranges:   032a0090
        FreeList[ 00 ] at 032a00c4: 0512f228 . 06de6c20      Unable to read nt!_HEAP_FREE_ENTRY structure at fffffff7
     (632 blocks)

            06dee020: 00030 . 00048 [107] - busy (30), tail fill
            06dee068: 00048 . 00350 [107] - busy (331), tail fill (Handle ffffffff) (Tag ffff)

    Stack traces not enabled (ntdll!RtlpStackTraceDataBase is null).

        Heap block at 06dee068 modified at 06dee3a1 past requested size of 331 (6a * 8 - 1f)
            06dee3b8: 55960 . 6b288 [01] - busy (5b289)
        
    ##CORRUPTION FOUND at 0x06DEE3B8
        PreviousSize field does not match Size field in previous entry 
        Entry->PreviousSize == 0xd651
        PreviousEntry->Size == 0x9
        
    ##CORRUPTION FOUND at 0x06E59640
        PreviousSize field does not match Size field in previous entry 
        Entry->PreviousSize == 0xf00d
        PreviousEntry->Size == 0xab2c
    ##The above errors were found in segment at 0x05EA0000
        Flags:                40001062
        ForceFlags:           40000060
        Granularity:          8 bytes
        Segment Reserve:      02fa0000
        Segment Commit:       00002000
        DeCommit Block Thres: 00000200
        DeCommit Total Thres: 00002000
        Total Free Size:      0000c9f3
        Max. Allocation Size: 7ffdefff
        Lock Variable at:     032a0138
        Next TagIndex:        0000
        Maximum TagIndex:     0000
        Tag Entries:          00000000
        PsuedoTag Entries:    00000000
        Virtual Alloc List:   032a00a0
        Unable to read nt!_HEAP_VIRTUAL_ALLOC_ENTRY structure at 05be0000
        Uncommitted ranges:   032a0090
        FreeList[ 00 ] at 032a00c4: 0512f228 . 06de6c20      Unable to read nt!_HEAP_FREE_ENTRY structure at fffffff7
     (632 blocks)

            06dee020: 00030 . 00048 [107] - busy (30), tail fill
            06dee068: 00048 . 00350 [107] - busy (331), tail fill (Handle ffffffff) (Tag ffff)

    Stack traces not enabled (ntdll!RtlpStackTraceDataBase is null).

        Heap block at 06dee068 modified at 06dee3a1 past requested size of 331 (6a * 8 - 1f)
            06dee3b8: 55960 . 6b288 [01] - busy (5b289)
        
    ##CORRUPTION FOUND at 0x06DEE3B8
        PreviousSize field does not match Size field in previous entry 
        Entry->PreviousSize == 0xd651
        PreviousEntry->Size == 0x9
        
    ##CORRUPTION FOUND at 0x06E59640
        PreviousSize field does not match Size field in previous entry 
        Entry->PreviousSize == 0xf00d
        PreviousEntry->Size == 0xab2c
    ##The above errors were found in segment at 0x05EA0000

Timeline

2017-10-11 - Vendor Disclosure
2017-10-30 - Public Release

Credit

Discovered by Piotr Bania of Cisco Talos