advanced
C/C++ Targets Instrumented with Honggfuzz¶
Need to compile a C/C++ target with honggfuzz instrumentation? In this lesson, we'll walk you through how to compile C/C++ honggfuzz targets and test them in Mayhem.
Estimated Time: 15 minutes
By the end of this lesson, you will be able to:
- Compile and fuzz a C honggfuzz target with an improper input validation defect.
- Compile and fuzz a C++ honggfuzz target with an improper input validation defect.
Run through the lesson:
See prerequisites before beginning.
-
Download the c-honggfuzz-gcc.tgz and build the
c-honggfuzz-gcc
Docker image, and push it to the specified Docker registry:docker build -f Dockerfile -t <DOCKERHUB_USERNAME>/c-honggfuzz-gcc . docker push <DOCKERHUB_USERNAME>/c-honggfuzz-gcc
docker build -f Dockerfile -t $MAYHEM_DOCKER_REGISTRY/forallsecure/c-honggfuzz-gcc . docker push $MAYHEM_DOCKER_REGISTRY/forallsecure/c-honggfuzz-gcc
-
Execute a Mayhem run on the
forallsecure/c-honggfuzz-gcc
Docker image using either the Mayhem UI or Mayhem CLI with the following Mayhemfile:1 2 3 4 5 6 7
image: <DOCKERHUB_USERNAME>/c-honggfuzz-gcc:latest duration: 90 project: mayhem-examples target: c-honggfuzz-gcc cmds: - cmd: /mayhemit honggfuzz: true
1 2 3 4 5 6 7
image: $MAYHEM_DOCKER_REGISTRY/forallsecure/c-honggfuzz-gcc:latest duration: 90 project: mayhem-examples target: c-honggfuzz-gcc cmds: - cmd: /mayhemit honggfuzz: true
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 C target with honggfuzz instrumentation! 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 can fuzz a C target instrumented with honggfuzz, let's now walk through how to compile and test the C-honggfuzz target that you just executed a Mayhem run for!
Compiling and Testing a C Target with Honggfuzz Instrumentation¶
File: c-honggfuzz-gcc.tgz
Download and extract the above c-honggfuzz-gcc.tgz
and take a look at the following source code for mayhemit.c
:
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 26 |
|
Here you'll notice that instead of a typical main
function, the source code utilizes the HF_ITER
function instead to accept an array of bytes that will be used to fuzz the target function, mayhemit
. If the input is then found to spell out the word "bug", the program crashes due to an improper input validation error.
Note
There are two types of fuzzer entrypoints when using honggfuzz: ASAN-style (LLVMFuzzerTestOneInput) or HF_ITER style. Check out the documentation on honggfuzz persistent fuzzing for more information.
Taking a look at the corresponding Dockerfile
shows us the process for compiling our c-honggfuzz-gcc
target:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
|
- Line 1: The
fuzzers/honggfuzz:1.9
base image is imported to provide the necessary honggfuzz dependencies. - Line 2: The
mayhemit.c
source file is copied over into the Docker container. - Line 3: The
hfuzz-gcc
C compiler is to used to compile our C target with honggfuzz instrumentation. - Line 5: The
debian:buster-slim
base image is imported and the compiledmayhemit
binary along with thehonggfuzz
fuzzer (and its associated dependencies) are brought over from the previous build stage. - Line 17: The
/mayhemit
executable is set as the default executable for the Docker container.
Note
On lines 5-13, this is what's known as a multi-stage build and is done to optimize or slim down the size of the resulting Docker image. In addition, the honggfuzz driver must be the same version as the honggfuzz compiled binary. Therefore, by bringing over the honggfuzz
executable from the previous build stage, we ensure that the same version of honggfuzz is used as the one that compiled the binary.
Next, we need to build the resulting <DOCKERHUB_USERNAME>/c-honggfuzz-gcc
Docker image and push it to the Docker Hub registry:
Next, we need to build the resulting forallsecure/c-honggfuzz-gcc
Docker image and push it to the Mayhem Docker registry:
docker build -f Dockerfile -t <DOCKERHUB_USERNAME>/c-honggfuzz-gcc .
docker push <DOCKERHUB_USERNAME>/c-honggfuzz-gcc
docker build -f Dockerfile -t $MAYHEM_DOCKER_REGISTRY/forallsecure/c-honggfuzz-gcc .
docker push $MAYHEM_DOCKER_REGISTRY/forallsecure/c-honggfuzz-gcc
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.
Upon successfully pushing the newly created Docker image to the Docker Hub registry, create a new run via the Mayhem UI and search for the <DOCKERHUB_USERNAME>/c-honggfuzz-gcc
Docker image. Confirm that your Mayhemfile
looks similar to the following:
Upon successfully pushing the newly created Docker image to the private Mayhem Docker Registry, create a new run via the Mayhem UI and search for the forallsecure/c-honggfuzz-gcc
Docker image. Confirm that your Mayhemfile
looks similar to the following:
1 2 3 4 5 6 7 |
|
1 2 3 4 5 6 7 |
|
Now just click Next until you reach the final confirmation page of the create new run flow and hit Start Run to execute your Mayhem run! You should see a Run page similar to the following:
Congratulations! You just tested a C honggfuzz target with Mayhem!
⚡ Real World Exercise: Compiling and Testing a C++ Target with Honggfuzz Instrumentation¶
Now that you're familiar with the steps for compiling and testing a C target with honggfuzz instrumentation, let's see if you can do the same for a C++ target!
Files cpp-honggfuzz-gcc.tgz
Instructions:
- Use the
Dockerfile
and thedocker build
command and tag the resulting Docker image as<DOCKERHUB_USERNAME>/cpp-honggfuzz-gcc
. - Push the
<DOCKERHUB_USERNAME>/cpp-honggfuzz-gcc
Docker image to the Docker Hub registry using thedocker tag
anddocker push
commands. -
Fuzz the
<DOCKERHUB_USERNAME>/cpp-honggfuzz-gcc
Docker image using either the Mayhem UI or Mayhem CLI. Make sure to set the associatedMayhemfile
accordingly. -
Use the
Dockerfile
and thedocker build
command and tag the resulting Docker image asforallsecure/cpp-honggfuzz-gcc
. - Push the
forallsecure/cpp-honggfuzz-gcc
Docker image to the internal Mayhem Docker registry using thedocker tag
anddocker push
commands. - Test the
forallsecure/cpp-honggfuzz-gcc
Docker image using either the Mayhem UI or Mayhem CLI. Make sure to set the associatedMayhemfile
accordingly.
🔍 Review It! Compiling and Testing a C++ Target with Honggfuzz Instrumentation¶
Solution
First things first, let's take a look at the mayhemit.cpp
source code:
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 26 |
|
One difference you may have noticed when comparing against the source code of the c-honggfuzz-gcc
target is the use of the extern "C"
keyword. The extern "C"
keyword makes a function-name in C++ have C linkage so that client C code can link to (use) your function using a C compatible header file that contains just the declaration of your function.
Next up, let's take a look at the associated Dockerfile
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
|
Here we see that on line 1 we import the fuzzers/honggfuzz:1.9
base image as we've done before and now instead use the hfuzz-g++
compiler on line 3 to compile our C++ target with Honggfuzz instrumentation. Then, on line 5 and onward, the compiled mayhemit
binary and honggfuzz
fuzzer (with it's associated dependencies) are brought over to the next stage build under the debian:buster-slim
base image. Thereby making this Dockerfile
a multi-stage build to optimize disk space of the resulting Docker image.
Then, you needed to run the docker build
command in the same directory as the Dockerfile
and proceed to tag the resulting Docker image as <DOCKERHUB_USERNAME>/cpp-honggfuzz-gcc
:
Then, you needed to run the docker build
command in the same directory as the Dockerfile
and proceed to tag the resulting Docker image as forallsecure/cpp-honggfuzz-gcc
:
docker build -f Dockerfile -t <DOCKERHUB_USERNAME>/cpp-honggfuzz-gcc .
docker build -f Dockerfile -t $MAYHEM_DOCKER_REGISTRY/forallsecure/cpp-honggfuzz-gcc .
Next, you had to push the <DOCKERHUB_USERNAME>/cpp-honggfuzz-gcc
Docker image to the Docker Hub registry:
Next, you had to push the forallsecure/cpp-honggfuzz-gcc
Docker image to the private Mayhem Docker registry:
docker push <DOCKERHUB_USERNAME>/cpp-honggfuzz-gcc
docker push $MAYHEM_DOCKER_REGISTRY/forallsecure/cpp-honggfuzz-gcc
Lastly, you needed to execute a Mayhem run on the uploaded <DOCKERHUB_USERNAME>/cpp-honggfuzz-gcc
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 forallsecure/cpp-honggfuzz-gcc
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 |
|
After initiating the Mayhem run, you should have seen a Run page similar to the following:
Congratulations! Mayhem found the improper input validation defect! You just built a honggfuzz C++ target from scratch and used Mayhem to detect the bug!
✏️ Summary and Recap¶
In this lesson, you learned how to compile C/C++ targets with Honggfuzz instrumentation and fuzz them in Mayhem!
I learned how to...
1. Compile and test a C honggfuzz target with an improper input validation defect.
-
The source code should contain the following defect:
1 2 3 4 5 6 7 8 9 10
int mayhemit(char *buf, unsigned len) { if(len >= 3) if(buf[0] == 'b') if(buf[1] == 'u') if(buf[2] == 'g') { abort(); // Defect: SIGABRT. } return 0; }
-
Then, to fuzz the C honggfuzz target, use the following
Dockerfile
andMayhemfile
to build the Docker image containing the C program and fuzz it in Mayhem, respectively:1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
FROM fuzzers/honggfuzz:1.9 COPY mayhemit.c . RUN hfuzz-gcc mayhemit.c -o /mayhemit FROM debian:buster-slim COPY --from=0 /mayhemit . COPY --from=0 /usr/local/bin/honggfuzz /usr/local/bin/honggfuzz COPY --from=0 /usr/lib/x86_64-linux-gnu/libunwind-ptrace.so.0 /usr/lib/x86_64-linux-gnu/libunwind-ptrace.so.0 COPY --from=0 /usr/lib/x86_64-linux-gnu/libunwind-x86_64.so.8 /usr/lib/x86_64-linux-gnu/libunwind-x86_64.so.8 COPY --from=0 /usr/lib/x86_64-linux-gnu/libbfd-2.31.1-system.so /usr/lib/x86_64-linux-gnu/libbfd-2.31.1-system.so COPY --from=0 /usr/lib/x86_64-linux-gnu/libopcodes-2.31.1-system.so /usr/lib/x86_64-linux-gnu/libopcodes-2.31.1-system.so COPY --from=0 /usr/lib/x86_64-linux-gnu/libunwind.so.8 /usr/lib/x86_64-linux-gnu/libunwind.so.8 RUN mkdir /testsuite && echo seed > /testsuite/seed # Set to fuzz! ENTRYPOINT ["honggfuzz", "-f", "/testsuite", "--"] CMD ["/mayhemit"]
1 2 3 4 5 6 7
image: <DOCKERHUB_USERNAME>/c-honggfuzz-gcc:latest duration: 90 project: mayhem-examples target: c-honggfuzz-gcc cmds: - cmd: /mayhemit honggfuzz: true
1 2 3 4 5 6 7
image: $MAYHEM_DOCKER_REGISTRY/forallsecure/c-honggfuzz-gcc:latest duration: 90 project: mayhem-examples target: c-honggfuzz-gcc cmds: - cmd: /mayhemit honggfuzz: true
2. Compile and fuzz a C++ honggfuzz target with an improper input validation defect.
-
The source code should contain the following defect:
1 2 3 4 5 6 7 8 9 10
int mayhemit(char *buf, unsigned len) { if(len >= 3) if(buf[0] == 'b') if(buf[1] == 'u') if(buf[2] == 'g') { abort(); // Defect: SIGABRT. } return 0; }
-
Then, to fuzz the C honggfuzz target, use the following
Dockerfile
andMayhemfile
to build the Docker image containing the C program and fuzz it in Mayhem, respectively:1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
FROM fuzzers/honggfuzz:1.9 COPY mayhemit.cpp . RUN hfuzz-g++ mayhemit.cpp -o /mayhemit FROM debian:buster-slim COPY --from=0 /mayhemit . COPY --from=0 /usr/local/bin/honggfuzz /usr/local/bin/honggfuzz COPY --from=0 /usr/lib/x86_64-linux-gnu/libunwind-ptrace.so.0 /usr/lib/x86_64-linux-gnu/libunwind-ptrace.so.0 COPY --from=0 /usr/lib/x86_64-linux-gnu/libunwind-x86_64.so.8 /usr/lib/x86_64-linux-gnu/libunwind-x86_64.so.8 COPY --from=0 /usr/lib/x86_64-linux-gnu/libbfd-2.31.1-system.so /usr/lib/x86_64-linux-gnu/libbfd-2.31.1-system.so COPY --from=0 /usr/lib/x86_64-linux-gnu/libopcodes-2.31.1-system.so /usr/lib/x86_64-linux-gnu/libopcodes-2.31.1-system.so COPY --from=0 /usr/lib/x86_64-linux-gnu/libunwind.so.8 /usr/lib/x86_64-linux-gnu/libunwind.so.8 RUN mkdir /testsuite && echo seed > /testsuite/seed # Set to fuzz! ENTRYPOINT ["honggfuzz", "-f", "/testsuite", "--"] CMD ["/mayhemit"]
1 2 3 4 5 6 7
image: <DOCKERHUB_USERNAME>/cpp-honggfuzz-gcc:latest duration: 90 project: mayhem-examples target: cpp-honggfuzz-gcc cmds: - cmd: /mayhemit honggfuzz: true
1 2 3 4 5 6 7
image: $MAYHEM_DOCKER_REGISTRY/forallsecure/cpp-honggfuzz-gcc:latest duration: 90 project: mayhem-examples target: cpp-honggfuzz-gcc cmds: - cmd: /mayhemit honggfuzz: true