Skip to content

Fuzzing golang image (Go) project with sydr fuzz (go fuzz backend)

Andrey Fedotov edited this page Mar 2, 2023 · 21 revisions

Introduction

In this article we will try to apply hybrid fuzzing tool sydr-fuzz for fuzzing Go projects. Sydr-fuzz combines the power of Sydr - dynamic symbolic execution tool and AFLplusplus. It also supports another fuzzing engine libFuzzer, which we will use. We are lucky, go-fuzz has libFuzzer support, so we could try to use it as libFuzzer engine in sydr-fuzz. In this guide we will focus on preparing targets for go-fuzz(libFuzzer), Sydr, and code coverage. We will do hybrid fuzzing using Sydr & go-fuzz and then we will collect code coverage. Also, we will use our crash triage tool casr, and apply Sydr to check security predicates for finding interesting bugs using symbolic execution techniques. And of course, I'll focus on some interesting cases that I met during my experience in fuzzing Go projects.

Preparing Fuzz Target

Image decoders such as golang/image is a nice target to apply fuzzing. Before I start, there is already prepared for building docker container with all fuzz environment: targets for go-fuzz, Sydr, and code coverage.

go-fuzz has detailed instruction how to build fuzz targets and start fuzzing. Also there is a nice go-fuzz-corpus repository where you can find fuzz targets and initial corpus. In this repository there are fuzz targets for golang/image project (png, webp, tiff, jpeg, etc.). According to go-fuzz project manual we could just build fuzz target from go-fuzz-corpus repository, but let's just borrow fuzz targets and pretend that we write them from scratch.

Okay, let's write fuzz target for webp decoder. First, I clone golang/image repository and create fuzz.go file there with the following contents:

package image

import (
	"bytes"
	"golang.org/x/image/webp"
)

func FuzzWebp(data []byte) int {
    cfg, err := webp.DecodeConfig(bytes.NewReader(data))
    if err != nil {
       return 0
    }
    if cfg.Width*cfg.Height > 4000000 {
       return 0
    }
    if _, err := webp.Decode(bytes.NewReader(data)); err != nil {
       return 0
    }
    return 1
}

I slightly modified the fuzz target using image-rs webp target:

if cfg.Width*cfg.Height > 4000000 { // originally 1e6

To build fuzz target we can use just use go-fuzz-build with -libfuzzer option:

go-fuzz-build -libfuzzer -func=FuzzWebp -o webp.a
clang -fsanitize=fuzzer webp.a -o fuzz_webp

Clone this wiki locally