コンテンツにスキップ

advanced

Base-Executable Rust Targets

rust-logo

Need to test an uninstrumented or base-executable Rust target? We'll walk you through how to test base-executable Rust targets in Mayhem!

Estimated Time: 15 minutes

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

  1. Build and fuzz a base-executable Rust target with an improper input validation defect.
  2. Build and fuzz a base-executable Rust target with an index out-of-bounds defect.

Run through the lesson:

See prerequisites before beginning.

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

    docker build -t <DOCKERHUB_USERNAME>/rust-base-executable .
    docker push <DOCKERHUB_USERNAME>/rust-base-executable
    
    docker build -t $MAYHEM_DOCKER_REGISTRY/forallsecure/rust-base-executable .
    docker push $MAYHEM_DOCKER_REGISTRY/forallsecure/rust-base-executable
    
  2. Execute a Mayhem run on the rust-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>/rust-base-executable:latest
    duration: 90
    project: mayhem-examples
    target: rust-base-executable
    cmds:
      - cmd: /mayhemit @@
    
    1
    2
    3
    4
    5
    6
    image: $MAYHEM_DOCKER_REGISTRY/forallsecure/rust-base-executable:latest
    duration: 90
    project: mayhem-examples
    target: rust-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 button below to start testing a base-executable Rust target! Click Next until you reach the final confirmation page and then hit Start Run!

You should see a Run page similar to the following:

rust-base-executable-run

Now that you've seen Mayhem testing a base-executable Rust target, let's walk through end-to-end how the Rust target was built!

Testing a Base-Executable Rust Target

File: rust-base-executable.tgz

Download and extract the above rust-base-executable.tgz and take a look at the following bugged mayhemit.rs 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
use std::env;
use std::fs::File;
use std::io;
use std::io::prelude::*;
use std::process;

fn main() -> io::Result<()> {
    let args: Vec<String> = env::args().collect();
    let filename = &args[1];

    let mut f = File::open(filename)?;
    let mut buffer = [0; 10];

    // read up to 10 bytes
    f.read(&mut buffer)?;
    mayhemit(&buffer);
    Ok(())
}

fn mayhemit(data: &[u8]) {
    if data[0] == 'b' as u8 {
        if data[1] == 'u' as u8 {
            if data[2] == 'g' as u8 {
                process::abort();
            }
        }
    }
}

Here we see that various standard Rust modules have been imported into the program at the top of source code, and that there are two main functions: main and mayhemit.

The main function handles file inputs and reads up to the first 10 bytes of its contents, which is then parsed by the mayhemit function to determine if an input test case "bug" has been inserted into the program. If a test case "bug" is present, then the improper input validation defect is initialized via the abort() function.

Let's now take a look at how the rust-base-executable target will be built. Looking at the associated Dockerfile we can see the following:

1
2
3
4
5
6
7
FROM rust:1.44-buster as rust-target
COPY mayhemit.rs .
RUN rustc -o /mayhemit mayhemit.rs

# Set to fuzz!
ENTRYPOINT []
CMD ["/mayhemit", "@@"]
  • Line 1: The rust:1.44-buster base image is imported to gather the necessary Rust dependencies.
  • Line 2: The mayhemit.rs source file is copied into the Docker container.
  • Line 3: The rustc compiler compiles the mayhemit.rs source code into the mayhemit Rust executable.
  • Line 7: The /mayhemit @@ executable is defined as the default executable for the resulting Docker image.

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

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

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

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
Here, we've provided an example Mayhem Docker registry URL, but you will need to set the DOCKER_REGISTRY environment variable for your specific Mayhem Docker Registry URL.

Upon successfully pushing the newly created Docker image to the public Docker Hub registry, create a new run via the Mayhem UI and search for the <DOCKERHUB_USERNAME>/rust-base-executable 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/rust-base-executable Docker image. Confirm that your Mayhemfile looks similar to the following:

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

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:

rust-base-executable-run

Congratulations! You just tested a base-executable Rust target with Mayhem!

Real World Exercise: Building and Testing the mayhemit-out-of-bounds Base-Executable Rust Target

Now that you know how to build and test a base-executable Rust target with a improper input validation defect, let's see if you can modify the source code to use an index out-of-bounds defect instead.

Files: mayhemit-out-of-bounds-unsolved.zip

  • Modify the mayhemit.rs source code and add the index out-of-bounds defect:

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    fn mayhemit(data: &[u8]) {
        if data[0] == 'b' as u8 {
            if data[1] == 'u' as u8 {
                if data[2] == 'g' as u8 {
                    println!("made it!");
                    let x;
                    x = data[10];
                }
            }
        }
    }
    
  • Rebuild the Dockerfile using the docker build command and tag the resulting Docker image as <DOCKERHUB_USERNAME>/rust-base-executable/mayhemit-out-of-bounds.

  • Push the <DOCKERHUB_USERNAME>/rust-base-executable/mayhemit-out-of-bounds Docker image to the Docker Hub registry using the docker push command.
  • Fuzz the <DOCKERHUB_USERNAME>/rust-base-executable/mayhemit-out-of-bounds Docker image using either the Mayhem UI or Mayhem CLI. Make sure to set the associated Mayhemfile accordingly.
  • Rebuild the Dockerfile using the docker build command and tag the resulting Docker image as $MAYHEM_DOCKER_REGISTRY/rust-base-executable/mayhemit-out-of-bounds.
  • Push the $MAYHEM_DOCKER_REGISTRY/rust-base-executable/mayhemit-out-of-bounds Docker image to the private Mayhem Docker registry using the docker push command.
  • Test the $MAYHEM_DOCKER_REGISTRY/rust-base-executable/mayhemit-out-of-bounds Docker image using either the Mayhem UI or Mayhem CLI. Make sure to set the associated Mayhemfile accordingly.

🔍 Review It! Building and Testing the mayhemit-out-of-bounds Base-Executable Rust Target

Solution

Solution: mayhemit-out-of-bounds-solved.zip

First things first, you needed to set the max length constraint [0; 3] and add the erroneous call for data[10] so that when the mayhemit function is used to parse the fuzz input, 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
26
27
28
29
30
use std::env;
use std::fs::File;
use std::io;
use std::println;
use std::io::prelude::*;


fn main() -> io::Result<()> {
    let args: Vec<String> = env::args().collect();
    let filename = &args[1];

    let mut f = File::open(filename)?;
    let mut buffer = [0; 3];

    f.read(&mut buffer)?;
    mayhemit(&buffer);
    Ok(())
}

fn mayhemit(data: &[u8]) {
    if data[0] == 'b' as u8 {
        if data[1] == 'u' as u8 {
            if data[2] == 'g' as u8 {
                println!("made it!");
                let x;
                x = data[10];
            }
        }
    }
}

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>/rust-base-executable-mayhemit-out-of-bounds:

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 $MAYHEM_DOCKER_REGISTRY/rust-base-executable/mayhemit-out-of-bounds:

docker build -f Dockerfile -t <DOCKERHUB_USERNAME>/rust-base-executable-mayhemit-out-of-bounds .
docker build -f Dockerfile -t $MAYHEM_DOCKER_REGISTRY/rust-base-executable/mayhemit-out-of-bounds .

Next, you had to push the <DOCKERHUB_USERNAME>/rust-base-executable-mayhemit-out-of-bounds Docker image to the public Docker Hub registry:

Next, you had to push the $MAYHEM_DOCKER_REGISTRY/rust-base-executable/mayhemit-out-of-bounds Docker image to the private Mayhem Docker registry:

docker push <DOCKERHUB_USERNAME>/rust-base-executable-mayhemit-out-of-bounds
docker push $MAYHEM_DOCKER_REGISTRY/rust-base-executable/mayhemit-out-of-bounds

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 could have executed a Mayhem run on the uploaded <DOCKERHUB_USERNAME>/rust-base-executable-mayhemit-out-of-bounds Docker image using either the Mayhem UIMayhem UI or Mayhem CLI. As long as your Mayhemfile looked similar to the following:

Lastly, you could have executed a Mayhem run on the uploaded $MAYHEM_DOCKER_REGISTRY/rust-base-executable/mayhemit-out-of-bounds Docker image using either the Mayhem UIMayhem UI or Mayhem CLI. As long as your Mayhemfile looked similar to the following:

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

Your final Run page should have looked like the following:

mayhemit-out-of-bounds-run

Congratulations! Mayhem found the index out-of-bounds defect! You just built a base-executable Rust target from scratch and used Mayhem to detect the bug that you added!

✏️ Summary and Recap

In this lesson, you learned how to fuzz base-executable Rust targets in Mayhem!


I learned how to...

1. Build and test a base-executable Rust target for an improper input validation defect.
  • The source code should contain the following defect:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    fn mayhemit(data: &[u8]) {
        if data[0] == 'b' as u8 {
            if data[1] == 'u' as u8 {
                if data[2] == 'g' as u8 {
                    process::abort();
                }
            }
        }
    }
    

  • Then, to fuzz the Rust base-executable target, use the following Dockerfile to build the Docker image containing the Rust program:

    1
    2
    3
    4
    5
    6
    7
    FROM rust:1.44-buster as rust-target
    COPY mayhemit.rs .
    RUN rustc -o /mayhemit mayhemit.rs
    
    # Set to fuzz!
    ENTRYPOINT []
    CMD ["/mayhemit", "@@"]
    

    1
    2
    3
    4
    5
    6
    image: <DOCKERHUB_USERNAME>/rust-base-executable:latest
    duration: 90
    project: mayhem-examples
    target: rust-base-executable
    cmds:
      - cmd: /mayhemit @@
    
    1
    2
    3
    4
    5
    6
    image: $MAYHEM_DOCKER_REGISTRY/forallsecure/rust-base-executable:latest
    duration: 90
    project: mayhem-examples
    target: rust-base-executable
    cmds:
      - cmd: /mayhemit @@
    
2. Build and fuzz a base-executable Rust target with an out-of-bounds defect.
  • The source code should contain the following defect:

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    fn mayhemit(data: &[u8]) {
        if data[0] == 'b' as u8 {
            if data[1] == 'u' as u8 {
                if data[2] == 'g' as u8 {
                    println!("made it!");
                    let x;
                    x = data[10];
                }
            }
        }
    }
    

  • Then, to fuzz the base-executable Rust target, use the following Dockerfile to build the Docker image containing the Rust program:

    1
    2
    3
    4
    5
    6
    7
    FROM rust:1.44-buster as rust-target
    COPY mayhemit.rs .
    RUN rustc -o /mayhemit mayhemit.rs
    
    # Set to fuzz!
    ENTRYPOINT []
    CMD ["/mayhemit", "@@"]
    

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