11

This is the AddressSanitizer output, for different input I get READ and WRITE errors. From Heap Buffer Overflow perspective which are more interesting? I want to execute my shellcode. Can somebody interpret this AndressSanitizer output in more "human" understandable way?

READ example:

==24222== ERROR: AddressSanitizer: heap-buffer-overflow on address 0x602000010000 at pc 0x4022bd bp 0x7fff9b142e90 sp 0x7fff9b142e88
READ of size 1 at 0x602000010000 thread T0
    #0 0x4022bc (/home/user/final/apngdis-2.5.orig/apngdis+0x4022bc)
    #1 0x40619a (/home/user/final/apngdis-2.5.orig/apngdis+0x40619a)
    #2 0x4012cd (/home/user/final/apngdis-2.5.orig/apngdis+0x4012cd)
    #3 0x7f677aadfec4 (/lib/x86_64-linux-gnu/libc-2.19.so+0x21ec4)
    #4 0x401734 (/home/user/final/apngdis-2.5.orig/apngdis+0x401734)
0x602000010000 is located 0 bytes to the right of 192-byte region [0x60200000ff40,0x602000010000)
allocated by thread T0 here:
    #0 0x7f677b0b141a (/usr/lib/x86_64-linux-gnu/libasan.so.0.0.0+0x1541a)
    #1 0x4059bb (/home/user/final/apngdis-2.5.orig/apngdis+0x4059bb)
Shadow bytes around the buggy address:
  0x0c047fff9fb0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c047fff9fc0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c047fff9fd0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c047fff9fe0: fa fa fa fa fa fa fa fa 00 00 00 00 00 00 00 00
  0x0c047fff9ff0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=>0x0c047fffa000:[fa]fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c047fffa010: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c047fffa020: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c047fffa030: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c047fffa040: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c047fffa050: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
Shadow byte legend (one shadow byte represents 8 application bytes):
  Addressable:           00
  Partially addressable: 01 02 03 04 05 06 07 
  Heap left redzone:     fa
  Heap righ redzone:     fb
  Freed Heap region:     fd
  Stack left redzone:    f1
  Stack mid redzone:     f2
  Stack right redzone:   f3
  Stack partial redzone: f4
  Stack after return:    f5
  Stack use after scope: f8
  Global redzone:        f9
  Global init order:     f6
  Poisoned by user:      f7
  ASan internal:         fe
==24222== ABORTING

Below is GDB Output

Is this Heap overflow exploitable? What I should look for in the code? Can you give any examples with code snippets?

Starting program: /home/user/final/apngdis-2.5.orig/apngdis crash.png

APNG Disassembler 2.5

Reading 'crash.png'...

Breakpoint 2, unpack (zstream=..., dst=dst@entry=0x6e1910 "", dst_size=dst_size@entry=192, src=src@entry=0x6e19e0 "x\332b\356\317\300", src_size=src_size@entry=14, h=2147483651, 
    rowbytes=rowbytes@entry=63, bpp=1 '\001') at apngdis.c:171
171 {
(gdb) 
(gdb) 
(gdb) l
166       row[i] += row[i-bpp];
167   }
168 }
169 
170 void unpack(z_stream zstream, unsigned char * dst, unsigned int dst_size, unsigned char * src, unsigned int src_size, unsigned int h, unsigned int rowbytes, unsigned char bpp)
171 {
172   unsigned int    j;
173   unsigned char * row = dst;
174   unsigned char * prev_row = NULL;
175 
(gdb) l
176   zstream.next_out  = dst;
177   zstream.avail_out = dst_size;
178   zstream.next_in   = src;
179   zstream.avail_in  = src_size;
180   inflate(&zstream, Z_FINISH);
181   inflateReset(&zstream);
182 
183   for (j=0; j<h; j++)
184   {
185     switch (*row++) 
(gdb) l
186     {
187       case 0: break;
188       case 1: read_sub_row(row, rowbytes, bpp); break;
189       case 2: read_up_row(row, prev_row, rowbytes, bpp); break;
190       case 3: read_average_row(row, prev_row, rowbytes, bpp); break;
191       case 4: read_paeth_row(row, prev_row, rowbytes, bpp); break;
192     }
193     prev_row = row;
194     row += rowbytes;
195   }
(gdb) cont
Continuing.

Program received signal SIGSEGV, Segmentation fault.
unpack (zstream=..., dst=dst@entry=0x6e1910 "\003\217\257\277\307\313\315\316", '\317' <repeats 17 times>, "ϗ{mfca```\200\220H$\022\t\004\002\001", dst_size=dst_size@entry=192, 
    src=src@entry=0x6e19e0 "x\332b\356\317\300", src_size=src_size@entry=14, h=2147483651, rowbytes=rowbytes@entry=63, bpp=1 '\001') at apngdis.c:185
185     switch (*row++) 
(gdb) 

Here with symbols:

root@user-lap:~/final/apngdis-2.5.orig# export ASAN_SYMBOLIZER_PATH=/usr/bin/llvm-symbolizer-3.4 
root@user-lap:~/final/apngdis-2.5.orig# ASAN_OPTIONS=symbolize=1 ./apngdis crash.png 

APNG Disassembler 2.5

Reading 'crash.png'...
=================================================================
==25265== ERROR: AddressSanitizer: heap-buffer-overflow on address 0x602000010000 at pc 0x41c07d bp 0x7ffc560b3f20 sp 0x7ffc560b3f18
READ of size 1 at 0x602000010000 thread T0
    #0 0x41c07c in unpack /home/user/final/apngdis-2.5.orig/apngdis.c:185
    #1 0x41ff5a in LoadAPNG /home/user/final/apngdis-2.5.orig/apngdis.c:846
    #2 0x40281d in main /home/user/final/apngdis-2.5.orig/apngdis.c:1208
    #3 0x7fb4ca7e4ec4 (/lib/x86_64-linux-gnu/libc.so.6+0x21ec4)
    #4 0x402c84 in _start (/home/user/final/apngdis-2.5.orig/apngdis+0x402c84)
0x602000010000 is located 0 bytes to the right of 192-byte region [0x60200000ff40,0x602000010000)
allocated by thread T0 here:
    #0 0x412c0a in __interceptor_malloc (/home/user/final/apngdis-2.5.orig/apngdis+0x412c0a)
    #1 0x41f77b in LoadAPNG /home/user/final/apngdis-2.5.orig/apngdis.c:635
SUMMARY: AddressSanitizer: heap-buffer-overflow /home/user/final/apngdis-2.5.orig/apngdis.c:185 unpack
Shadow bytes around the buggy address:
  0x0c047fff9fb0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c047fff9fc0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c047fff9fd0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c047fff9fe0: fa fa fa fa fa fa fa fa 00 00 00 00 00 00 00 00
  0x0c047fff9ff0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=>0x0c047fffa000:[fa]fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c047fffa010: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c047fffa020: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c047fffa030: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c047fffa040: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c047fffa050: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
Shadow byte legend (one shadow byte represents 8 application bytes):
  Addressable:           00
  Partially addressable: 01 02 03 04 05 06 07 
  Heap left redzone:     fa
  Heap righ redzone:     fb
  Freed Heap region:     fd
  Stack left redzone:    f1
  Stack mid redzone:     f2
  Stack right redzone:   f3
  Stack partial redzone: f4
  Stack after return:    f5
  Stack use after scope: f8
  Global redzone:        f9
  Global init order:     f6
  Poisoned by user:      f7
  ASan internal:         fe
==25265== ABORTING

Last, but not least a link to a good tutorial on Heap Buffer Overflows under Linux that is actual will be awesome!

Here is complete code of program in question:

http://pastebin.com/qu6BRtJa

Update 29.02.2016

Found a write of 4 bytes. It seems there is a malloc call in LoadAPNG with user controlled value. Can the technique "The House of Force" be used?

==2720== ERROR: AddressSanitizer: heap-buffer-overflow on address 0x60ae0003a81c at pc 0x41ee70 bp 0x7ffc84d157d0 sp 0x7ffc84d157c8
WRITE of size 4 at 0x60ae0003a81c thread T0
    #0 0x41ee6f in compose6 /home/user/final/apngdis-2.5.orig/apngdis.c:475
    #1 0x420025 in LoadAPNG /home/user/final/apngdis-2.5.orig/apngdis.c:853
    #2 0x40281d in main /home/user/final/apngdis-2.5.orig/apngdis.c:1208
    #3 0x7f4942135ec4 (/lib/x86_64-linux-gnu/libc.so.6+0x21ec4)
    #4 0x402c84 in _start (/home/user/final/apngdis-2.5.orig/apngdis+0x402c84)
0x60ae0003a81c is located 0 bytes to the right of 114716-byte region [0x60ae0001e800,0x60ae0003a81c)
allocated by thread T0 here:
    #0 0x412c0a in __interceptor_malloc (/home/user/final/apngdis-2.5.orig/apngdis+0x412c0a)
    #1 0x41f746 in LoadAPNG /home/user/final/apngdis-2.5.orig/apngdis.c:633
SUMMARY: AddressSanitizer: heap-buffer-overflow /home/user/final/apngdis-2.5.orig/apngdis.c:474 compose6
Shadow bytes around the buggy address:
  0x0c163ffff4b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c163ffff4c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c163ffff4d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c163ffff4e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c163ffff4f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=>0x0c163ffff500: 00 00 00[04]fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c163ffff510: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c163ffff520: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c163ffff530: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c163ffff540: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c163ffff550: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
Shadow byte legend (one shadow byte represents 8 application bytes):
  Addressable:           00
  Partially addressable: 01 02 03 04 05 06 07 
  Heap left redzone:     fa
  Heap righ redzone:     fb
  Freed Heap region:     fd
  Stack left redzone:    f1
  Stack mid redzone:     f2
  Stack right redzone:   f3
  Stack partial redzone: f4
  Stack after return:    f5
  Stack use after scope: f8
  Global redzone:        f9
  Global init order:     f6
  Poisoned by user:      f7
  ASan internal:         fe
==2720== ABORTING

Update 07.02.2017

As requested by @grepNstepN

root@laptop:~/security/apngfuzz/apngdis-2.5.orig# gdb ./apngdis crash/crash.png
GNU gdb (Ubuntu 7.11.1-0ubuntu1~16.04) 7.11.1
Copyright (C) 2016 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from ./apngdis...done.
"/home/user/security/apngfuzz/apngdis-2.5.orig/crash/crash.png" is not a core dump: File format not recognized
(gdb) r crash/crash.png
Starting program: /home/user/security/apngfuzz/apngdis-2.5.orig/apngdis crash/crash.png
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".

APNG Disassembler 2.5

Reading 'crash/crash.png'...
=================================================================
==14864==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x60200000ef91 at pc 0x00000040b1b4 bp 0x7fffffffd9b0 sp 0x7fffffffd9a0
READ of size 1 at 0x60200000ef91 thread T0
    #0 0x40b1b3 in compose6 /home/user/security/apngfuzz/apngdis-2.5.orig/apngdis.c:469
    #1 0x40ca5f in LoadAPNG /home/user/security/apngfuzz/apngdis-2.5.orig/apngdis.c:850
    #2 0x4017be in main /home/user/security/apngfuzz/apngdis-2.5.orig/apngdis.c:1202
    #3 0x7ffff68a782f in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2082f)
    #4 0x402048 in _start (/home/user/security/apngfuzz/apngdis-2.5.orig/apngdis+0x402048)

0x60200000ef91 is located 0 bytes to the right of 1-byte region [0x60200000ef90,0x60200000ef91)
allocated by thread T0 here:
    #0 0x7ffff6f02602 in malloc (/usr/lib/x86_64-linux-gnu/libasan.so.2+0x98602)
    #1 0x40bb97 in LoadAPNG /home/user/security/apngfuzz/apngdis-2.5.orig/apngdis.c:632

SUMMARY: AddressSanitizer: heap-buffer-overflow /home/user/security/apngfuzz/apngdis-2.5.orig/apngdis.c:469 compose6
Shadow bytes around the buggy address:
  0x0c047fff9da0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c047fff9db0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c047fff9dc0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c047fff9dd0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c047fff9de0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa 00 06
=>0x0c047fff9df0: fa fa[01]fa fa fa 04 fa fa fa 01 fa fa fa 01 fa
  0x0c047fff9e00: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c047fff9e10: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c047fff9e20: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c047fff9e30: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c047fff9e40: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
Shadow byte legend (one shadow byte represents 8 application bytes):
  Addressable:           00
  Partially addressable: 01 02 03 04 05 06 07 
  Heap left redzone:       fa
  Heap right redzone:      fb
  Freed heap region:       fd
  Stack left redzone:      f1
  Stack mid redzone:       f2
  Stack right redzone:     f3
  Stack partial redzone:   f4
  Stack after return:      f5
  Stack use after scope:   f8
  Global redzone:          f9
  Global init order:       f6
  Poisoned by user:        f7
  Container overflow:      fc
  Array cookie:            ac
  Intra object redzone:    bb
  ASan internal:           fe
==14864==ABORTING
[Inferior 1 (process 14864) exited with code 01]
(gdb) disass crash/crash.pngQuit
(gdb) dis
disable      disassemble  disconnect   display      
(gdb) disass 0x40b1b3
Dump of assembler code for function compose6:
   0x000000000040a990 <+0>: lea    -0x98(%rsp),%rsp
   0x000000000040a998 <+8>: mov    %rdx,(%rsp)
   0x000000000040a99c <+12>:    mov    %rcx,0x8(%rsp)
   0x000000000040a9a1 <+17>:    mov    %rax,0x10(%rsp)
   0x000000000040a9a6 <+22>:    mov    $0xbb3f,%rcx
   0x000000000040a9ad <+29>:    callq  0x4112e0 <__afl_maybe_log>
   0x000000000040a9b2 <+34>:    mov    0x10(%rsp),%rax
   0x000000000040a9b7 <+39>:    mov    0x8(%rsp),%rcx
   0x000000000040a9bc <+44>:    mov    (%rsp),%rdx
   0x000000000040a9c0 <+48>:    lea    0x98(%rsp),%rsp
   0x000000000040a9c8 <+56>:    push   %r15
   0x000000000040a9ca <+58>:    push   %r14
   0x000000000040a9cc <+60>:    push   %r13
   0x000000000040a9ce <+62>:    push   %r12
   0x000000000040a9d0 <+64>:    push   %rbp
   0x000000000040a9d1 <+65>:    push   %rbx
   0x000000000040a9d2 <+66>:    sub    $0x48,%rsp
   0x000000000040a9d6 <+70>:    movzbl 0x88(%rsp),%r13d
   0x000000000040a9df <+79>:    mov    %rdi,0x18(%rsp)
   0x000000000040a9e4 <+84>:    mov    %r8d,0x28(%rsp)
   0x000000000040a9e9 <+89>:    mov    %r9d,0x2c(%rsp)
   0x000000000040a9ee <+94>:    add    $0x7,%r13d
---Type <return> to continue, or q <return> to quit---q
Quit
(gdb) i r
The program has no registers now.
(gdb) b *0x40b1b3
Breakpoint 1 at 0x40b1b3: file apngdis.c, line 469.
(gdb) r crash/crash.png
Starting program: /home/user/security/apngfuzz/apngdis-2.5.orig/apngdis crash/crash.png
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".

APNG Disassembler 2.5

Reading 'crash/crash.png'...

Program received signal SIGSEGV, Segmentation fault.
0xffffffffcd4013e0 in ?? ()

(gdb) i r
rax            0x1  1
rbx            0x1  1
rcx            0x60210000efd0   105694850248656
rdx            0xc0400001df2    13211319410162
rsi            0x60200000ef92   105690555281298
rdi            0x60200000ef91   105690555281297
rbp            0x2  0x2
rsp            0x7fffffffd9b8   0x7fffffffd9b8
r8             0x0  0
r9             0x1  1
r10            0x60200000eff0   105690555281392
r11            0x60200000ef91   105690555281297
r12            0x40000000   1073741824
r13            0x1  1
r14            0x1  1
r15            0x4  4
rip            0xffffffffcd4013e0   0xffffffffcd4013e0
eflags         0x10202  [ IF RF ]
cs             0x33 51
ss             0x2b 43
ds             0x0  0
es             0x0  0
fs             0x0  0
---Type <return> to continue, or q <return> to quit---
gs             0x0  0

(gdb) info registers rip
rip            0xffffffffcd4013e0   0xffffffffcd4013e0
  • 3
    www.mathyvanhoef.com/2013/02/understanding-heap-exploiting-heap.html this might help u – BlueBerry - Vignesh4303 Feb 26 '16 at 13:41
  • 1
    ok thanks. Briefly read it ... so i guess this is not exploitable .. since I need to get WRITEs not READs on the heap, also other conditions need to be meet, which I will have to check for. – dev Feb 26 '16 at 14:19
  • 1
    With other condition I meant techniques like: 1) The House of Prime 2) The House of Mind 3) The House of Force 4) The House of Lore 5) The House of Spirit. All techniques require a sufficient (and controllable) amount of calls to free and/or malloc. Have to check if my program makes such calls. Do I understand it correctly? – dev Feb 29 '16 at 13:01
  • 1
    Any buffer that can overflow can be exploited. Any time a source code allows a user to overwrite the end of a buffer, it can be exploited. Even if the buffer that overflows is a heap. – Brent Kirkpatrick Apr 14 '16 at 3:28
  • 2
    Out of curiousity, what is the malicious png that caused the [program][1] to crash? [1]: pastebin.com/qu6BRtJa – grepNstepN Jun 28 '16 at 15:36
3

I understand where you're coming from, I fuzz various products (chrome, flash, among some other things). The last thing you want to do is give away a possible bounty or advisory (I support the former more than the latter, especially considering what happened to Aaron Schwartz).

Think about it: in this case apngdis can yield a possible parser or file format vulnerability in libpng, which is used by Chrome, Firefox, Webkit (iOS, OSX), etc. The aforementioned all have bug bounties. At the very least, Google offers bounties for securing open source projects. I don't know if apngdis is used in any products directly.

Considering the aforementioned, if you need help, you can do what I've done in the past regarding several vulnerabilities I've found:

  1. Ask help from someone who has too much reputation to steal your bounty/advisory (#corelan/Peter Van Eekhoutte comes to mind), but offer a shoutout/thanks in the advisory...curiousity/a challenge/fame/altruism is a great motivator
  2. Ask someone to sign a NDA to ensure no theft occurs. In return, however, you'll have to give a portion of the bounty/glory (a shoutout in the advisory, or even co-authorship)
  3. Review previous tutorials and exploit writeups, looking for similarities
  4. Ask for help offering nothing in return on stackexchange, which is fairly disrespectful. At least if its a public disclosure, give a thanks to whomever helps...there's a reason why you don't see more people asking for exploitation help on stackexchange.

If you choose #4, we'll need the following from you:

We need the disassembly of the read at [apngdis+0x4022bc], the previous instruction, and the call stack. Same goes for the write (disassembly of RIP, RIP-1 instruction, call stack)

Consider: interpreting the ASan output won't necessarily help you with exploitability without the aforementioned. For instance:

==24222== ERROR: AddressSanitizer: heap-buffer-overflow on address 0x602000010000 at pc 0x4022bd bp 0x7fff9b142e90 sp 0x7fff9b142e88
READ of size 1 at 0x602000010000 thread T0
#0 0x4022bc (/home/user/final/apngdis-2.5.orig/apngdis+0x4022bc)
...
  • THANKS!!! Are you still interested in this? I can provide you with more details ... but have to dig them out ... it has been a while now – dev Feb 6 '17 at 19:16
  • yeah i'm still interested. would you like assistance on stackexchange or out of band – grepNstepN Feb 8 '17 at 15:25
  • Perfect!!! Yea, out of band would be better since I have some other programs I have similar questions and you seem like a knowledgeable and helping person :) In regards to this questions, I partially figured it out here: security.stackexchange.com/questions/150637/… and security.stackexchange.com/questions/150658/… – dev Feb 8 '17 at 16:27
  • ok, do you want to either A) update your profile (or comment here) with a (temp) email address from guerrillamail so I can email you my contact info or B) paste it on ghostbin? – grepNstepN Feb 8 '17 at 20:21
  • if you dont care about OPSEC (you should as your a vuln researcher and foreign intelligence services (RU/CN/VN/Cuba) will steal your shit) post your email in the comment section – grepNstepN Feb 8 '17 at 20:22
2

CVE-2017-6193 has been reserved for this specific vulnerability (present in version 2.8). Your name has been included as the discoverer and as a co-contributor.

Tomorrow this post will be online for a year, and at time of writing has been viewed almost 2000 times. So to prevent anyone from misusing this, and seeing as the details are still public, I hope you don't mind I took the liberty of running apngdis in an afl-fuzz cluster to reconstruct the issue for reporting.

Among rediscovering these memory corruptions, there was also one in the chunk size descriptor, not to mention a textbook overflow in the handling of the filename parameter.

I debugged the issues and notified the developer. After explaining the seriousness of the situation that went on behind his back, he was very responsive and is now kind enough to be working on version 2.9.

The memory corruption in the compose_frame function is still present in the latest version 2.8, and is easy to explain. memcpy() gets invoked over a bunch of zeroes with an attacker supplied length, within some constraints.

First, after making sure it's actually a PNG, and an IHDR size field, the value gets loaded from the file:

    w0 = w = png_get_uint_32(chunkIHDR.p + 8);
    h0 = h = png_get_uint_32(chunkIHDR.p + 12);

Then after checking the values to be less than const unsigned long cMaxPNGSize = 1000000UL;, the following gets called:

compose_frame(frameCur.rows, frameRaw.rows, bop, x0, y0, w0, h0);

Which consist of:

void compose_frame(unsigned char ** rows_dst, unsigned char ** rows_src, unsigned char bop, unsigned int x, unsigned int y, unsigned int w, unsigned int h)
{
  unsigned int  i, j;
  int u, v, al;

  for (j=0; j<h; j++)
  {
    unsigned char * sp = rows_src[j];
    unsigned char * dp = rows_dst[j+y] + x*4;

    if (bop == 0)
      memcpy(dp, sp, w*4);

Memcpy gets invoked and happily starts copying a few million zeroes before running into unmapped memory.:

Breakpoint 1, compose_frame (rows_dst=0x7fffef54f010, rows_src=0x7ffff3150010, bop=0 '\000', x=0, y=0, w=983040, h=983040) at apngdis.cpp:77
77          if (bop == 0)
(gdb) n
78            memcpy(dp, sp, w*4);
(gdb) print dp
$1 = (unsigned char *) 0x55555576f910 ""
(gdb) print sp
$2 = (unsigned char *) 0x55555576f2a0 ""
(gdb) print w

On Windows x86, this compiles to the following assembly and we can see the copying happens from ESI to EDI:

.text:011FFA90 loc_11FFA90: ; CODE XREF: .text:011FFAEBj .text:011FFA90 movdqa xmm0, oword ptr [esi] .text:011FFA94 movdqa xmm1, oword ptr [esi+10h] .text:011FFA99 movdqa xmm2, oword ptr [esi+20h] .text:011FFA9E movdqa xmm3, oword ptr [esi+30h] .text:011FFAA3 movdqa oword ptr [edi], xmm0 .text:011FFAA7 movdqa oword ptr [edi+10h], xmm1 .text:011FFAAC movdqa oword ptr [edi+20h], xmm2 .text:011FFAB1 movdqa oword ptr [edi+30h], xmm3 .text:011FFAB6 movdqa xmm4, oword ptr [esi+40h] .text:011FFABB movdqa xmm5, oword ptr [esi+50h] .text:011FFAC0 movdqa xmm6, oword ptr [esi+60h] .text:011FFAC5 movdqa xmm7, oword ptr [esi+70h] .text:011FFACA movdqa oword ptr [edi+40h], xmm4 .text:011FFACF movdqa oword ptr [edi+50h], xmm5 .text:011FFAD4 movdqa oword ptr [edi+60h], xmm6 .text:011FFAD9 movdqa oword ptr [edi+70h], xmm7 .text:011FFADE lea esi, [esi+80h] .text:011FFAE4 lea edi, [edi+80h] .text:011FFAEA dec edx .text:011FFAEB jnz short loc_11FFA90

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.