Fuzzying older version of libpng

341 views
Skip to first unread message

Daniel Stender

unread,
Aug 3, 2017, 7:07:59 PM8/3/17
to afl-...@googlegroups.com
Hi,

I'm writing an article of AFL for a German magazine and I want to provide an example which
readers could try out, and I've decided to show how CVE-2015-8126 can be/has been found by/
with AFL in an older tarball of libpng.

That's a buffer overflow in png_set_PLTE and png_get_PLTE in libpng before 1.0.64, 1.2.54, 1.4.17,
1.5.24 and 1.6.19 (fail to check for an out-of-range-palette when reading or writing a PNG with
a bit depth less than 8).

This has been reported by Jakub against optipng first in 2015 (https://bugs.debian.org/787647), and then
later it has been reassigned to libpng itself.

libpng is rather easy to build as widely known, only zlib is needed, and there's also a pngtest.c
which can be used to test drive the thing on the spot - easy to follow and to try out. The crash sample
from the bug report on optipng as a matter of fact triggers a crash in libpng 1.2.53:

<cut>
$ ./libpng-1.2.53/pngtest crash.png

Testing libpng version 1.2.53
with zlib version 1.2.8

libpng version 1.2.53 - February 26, 2015
Copyright (c) 1998-2015 Glenn Randers-Pehrson
Copyright (c) 1996-1997 Andreas Dilger
Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.
library (10253): libpng version 1.2.53 - February 26, 2015

pngtest (10253): libpng version 1.2.53 - February 26, 2015
sizeof(png_struct)=1264, sizeof(png_info)=464

libpng error: Read Error
Testing crash.png:crash.png -> pngout.png: libpng read error
</cut>

I'm fuzzying the library now using pngtest, and I've only instrumented pngget.c (targeting png_get_PLTE)
to trigger a read error following the advice in perf_tips.txt of AFL because building the whole library
with afl-gcc brought up a "too slow" warning. I've seeded afl-fuzz with not_kitty.png from the shipped
testcases.

The article is waiting for this to succeed with hopefully one try, for that I want to ask if
somebody has done this, this CVE in particular or fuzzed libpng on another issue before and some
advice how to do that right, and bring up the targeted result (maybe next to others).

Thanks
Daniel Stender

--
4096R/DF5182C8 (ste...@debian.org)
http://www.danielstender.com/

Michal Zalewski

unread,
Aug 3, 2017, 7:14:47 PM8/3/17
to afl-users
> libpng is rather easy to build as widely known, only zlib is needed, and there's also a pngtest.c
> which can be used to test drive the thing on the spot - easy to follow and to try out. The crash sample
> from the bug report on optipng as a matter of fact triggers a crash in libpng 1.2.53:
>
> <cut>
> $ ./libpng-1.2.53/pngtest crash.png
>
> [...]
>
> libpng error: Read Error
> Testing crash.png:crash.png -> pngout.png: libpng read error
> </cut>

That does not sound like a crash?

> I'm fuzzying the library now using pngtest, and I've only instrumented pngget.c (targeting png_get_PLTE)

Please don't do this; it's unlikely to produce satisfactory results.

> to trigger a read error following the advice in perf_tips.txt of AFL because building the whole library
> with afl-gcc brought up a "too slow" warning.

This suggests there is a more substantial problem elsewhere; you
should not be getting that warning with something like pngtest.

/mz

Konstantin Serebryany

unread,
Aug 3, 2017, 7:39:59 PM8/3/17
to afl-...@googlegroups.com
We are using libpng-1.2.56 as a benchmarks for libFuzzer: 
So far we did not find any interesting crashes in that version, only one case of allocating 2Gb in a single malloc. 

We also fuzz libpng trunk continuously at OSS-Fuzz (using both libFuzzer and AFL): 
Nothing exciting so far, but we've recently caught a regression in trunk

--kcc 



--
You received this message because you are subscribed to the Google Groups "afl-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to afl-users+unsubscribe@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Jakub Wilk

unread,
Aug 4, 2017, 3:58:14 AM8/4/17
to afl-...@googlegroups.com
* Daniel Stender <deb...@danielstender.com>, 2017-08-04, 01:07:
>This has been reported by Jakub against optipng first in 2015
>(https://bugs.debian.org/787647), and then later it has been reassigned to
>libpng itself.

I have only hazy memory of that time; but fortunately I still have the old
files lying around, so I was able to reconstruct what I did:

* I patched libpng to disable CRC checks (see
experimental/libpng_no_checksum/libpng-nocrc.patch).

* I compiled both optipng and libpng with afl-clang-fast.

* I used not_kitty*.png as initial input.

* I cheated by importing the the png/full/images directory from
<http://lcamtuf.coredump.cx/afl/demo/afl_testcases.tgz>.

* My hardware looks like this:

$ lscpu | grep -E '^(Model |CPU max)'
Model name: AMD Athlon(tm) 64 X2 Dual Core Processor 4400+
CPU max MHz: 2300.0000

* I fuzzed on two cores (1 master + 1 secondary instance).

* I achieved 800-900 execs per second per core.

* It took about 50 minutes (of wall clock time) to hit the bug.

>there's also a pngtest.c which can be used to test drive the thing on the spot

I don't believe pngtest would ever trigger this bug.

See https://sourceforge.net/p/png-mng/mailman/message/34626800/ for a
description how a hypothetical vulnerable program would look like.

--
Jakub Wilk
Message has been deleted

SSi

unread,
Apr 3, 2018, 10:21:29 AM4/3/18
to afl-users
Hi Jakub,

Did you end up having to use the full png directory in afl_testcases, or did you just use the four png files (not_kitty*.png files that come with afl)?

I have been running the following code with afl to target this vulnerability:


static int fuzzPNG_get_PLTE(FILE *fp){

    if (!fp){
        return 1; // reutrn ERROR
    }



    //check that input file is a valid PNG
    char header[8];
    fread(header, 1, 8, fp);
    int is_png = !png_sig_cmp(header, 0, 8);
    if (!is_png) {
        return 1;
    }

   /* Allocate/initialize the memory for image information.  REQUIRED. */
    png_structrp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
    if(!png_ptr)
        return 1;

    png_infop info_ptr = png_create_info_struct(png_ptr);
    if (!info_ptr){
        png_destroy_read_struct(&png_ptr,(png_infopp)NULL, (png_infopp)NULL);
        return 1;
    }

    png_infop end_info = png_create_info_struct(png_ptr);
    if (!end_info){
        png_destroy_read_struct(&png_ptr, &info_ptr,(png_infopp)NULL);
        return 1;
    }

    if (setjmp(png_jmpbuf(png_ptr))){
        png_destroy_read_struct(&png_ptr, &info_ptr,&end_info);
        fclose(fp);
        return 1;
    }


    png_init_io(png_ptr, fp);
    png_set_sig_bytes(png_ptr, 8);

    png_read_info(png_ptr, info_ptr);

    int num_palette;
    png_colorp palette;
    png_get_PLTE(png_ptr, info_ptr, &palette, &num_palette);

    return 0;
}

int main(void){
    return fuzzPNG_get_PLTE(stdin);
}

So far I have not been able to produce any crashes with alf after over 24 hours.

 
Am I targeting the png_get_PLTE() function appropriately, based on the code snippet provided above? Did you do anything differently?

Thanks,

   - Shane
Reply all
Reply to author
Forward
0 new messages