コンテンツにスキップ

advanced

Base-Executable C/C++ Targets

c-cpp-logo

Got an uninstrumented or base-executable C/C++ target? In this lesson, we'll walk you through how to test base-executable C/C++ targets in Mayhem.

Estimated Time: 15 minutes

By the end of this lesson, you will be able to:

  1. Compile and fuzz a base-executable C target with an improper input validation defect.
  2. Compile and fuzz a base-executable C++ target with an improper input validation defect.

Run through the lesson:

See prerequisites before beginning.

  1. Download the c-base-executable.tgz, build the c-base-executable Docker image, and push it to the specified Docker Registry:

    docker build -t <DOCKERHUB_USERNAME>/c-base-executable .
    docker push <DOCKERHUB_USERNAME>/c-base-executable
    
    docker build -t $MAYHEM_DOCKER_REGISTRY/forallsecure/c-base-executable .
    docker push $MAYHEM_DOCKER_REGISTRY/forallsecure/c-base-executable
    
  2. Execute a Mayhem run on the c-base-executable Docker image using either the Mayhem UI or Mayhem CLI with the following Mayhemfile:

    1
    2
    3
    4
    5
    6
    image: <DOCKERHUB_USERNAME>/c-base-executable:latest
    duration: 90
    project: mayhem-examples
    target: c-base-executable
    cmds:
      - cmd: /mayhemit @@
    
    1
    2
    3
    4
    5
    6
    image: $MAYHEM_DOCKER_REGISTRY/forallsecure/c-base-executable:latest
    duration: 90
    project: mayhem-examples
    target: c-base-executable
    cmds:
      - cmd: /mayhemit @@
    

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 base-executable C target! 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:

c-base-executable-run

Awesome! Now that you've seen Mayhem testing a base-executable C target, let's now walk through how to compile and test the c-base-executable target that you just executed a Mayhem run for!

Compiling and Testing a Base-Executable C Target

File: c-base-executable.tgz

Download and extract the above c-base-executable.tgz and take a look at the following bugged mayhemit.c program.

 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
27
28
29
30
31
32
33
34
35
36
#include <stdio.h>
#include <string.h>

int mayhemit(char *buf)
{
  if(strlen(buf) >= 3)
    if(buf[0] == 'b')
      if(buf[1] == 'u')
        if(buf[2] == 'g') {
          printf("You've got it!");
          abort(); // Defect: SIGABRT.
        }
  return 0;
}

int main(int argc, char *argv[])
{
  FILE *f;
  char buf[12];

  if(argc != 2){
    fprintf(stderr, "Must supply a text file\n");
    return -1;
  }
  f = fopen(argv[1], "r");
  if(f == NULL){
    fprintf(stderr, "Could not open %s\n", argv[1]);
    return -1;
  }
  if(fgets(buf, sizeof(buf), f) == NULL){
    fprintf(stderr, "Could not read from %s\n", argv[1]);
    return -1;
  }
  mayhemit(buf);
  return 0;
}

Here we see that the header files stdio.h and string.h have been included in the program on lines 1-2 and that there are two functions of interest: main and mayhemit.

Info

C programs use the stdio.h header file while C++ programs use the iostream header file. If you were to take a look at other C++ programs, their source code would typically use the iostream header file instead.

The main function handles file input, and invokes the mayhemit function if a file has been properly supplied to the program. The mayhemit function then parses the input file and returns an improper input validation error if the input test case supplied to the program reads "bug". Therefore, for this target, Mayhem should be able to fuzz this program and provide a crashing test case of "bug" to reveal the improper input validation defect.

Before we can fuzz the program, however, we'll need to compile the program and then subsequently upload the target to Mayhem for ingestion. For this first step, we advise using a Docker container that couples the target application with its program dependencies and ensures Mayhem can successfully execute and fuzz the C target.

Taking a look at the associated Dockerfile, we see the following operations:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
FROM debian:buster-slim as builder
RUN apt-get update && \
    apt-get install -y gcc make libc6-dbg && \
    rm -rf /var/lib/apt/lists/*
COPY mayhemit.c .
RUN gcc -o mayhemit -Wno-div-by-zero -fno-stack-protector -zexecstack -no-pie mayhemit.c

# Set to fuzz!
ENTRYPOINT []
CMD /mayhemit @@
  • Line 1: The debian:buster-slim image is imported as the base image for the new Docker container.
  • Lines 2-4: The necessary dependencies are downloaded and installed within the new Docker container.
  • Line 5: The mayhemit.c source code is copied over into the Docker container.
  • Line 6: The gcc C compiler is used to compile the mayhemit.c source code into the mayhemit executable.
  • Line 10: The /mayhemit @@ command is set as the default executable for the resulting Docker container.

Next, we need to actually build and push the resulting Docker image to the Docker Hub registry using the docker build and docker push commands.

Next, we need to actually build and push the resulting Docker image to the Mayhem server using the docker build and docker push commands, where $MAYHEM_DOCKER_REGISTRY represents an environment variable for the URL of the private Mayhem Docker registry.

Info

For example, we can set our $DOCKER_REGISTRY environment variable to tutorial.forallsecure.com:5000 by executing the following:

export DOCKER_REGISTRY=tutorial.forallsecure.com:5000

Within the c-base-executable directory, execute the following commands:

docker build -t <DOCKERHUB_USERNAME>/c-base-executable .
docker push <DOCKERHUB_USERNAME>/c-base-executable
docker build -t $MAYHEM_DOCKER_REGISTRY/forallsecure/c-base-executable .
docker push $MAYHEM_DOCKER_REGISTRY/forallsecure/c-base-executable

Upon successfully pushing the newly created Docker image to the public Docker Hub registry, create a new run via the Mayhem UI and select your uploaded <DOCKERHUB_USERNAME>/c-base-executable Docker image. Click Next through the create new run flow and verify that the Mayhemfile looks similar to the following before starting the run:

Upon successfully pushing the newly created Docker image to the private Mayhem Docker registry, create a new run via the Mayhem UI and select your uploaded forallsecure/c-base-executable Docker image. Click Next through the create new run flow and verify that the Mayhemfile looks similar to the following before starting the run:

1
2
3
4
5
6
image: <DOCKERHUB_USERNAME>/c-base-executable:latest
duration: 90
project: mayhem-examples
target: c-base-executable
cmds:
  - cmd: /mayhemit @@
1
2
3
4
5
6
image: $MAYHEM_DOCKER_REGISTRY/forallsecure/c-base-executable:latest
duration: 90
project: mayhem-examples
target: c-base-executable
cmds:
  - cmd: /mayhemit @@

You should now see that Mayhem was able to find the underlying improper input validation defect! Congratulations on compiling and testing your C target!

c-base-executable-run

Real World Exercise: Compiling and Testing a Base-Executable C++ Target

Now that you're familiar with the steps for compiling and testing a base-executable C target, let's see if you can do the same for a base-executable C++ target!

Files: cpp-base-executable.tgz

Instructions:

  • Download and extract the above cpp-base-executable.tgz file and use the docker build and docker push commands to build and push the resulting Docker image so that Mayhem can fuzz your <DOCKERHUB_USERNAME>/cpp-base-executable target.
  • Then, fuzz your newly uploaded <DOCKERHUB_USERNAME>/cpp-base-executable Docker image using the Mayhem UI!
  • Download and extract the above cpp-base-executable.tgz file and use the docker build and docker push commands to build and push the resulting Docker image so that Mayhem can fuzz your forallsecure/cpp-base-executable target.
  • Then, test your newly uploaded forallsecure/cpp-base-executable Docker image using the Mayhem UI!

🔍 Review It! Compiling and Testing a Base-Executable C++ Target

Solution

Okay let's take a look at how you did! First things first, let's inspect the source code for the mayhemit.cpp program:

 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
27
28
29
30
31
32
33
34
35
36
#include <iostream>
#include <string.h>

int mayhemit(char *buf)
{
  if(strlen(buf) >= 3)
    if(buf[0] == 'b')
      if(buf[1] == 'u')
        if(buf[2] == 'g') {
          printf("You've got it!");
          abort(); // Defect: SIGABRT.
        }
  return 0;
}

int main(int argc, char *argv[])
{
  FILE *f;
  char buf[12];

  if(argc != 2){
    fprintf(stderr, "Must supply a text file\n");
    return -1;
  }
  f = fopen(argv[1], "r");
  if(f == NULL){
    fprintf(stderr, "Could not open %s\n", argv[1]);
    return -1;
  }
  if(fgets(buf, sizeof(buf), f) == NULL){
    fprintf(stderr, "Could not read from %s\n", argv[1]);
    return -1;
  }
  mayhemit(buf);
  return 0;
}

Here we see that aside from the C++ iostream header file that has replaced the previous C stdio.h header file, the cpp-base-executable source code is nearly identical to the c-base-executable source code.

Next, let's inspect the associated Dockerfile. Here we see the following operations:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
FROM debian:buster-slim as builder
RUN apt-get update && \
    apt-get install -y gcc g++ make libc6-dbg && \
    rm -rf /var/lib/apt/lists/*
COPY mayhemit.cpp .
RUN g++ -Wno-div-by-zero -fno-stack-protector -zexecstack -no-pie -o mayhemit mayhemit.cpp

# Set to fuzz!
ENTRYPOINT []
CMD /mayhemit @@
  • Line 1: The debian:buster-slim image is imported as the base image for the new Docker container.
  • Lines 2-4: The necessary dependencies are downloaded and installed within the new Docker container.
  • Line 5: The mayhemit.cpp source code is copied over into the Docker container.
  • Line 6: The g++ C++ compiler is used to compile the mayhemit.cpp source code into the mayhemit executable.
  • Line 10: The /mayhemit @@ command is set as the default executable for the resulting Docker container.

Almost done! Next up, you needed to build and push the Docker image as we've already done before and run the containerized cpp-base-executable target in Mayhem!

docker build -t <DOCKERHUB_USERNAME>/cpp-base-executable .
docker push <DOCKERHUB_USERNAME>/cpp-base-executable
docker build -t $MAYHEM_DOCKER_REGISTRY/forallsecure/cpp-base-executable .
docker push $MAYHEM_DOCKER_REGISTRY/forallsecure/cpp-base-executable

Your underlying Mayhemfile for the run should have looked similar to the following:

1
2
3
4
5
6
image: <DOCKERHUB_USERNAME>/cpp-base-executable:latest
duration: 90
project: mayhem-examples
target: cpp-base-executable
cmds:
  - cmd: /mayhemit @@
1
2
3
4
5
6
image: $MAYHEM_DOCKER_REGISTRY/forallsecure/cpp-base-executable:latest
duration: 90
project: mayhem-examples
target: cpp-base-executable
cmds:
  - cmd: /mayhemit @@

And finally, you should have seen a run page similar to the following:

cpp-base-executable-run

If you were able to get the cpp-base-executable target tested, nice job! You're already building and testing C++ targets all on your own!

✏️ Summary and Recap

In this lesson, you learned how to compile and test base-executable C/C++ targets in Mayhem!


I learned how to...

1. Compile and test a base-executable C 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
    11
    int mayhemit(char *buf)
    {
      if(strlen(buf) >= 3)
        if(buf[0] == 'b')
          if(buf[1] == 'u')
            if(buf[2] == 'g') {
              printf("You've got it!");
              abort(); // Defect: SIGABRT.
            }
      return 0;
    }
    

  • Then, to fuzz the C base-executable target, use the following Dockerfile and Mayhemfile 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
    FROM debian:buster-slim as builder
    RUN apt-get update && \
        apt-get install -y gcc make libc6-dbg && \
        rm -rf /var/lib/apt/lists/*
    COPY mayhemit.c .
    RUN gcc -o mayhemit -Wno-div-by-zero -fno-stack-protector -zexecstack -no-pie mayhemit.c
    
    # Set to fuzz!
    ENTRYPOINT []
    CMD /mayhemit @@
    

    1
    2
    3
    4
    5
    6
    image: <DOCKERHUB_USERNAME>/c-base-executable:latest
    duration: 90
    project: mayhem-examples
    target: c-base-executable
    cmds:
      - cmd: /mayhemit @@
    
    1
    2
    3
    4
    5
    6
    image: $MAYHEM_DOCKER_REGISTRY/forallsecure/c-base-executable:latest
    duration: 90
    project: mayhem-examples
    target: c-base-executable
    cmds:
      - cmd: /mayhemit @@
    
2. Compile and fuzz a base-executable C++ 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
    11
    int mayhemit(char *buf)
    {
      if(strlen(buf) >= 3)
        if(buf[0] == 'b')
          if(buf[1] == 'u')
            if(buf[2] == 'g') {
              printf("You've got it!");
              abort(); // Defect: SIGABRT.
            }
      return 0;
    }
    

  • Then, to fuzz the C++ base-executable target, use the following Dockerfile and Mayhemfile 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
    FROM debian:buster-slim as builder
    RUN apt-get update && \
        apt-get install -y gcc g++ make libc6-dbg && \
        rm -rf /var/lib/apt/lists/*
    COPY mayhemit.cpp .
    RUN g++ -Wno-div-by-zero -fno-stack-protector -zexecstack -no-pie -o mayhemit mayhemit.cpp
    
    # Set to fuzz!
    ENTRYPOINT []
    CMD /mayhemit @@
    

    1
    2
    3
    4
    5
    6
    image: <DOCKERHUB_USERNAME>/cpp-base-executable:latest
    duration: 90
    project: mayhem-examples
    target: cpp-base-executable
    cmds:
      - cmd: /mayhemit @@
    
    1
    2
    3
    4
    5
    6
    image: $MAYHEM_DOCKER_REGISTRY/forallsecure/cpp-base-executable:latest
    duration: 90
    project: mayhem-examples
    target: cpp-base-executable
    cmds:
      - cmd: /mayhemit @@