CVE-2019-8383: Invalid memory access in adv_png_unfilter_8( ) – advancecomp

Invalid memory access vulnerability in the function adv_png_unfilter_8( ) – advancecomp-2.1

Loginsoft-2018-1050

February 13, 2019

CVE Number

CVE-2019-8383

CWE

CWE-119: Improper Restriction of Operations within the Bounds of a Memory Buffer

Product Details

AdvanceCOMP contains recompression utilities for your .zip archives,.png images, .mng video clips and .gz files.
URL: https://sourceforge.net/projects/advancemame/

Vulnerable Versions

2.1

Vulnerability Details

During our research on advancecomp, we found invalid memory address in function adv_png_unfilter_8 ( ) at file png.c. The same can be triggered by sending a crafted abc file to the binary. It allows an attacker to cause Denial of Service (Segmentation fault) or possibly have unspecified other impact when a victim opens a specially crafted file.

SYNOPSIS

As per our research we observed that the vulnerability exists in function adv_png_unfilter_8( ) at file png.c . The function adv_png_read_rns( ),which reads an image from memory which is in png format and invokes the function adv_png_read_ihdr (),which reads a part of chunk image from PNG_CN_IHDR to the chunk from the main in PNG_CN_IEND . This function invokes adv_png_unfilter_8( ) which unfilters a 8 bit image of width, height, data and size of row. When a crafted file is passed to the binary advpng in function adv_png_unfilter_8( ) at unsigned char f = *p++;
p += width;
The value of width is being assigned to p. The value of f is 0 and p is having a value at address while incrementing the p value the vulnerability is being triggered as invalid memory access.

Vulnerable code
for(i=0;i<height;++i) {
        unsigned char f = *p++;
          if (f == 0) { /* none */
            p += width;
}
Analysis

 

277            unsigned char f = *p++;
[ Legend: Modified register | Code | Heap | Stack | String ]
───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────[ registers ]────
$rax   : 0x80661b7d        
$rbx   : 0x0               
$rcx   : 0x8000008d        
$rdx   : 0x80661b7e        
$rsp   : 0x7fffffffd7d0      →  0x00007fffffffd910  →  0x00007fffffffd9e0  →  0x00007fffffffda90  →  0x00007fffffffdb70  →  0x00007fffffffdc60  →  0x00007fffffffdce0  →  0x00007fffffffddb0
$rbp   : 0x7fffffffd7d0      →  0x00007fffffffd910  →  0x00007fffffffd9e0  →  0x00007fffffffda90  →  0x00007fffffffdb70  →  0x00007fffffffdc60  →  0x00007fffffffdce0  →  0x00007fffffffddb0
$rsi   : 0x78              
$rdi   : 0x8000008c        
$rip   : 0x40c5c7            →   movzx eax, BYTE PTR [rax]
$r8    : 0x65ffa0            →  0x0000000000000000
$r9    : 0x1               
$r10   : 0x8b8             
$r11   : 0x7ffff6fca4f0      →   push r13
$r12   : 0x402fe0            →   xor ebp, ebp
$r13   : 0x7fffffffdee0      →  0x0000000000000005
$r14   : 0x0               
$r15   : 0x0               
$eflags: [CARRY parity ADJUST zero SIGN trap INTERRUPT direction overflow RESUME virtualx86 identification]
$fs: 0x0000  $cs: 0x0033  $gs: 0x0000  $es: 0x0000  $ds: 0x0000  $ss: 0x002b  
───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────[ stack ]────
0x00007fffffffd7d0│+0x00: 0x00007fffffffd910  →  0x00007fffffffd9e0  →  0x00007fffffffda90  →  0x00007fffffffdb70  →  0x00007fffffffdc60  →  0x00007fffffffdce0  →  0x00007fffffffddb0     ← $rsp, $rbp
0x00007fffffffd7d8│+0x08: 0x000000000040d8d0  →   jmp 0x40db14 
0x00007fffffffd7e0│+0x10: 0xb7b6b5b4b3b2b1b0
0x00007fffffffd7e8│+0x18: 0x000000000065fe00  →  0x780000008c000080
0x00007fffffffd7f0│+0x20: 0x000000000065fc60  →  0x00007fff00000001
0x00007fffffffd7f8│+0x28: 0x00007fffffffda50  →  0x8000008d00000000
0x00007fffffffd800│+0x30: 0x00007fffffffda68  →  0x0000000000000000
0x00007fffffffd808│+0x38: 0x00007fffffffda4c  →  0x000000000000007e ("~"?)
────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────[ code:i386:x86-64 ]────
     0x40c5b7  test   BYTE PTR [rdx], 0x0
     0x40c5ba  add    BYTE PTR [rax-0x75], cl
     0x40c5bd  rex.RB movabs al, ds:0xa055894801508d48
→   0x40c5c7  movzx  eax, BYTE PTR [rax]
     0x40c5ca  mov    BYTE PTR [rbp-0x41], al
     0x40c5cd  cmp    BYTE PTR [rbp-0x41], 0x0
     0x40c5d1  jne    0x40c5df 
     0x40c5d3  mov    eax, DWORD PTR [rbp-0x54]
     0x40c5d6  add    QWORD PTR [rbp-0x60], rax
────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────[ source:lib/png.c+277 ]────
    272     void adv_png_unfilter_8(unsigned width, unsigned height, unsigned char* p, unsigned line)
    273     {
    274         unsigned i, j;
    275     
    276         for(i=0;i<height;++i) {
        // f=0x0, p=0x00007fffffffd770  →  0x0000000080661b7e
→  277             unsigned char f = *p++;
    278     
    279             if (f == 0) { /* none */
    280                 p += width;
    281             } else if (f == 1) { /* sub */
    282                 ++p;
─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────[ threads ]────
[#0] Id 1, Name: "advpng", stopped, reason: SIGSEGV
───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────[ trace ]────
[#0] 0x40c5c7 → Name: adv_png_unfilter_8(width=0x8000008c, height=0x78, p=0x80661b7e , line=0x8000008d)
[#1] 0x40d8d0 → Name: adv_png_read_ihdr(pix_width=0x7fffffffda44, pix_height=0x7fffffffda48, pix_pixel=0x7fffffffda40, dat_ptr=0x7fffffffda58, dat_size=0x7fffffffda3c, pix_ptr=0x7fffffffda70, pix_scanline=0x7fffffffda54, pal_ptr=0x7fffffffda60, pal_size=0x7fffffffda4c, rns_ptr=0x7fffffffda68, rns_size=0x7fffffffda50, f=0x65fc60, data=0x65fe00 "\200", data_size=0xd)
[#2] 0x40dc94 → Name: adv_png_read_rns(pix_width=0x7fffffffda44, pix_height=0x7fffffffda48, pix_pixel=0x7fffffffda40, dat_ptr=0x7fffffffda58, dat_size=0x7fffffffda3c, pix_ptr=0x7fffffffda70, pix_scanline=0x7fffffffda54, pal_ptr=0x7fffffffda60, pal_size=0x7fffffffda4c, rns_ptr=0x7fffffffda68, rns_size=0x7fffffffda50, f=0x65fc60)
[#3] 0x4037dd → Name: convert_f(f_in=0x65fc60, f_out=0x65fd30)
[#4] 0x403a62 → Name: convert_inplace(path="$POC")
[#5] 0x404209 → Name: rezip_single(file="id:000000,sig:11,src:000000,op:flip1,pos:16", total_0=@0x7fffffffdc90, total_1=@0x7fffffffdc98)
[#6] 0x4045a1 → Name: rezip_all(argc=0x1, argv=0x7fffffffdf08)
[#7] 0x404df0 → Name: process(argc=0x5, argv=0x7fffffffdee8)
[#8] 0x404fba → Name: main(argc=0x5, argv=0x7fffffffdee8)
Tested environment

64-bit ubuntu 16.04 LTS

Proof of Concept

- ./advpng -z -1 –f $POC

Timeline

Vendor Disclosure: 03-01-2019
Public Disclosure: 13-02-2019

Credit

Discovered by ACE Team – Loginsoft