advanced
Go Targets with LibFuzzer Instrumentation via Go-Fuzz¶
Need a Go target with libFuzzer instrumentation? In this lesson, we'll walk through how to compile Go targets with libFuzzer instrumentation using Go-Fuzz!
Estimated Time: 15 minutes
By the end of this lesson, you will be able to:
- Compile and fuzz a Go target with libFuzzer instrumentation via go-fuzz for an reachable assertion defect.
- Compile and fuzz a Go target with libFuzzer instrumentation via go-fuzz for an index-out-of-bounds defect.
Run through the lesson:
See prerequisites before beginning.
-
Download the go-go-fuzz.tgz and build the
go-go-fuzz
Docker image, and push it to the specified Docker registry:docker build -f Dockerfile -t <DOCKERHUB_USERNAME>/go-go-fuzz . docker push <DOCKERHUB_USERNAME>/go-go-fuzz
docker build -f Dockerfile -t $MAYHEM_DOCKER_REGISTRY/forallsecure/go-go-fuzz . docker push $MAYHEM_DOCKER_REGISTRY/forallsecure/go-go-fuzz
-
Execute a Mayhem run on the
go-go-fuzz
Docker image using either the Mayhem UI or Mayhem CLI with the following Mayhemfile:1 2 3 4 5
image: <DOCKERHUB_USERNAME>/go-go-fuzz:latest project: mayhem-examples target: go-go-fuzz cmds: - cmd: /go/mayhemit.libfuzzer
1 2 3 4 5
image: $MAYHEM_DOCKER_REGISTRY/forallsecure/go-go-fuzz:latest project: mayhem-examples target: go-go-fuzz cmds: - cmd: /go/mayhemit.libfuzzer
You will need the following:
- Docker installed.
- A valid Internet connection (for pulling Docker Hub base images)
One Click Testing¶
Click on the following button and hit Start Run at the end of the Create New Run flow to get a quick start on testing a Go target instrumented with go-fuzz! No need to configure anything, as the underlying Mayhemfile
has already been configured for you!
Once the Mayhem run initiates, you should see a Run page similar to the following:
Awesome! Now that you've seen Mayhem testing a libFuzzer instrumented Go target, let's now walk through how to compile and fuzz the go-go-fuzz
target that you just executed a Mayhem run for!
Compiling and Testing a Go Target with LibFuzzer Instrumentation via Go-Fuzz¶
File: go-go-fuzz.tgz
Download and extract the above go-go-fuzz.tgz
and take a look at the following bugged mayhemit.go
program.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
|
Here we see that there are two functions of interest: Fuzz
and mayhemit
. The Fuzz
function serves as the entrypoint for the go-fuzz
fuzzer and invokes the mayhemit
function on line 18 to check if the input test case reads "bug". If so, the program crashes via a reachable assertion error produced by the panic()
function on line 9.
Let's now see how this program will end up being compiled:
1 2 3 4 5 6 7 8 |
|
- Line 1: The
fuzzers/go-fuzz:1.2.0
base image is set as the base environment for the Docker container, providing access togo-fuzz
and its dependencies. - Line 2: The
mayhemit.go
source code is copied over into the Docker container. - Line 3: The
go-fuzz-build
compiler is used to compile themayhemit
executable. In this particular case, thego-fuzz-build
compiler outputs a libFuzzer archive file that can then be used with libFuzzer. - Line 8: The executable
/go/mayhemit.libfuzzer
is set as the default executable for the resulting Docker image.
Then, within the go-go-fuzz
folder, execute the following docker
commands to build and push the <DOCKERHUB_USERNAME>/go-go-fuzz
Docker image to the Docker Hub registry.
Then, within the go-go-fuzz
folder, execute the following docker
commands to build and push the forallsecure/go-go-fuzz
Docker image to the Mayhem Docker Registry.
docker build -f Dockerfile -t <DOCKERHUB_USERNAME>/go-go-fuzz .
docker push <DOCKERHUB_USERNAME>/go-go-fuzz
docker build -f Dockerfile -t $MAYHEM_DOCKER_REGISTRY/forallsecure/go-go-fuzz .
docker push $MAYHEM_DOCKER_REGISTRY/forallsecure/go-go-fuzz
Info
You can use the mayhem login
command to find your internal Mayhem Docker Registry URL and run the following command to set the DOCKER_REGISTRY
environment variable, like so:
export DOCKER_REGISTRY=tutorial.forallsecure.com:5000
DOCKER_REGISTRY
environment variable for your specific Mayhem Docker Registry URL.
Once the Docker image is successfully pushed, navigate to the Mayhem UI and select Docker Hub as the source to your new Mayhem run. Search for the <DOCKERHUB_USERNAME>/go-go-fuzz
Docker image you just uploaded and confirm the Mayhemfile
looks similar to the following:
Once the Docker image is successfully pushed, navigate to the Mayhem UI and select the Mayhem Docker Registry as the source to your new Mayhem run. Search for the forallsecure/go-go-fuzz
Docker image you just uploaded and confirm the Mayhemfile
looks similar to the following:
1 2 3 4 5 |
|
1 2 3 4 5 |
|
Then just click Next to the end of the Create New Run flow and hit the Click Start button to begin testing your new Go target! You should see a Run page similar to the following:
Congratulations! You just fuzzed a Go target with go-fuzz instrumentation!
⚡ Real World Exercise: Building and Testing the mayhemit-out-of-bounds
LibFuzzer Go Target via Go-Fuzz¶
Now that you know how to build and test a Go target with libFuzzer instrumentation using go-fuzz, let's see if you can modify the source code to use an index out-of-bounds error instead of a reachable assertion defect!
Files: mayhemit-out-of-bounds-unsolved.zip
Instructions:
-
Modify the
mayhemit.go
source code and add the array out-of-bounds defect:1 2 3 4 5 6 7 8 9 10 11 12 13 14
func mayhemit(bytes []byte) int { content := string(bytes) if len(content) >= 3 && len(content) < 5 { if string(content[0]) == "b" { if string(content[1]) == "u" { if string(content[2]) == "g" { var x = content[10] fmt.Println(x) } } } } return 0 }
-
Rebuild the Dockerfile using the
docker build
command and tag the resulting Docker image as<DOCKERHUB_USERNAME>/go-go-fuzz-mayhemit-out-of-bounds
. - Push the
<DOCKERHUB_USERNAME>/go-go-fuzz-mayhemit-out-of-bounds
Docker image to the public Docker Hub registry using thedocker push
command. - Fuzz the
<DOCKERHUB_USERNAME>/go-go-fuzz-mayhemit-out-of-bounds
Docker image using either the Mayhem UI or Mayhem CLI. Make sure to set the associatedMayhemfile
accordingly.
- Rebuild the Dockerfile using the
docker build
command and tag the resulting Docker image as$MAYHEM_DOCKER_REGISTRY/go-go-fuzz-mayhemit-out-of-bounds
. - Push the
$MAYHEM_DOCKER_REGISTRY/go-go-fuzz-mayhemit-out-of-bounds
Docker image to the private Mayhem Docker registry using thedocker push
command. - Test the
$MAYHEM_DOCKER_REGISTRY/go-go-fuzz-mayhemit-out-of-bounds
Docker image using either the Mayhem UI or Mayhem CLI. Make sure to set the associatedMayhemfile
accordingly.
🔍 Review It! Building and Testing the mayhemit-out-of-bounds
LibFuzzer Go Target via Go-Fuzz¶
Solution
Solution: mayhemit-out-of-bounds-solved.zip
First things first, you needed to add the max length constraint len(content) < 5
and the erroneous call for content[10]
so that when the mayhemit
function is fuzzed, the input test case "bug" will trigger the index out-of-bounds error.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
|
Then, you needed to run the docker build
command in the same directory as the Dockerfile
and simultaneously tag the resulting Docker image as <DOCKERHUB_USERNAME>/go-go-fuzz-mayhemit-out-of-bounds
.
Then, you needed to run the docker build
command in the same directory as the Dockerfile
and simultaneously tag the resulting Docker image as $MAYHEM_DOCKER_REGISTRY/go-go-fuzz-mayhemit-out-of-bounds
.
docker build -f Dockerfile -t <DOCKERHUB_USERNAME>/go-go-fuzz-mayhemit-out-of-bounds .
docker build -f Dockerfile -t $MAYHEM_DOCKER_REGISTRY/go-go-fuzz-mayhemit-out-of-bounds .
Next, you had to tag and push the <DOCKERHUB_USERNAME>/go-go-fuzz-mayhemit-out-of-bounds
Docker image to the public Docker Hub registry.
Next, you had to tag and push the $MAYHEM_DOCKER_REGISTRY/go-go-fuzz-mayhemit-out-of-bounds
Docker image to the private Mayhem Docker registry.
docker push <DOCKERHUB_USERNAME>/tutorial/go-go-fuzz-mayhemit-out-of-bounds
docker push $MAYHEM_DOCKER_REGISTRY/go-go-fuzz-mayhemit-out-of-bounds
Note
Here we uploaded the go-go-fuzz-mayhemit-out-of-bounds
Docker image to our tutorial.forallsecure.com
Mayhem deployment, specifically at the internal Docker registry located at port 5000
. For your Docker image to have successfully uploaded, you would have had to adjust the URL for your Mayhem deployment Docker registry accordingly.
Alternatively, you could have also used the included Makefile
to easily build and push the resulting Docker image by setting a MAYHEM_DOCKER_REGISTRY
environment variable and running the following commands:
make build
make push
Lastly, you needed to execute a Mayhem run on the uploaded <DOCKERHUB_USERNAME>/go-go-fuzz-mayhemit-out-of-bounds
Docker image using either the Mayhem UI or Mayhem CLI. As long as your Mayhemfile
looked similar to the following:
Lastly, you needed to execute a Mayhem run on the uploaded $MAYHEM_DOCKER_REGISTRY/go-go-fuzz-mayhemit-out-of-bounds
Docker image using either the Mayhem UI or Mayhem CLI. As long as your Mayhemfile
looked similar to the following:
1 2 3 4 5 6 7 |
|
1 2 3 4 5 6 7 |
|
Your final Run page should have looked like the following:
Congratulations! Mayhem found the index out-of-bounds defect that you added! You just built a libFuzzer instrumented Go target using go-fuzz and added a bug that was detected in Mayhem!
✏️ Summary and Recap¶
In this lesson, you learned how to compile libFuzzer instrumented Go targets with go-fuzz and fuzz them in Mayhem!
I learned how to...
1. Compile and test a Go target with libFuzzer instrumentation via go-fuzz for a reachable assertion defect.
-
The source code should contain the following defect:
1 2 3 4 5 6 7 8 9 10 11 12 13
func mayhemit(bytes []byte) int { content := string(bytes) if len(content) >= 3 { if string(content[0]) == "b" { if string(content[1]) == "u" { if string(content[2]) == "g" { panic("found a bug!") } } } } return 0 }
-
Then, to fuzz the libFuzzer Go target, use the following
Dockerfile
andMayhemfile
to build the Docker image containing the Go executable and fuzz it in Mayhem, respectively:1 2 3 4 5 6 7 8
FROM fuzzers/go-fuzz:1.2.0 COPY mayhemit.go . RUN go-fuzz-build -libfuzzer -o mayhemit.a && \ clang -fsanitize=fuzzer mayhemit.a -o mayhemit.libfuzzer # Set to fuzz! ENTRYPOINT [] CMD ["/go/mayhemit.libfuzzer"]
1 2 3 4 5
image: <DOCKERHUB_USERNAME>/go-go-fuzz:latest project: mayhem-examples target: go-go-fuzz cmds: - cmd: /go/mayhemit.libfuzzer
1 2 3 4 5
image: $MAYHEM_DOCKER_REGISTRY/forallsecure/go-go-fuzz:latest project: mayhem-examples target: go-go-fuzz cmds: - cmd: /go/mayhemit.libfuzzer
2. Compile and fuzz a Go target with libFuzzer instrumentation via go-fuzz for an index-out-of-bounds defect.
-
The source code should contain the following defect:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
func mayhemit(bytes []byte) int { content := string(bytes) if len(content) >= 3 && len(content) < 5 { if string(content[0]) == "b" { if string(content[1]) == "u" { if string(content[2]) == "g" { var x = content[10] fmt.Println(x) } } } } return 0 }
-
Then, to fuzz the libFuzzer Go target, use the following
Dockerfile
andMayhemfile
to build the Docker image containing the Go executable and fuzz it in Mayhem, respectively:1 2 3 4 5 6 7 8
FROM fuzzers/go-fuzz:1.2.0 COPY mayhemit.go . RUN go-fuzz-build -libfuzzer -o mayhemit.a && \ clang -fsanitize=fuzzer mayhemit.a -o mayhemit.libfuzzer # Set to fuzz! ENTRYPOINT [] CMD ["/go/mayhemit.libfuzzer"]
1 2 3 4 5 6 7
image: <DOCKERHUB_USERNAME>/go-go-fuzz-mayhemit-out-of-bounds:latest duration: 90 project: mayhem-examples target: go-go-fuzz-mayhemit-out-of-bounds cmds: - cmd: /go/mayhemit.libfuzzer libfuzzer: true
1 2 3 4 5 6 7
image: $MAYHEM_DOCKER_REGISTRY/go-go-fuzz-mayhemit-out-of-bounds:latest duration: 90 project: mayhem-examples target: go-go-fuzz-mayhemit-out-of-bounds cmds: - cmd: /go/mayhemit.libfuzzer libfuzzer: true