Skip to content

advanced

Base-Executable Java Targets

java-logo

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

Estimated Time: 15 minutes

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

  1. Build and fuzz a base-executable Java target with an uncaught exception defect.
  2. Build and fuzz a base-executable Java target with an index out-of-bounds-defect.

Run through the lesson:

See prerequisites before beginning.

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

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

    1
    2
    3
    4
    5
    6
    7
    8
    image: <DOCKERHUB_USERNAME>/java-base-executable:latest
    duration: 120
    project: mayhem-examples
    target: java-base-executable
    cmds:
      - cmd: /usr/bin/MayhemIt.jar @@
        env:
          MFUZZ_JAVA: '1'
    
    1
    2
    3
    4
    5
    6
    7
    8
    image: $MAYHEM_DOCKER_REGISTRY/forallsecure/java-base-executable:latest
    duration: 120
    project: mayhem-examples
    target: java-base-executable
    cmds:
      - cmd: /usr/bin/MayhemIt.jar @@
        env:
          MFUZZ_JAVA: '1'
    

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 Java 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:

base-executable-java-target-run

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

Testing a Standalone Java Target

File: java-base-executable.tgz

Download and extract the above java-base-executable.tgz and take a look at the following bugged MayhemIt.java 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
package mayhemit;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.BufferedReader;
import java.io.FileReader;
import java.util.Scanner;

public class MayhemIt {
    public static void main(String[] args) {
        String input = "";

        try {
            File file = new File(args[0]);
            BufferedReader br = new BufferedReader(new FileReader(file));
            Scanner in = new Scanner(br);
            input = in.nextLine();
        } catch (FileNotFoundException e) {
            System.err.println("Could not find file");
            return;
        }

        if (input.length() >= 3) {
            if (input.charAt(0) == 'b') {
                if (input.charAt(1) == 'u') {
                    if (input.charAt(2) == 'g') {
                        throw new RuntimeException("Made it to the bug!");
                    }
                }
            }
        }
    }
}

Here we see that various java libraries have been imported to support the file handling in the main function, and if the input test case reads as "bug", the program crashes due to an uncaught exception defect.

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

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
FROM amazoncorretto:8
COPY MayhemIt.java .

# Build MayhemIt.jar
RUN mkdir -p build && \
    javac -d build MayhemIt.java && \
    cd build && \
    jar -cfe MayhemIt.jar mayhemit.MayhemIt * && \
    chmod u+x MayhemIt.jar && \
    mv MayhemIt.jar /usr/bin/MayhemIt.jar && \
    rm -rf build

# Set to fuzz!
ENTRYPOINT []
CMD [ "/usr/bin/MayhemIt.jar", "@@" ]
  1. Line 1: The amazoncorretto:8 base image is imported to gather the necessary java dependencies.
  2. Line 2: The MayhemIt.java source file is copied over into the Docker container.
  3. Lines 5-11: The MayhemIt.jar file is compiled using the javac compiler.
  4. Line 14: The executable /usr/bin/MayhemIt.jar is set as the default executable for the resulting Docker image.

Note

We should clarify that in order to execute the MayhemIt.jar in the container, we need to run java -jar /usr/bin/MayhemIt.jar to execute the jar file in a JVM; however, when executing a Mayhem run for the MayhemIt.jar file, we enable the MFUZZ_JAVA environment variable by setting the value to 1, which instructs Mayhem to execute the the jar file in Mayhem's JVM during the run. Therefore, it is not necessary to specify java -jar in the CMD invocation for a Mayhemfile.

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 -f Dockerfile -t <DOCKERHUB_USERNAME>/java-base-executable .
docker push <DOCKERHUB_USERNAME>/java-base-executable
docker build -f Dockerfile -t $MAYHEM_DOCKER_REGISTRY/forallsecure/java-base-executable .
docker push $MAYHEM_DOCKER_REGISTRY/forallsecure/java-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>/java-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/java-base-executable Docker image. Confirm that your Mayhemfile looks similar to the following:

1
2
3
4
5
6
7
8
image: <DOCKERHUB_USERNAME>/java-base-executable:latest
duration: 120
project: mayhem-examples
target: java-base-executable
cmds:
  - cmd: /usr/bin/MayhemIt.jar @@
    env:
      MFUZZ_JAVA: '1'
1
2
3
4
5
6
7
8
image: $MAYHEM_DOCKER_REGISTRY/forallsecure/java-base-executable:latest
duration: 120
project: mayhem-examples
target: java-base-executable
cmds:
  - cmd: /usr/bin/MayhemIt.jar @@
    env:
      MFUZZ_JAVA: '1'

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:

base-executable-java-target-run

Congratulations! You just fuzzed a base-executable Java target with Mayhem!

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

Now that you know how to build and test a Java target with an uncaught exception 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

Instructions:

  • Modify the MayhemIt.java source code to set a max length constraint and implement the corresponding index out-of-bounds defect:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    if (input.length() >= 3 && input.length() < 5) {
        if (input.charAt(0) == 'b') {
            if (input.charAt(1) == 'u') {
                if (input.charAt(2) == 'g') {
                    char x = input.charAt(10);
                }
            }
        }
    }
    
  • Rebuild the Dockerfile using the docker build command and tag the resulting Docker image as <DOCKERHUB_USERNAME>/java-base-executable-mayhemit-out-of-bounds.

  • Push the <DOCKERHUB_USERNAME>/java-base-executable-mayhemit-out-of-bounds Docker image to the public Docker Hub registry using the docker tag and docker push commands.
  • Fuzz the <DOCKERHUB_USERNAME>/java-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/java-base-executable-mayhemit-out-of-bounds.
  • Push the $MAYHEM_DOCKER_REGISTRY/java-base-executable-mayhemit-out-of-bounds Docker image to the private Mayhem Docker registry using the docker tag and docker push commands.
  • Test the $MAYHEM_DOCKER_REGISTRY/java-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 Java Target

Solution

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

First things first, you needed to add the max length constraint input.length() < 5 and the erroneous call for input.charAt(10) to the main function so that when the main function is fuzzed, the input test case "bug" will trigger the corresponding index out-of-bounds error.

Note

We set the condition input.length() >= 3 && input.length() < 5 in order to ensure that no additional out-of-bounds defects would arise. For example, if the condition was just set to input.length() < 5, then lines 23, 24, and 25 could also result in additional index out-of-bounds errors.

 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
package mayhemit;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.BufferedReader;
import java.io.FileReader;
import java.util.Scanner;

public class MayhemIt {
    public static void main(String[] args) {
        String input = "";

        try {
            File file = new File(args[0]);
            BufferedReader br = new BufferedReader(new FileReader(file));
            Scanner in = new Scanner(br);
            input = in.nextLine();
        } catch (FileNotFoundException e) {
            System.err.println("Could not find file");
            return;
        }

        if (input.length() >= 3 && input.length() < 5) {
            if (input.charAt(0) == 'b') {
                if (input.charAt(1) == 'u') {
                    if (input.charAt(2) == 'g') {
                        char x = input.charAt(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>/java-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/java-base-executable-mayhemit-out-of-bounds:

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

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

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

docker push <DOCKERHUB_USERNAME>/java-base-executable-mayhemit-out-of-bounds
docker push $MAYHEM_DOCKER_REGISTRY/java-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>/java-base-executable-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 could have executed a Mayhem run on the uploaded $MAYHEM_DOCKER_REGISTRY/java-base-executable-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
8
image: <DOCKERHUB_USERNAME>/java-base-executable-mayhemit-out-of-bounds:latest
duration: 120
project: mayhem-examples
target: mayhemit-out-of-bounds
cmds:
  - cmd: /usr/bin/MayhemIt.jar @@
    env:
      MFUZZ_JAVA: '1'
1
2
3
4
5
6
7
8
image: $MAYHEM_DOCKER_REGISTRY/java-base-executable-mayhemit-out-of-bounds:latest
duration: 120
project: mayhem-examples
target: mayhemit-out-of-bounds
cmds:
  - cmd: /usr/bin/MayhemIt.jar @@
    env:
      MFUZZ_JAVA: '1'

Your final Run page should have looked like the following:

mayhemit-out-of-bounds-run

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

✏️ Summary and Recap

In this lesson, you learned how to fuzz base-executable Java targets with Mayhem!


I learned how to...

1. Build and test a base-executable Java target with an uncaught exception defect.
  • The source code should contain the following defect:

    1
    2
    3
    4
    5
    6
    7
    8
    if (input.length() >= 3) {
        if (input.charAt(0) == 'b') {
            if (input.charAt(1) == 'u') {
                if (input.charAt(2) == 'g') {
                    throw new RuntimeException("Made it to the bug!");
            }
        }
    }
    

  • Then, to fuzz the base-executable Java target, use the following Dockerfile and Mayhemfile to build the Docker image containing the Java program and fuzz it in Mayhem:

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    FROM fuzzers/jazzer:0.9.1-openjdk11
    COPY MayhemIt.java .
    
    # Build MayhemIt.jar
    RUN mkdir -p build && \
        javac -d build MayhemIt.java && \
        cd build && \
        jar cvf MayhemIt.jar * && \
        mv MayhemIt.jar /usr/bin/MayhemIt.jar && \
        rm -rf build
    
    # Set to fuzz!
    ENTRYPOINT []
    CMD [ "/usr/bin/jazzer_driver", "--cp=/usr/bin/MayhemIt.jar", "--target_class=mayhemit.MayhemIt" ]
    

    1
    2
    3
    4
    5
    6
    7
    8
    image: <DOCKERHUB_USERNAME>/java-base-executable:latest
    duration: 120
    project: mayhem-examples
    target: java-base-executable
    cmds:
      - cmd: /usr/bin/MayhemIt.jar @@
        env:
          MFUZZ_JAVA: '1'
    
    1
    2
    3
    4
    5
    6
    7
    8
    image: $MAYHEM_DOCKER_REGISTRY/forallsecure/java-base-executable:latest
    duration: 120
    project: mayhem-examples
    target: java-base-executable
    cmds:
      - cmd: /usr/bin/MayhemIt.jar @@
        env:
          MFUZZ_JAVA: '1'
    
2. Build and fuzz a base-executable Java target with an out-of-bounds-defect.
  • The source code should contain the following defect:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    if (input.length() > 3 && input.length() < 5) {
        if (input.charAt(0) == 'b') {
            if (input.charAt(1) == 'u') {
                if (input.charAt(2) == 'g') {
                    char x = input.charAt(10);
                }
            }
        }
    }
    

  • Then, to fuzz the base-executable Java target, use the following Dockerfile and Mayhemfile to build the Docker image containing the Java program and fuzz it in Mayhem:

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    FROM amazoncorretto:8
    COPY MayhemIt.java .
    
    # Build MayhemIt.jar
    RUN mkdir -p build && \
        javac -d build MayhemIt.java && \
        cd build && \
        jar --create --file MayhemIt.jar --main-class mayhemit.MayhemIt * && \
        chmod u+x MayhemIt.jar && \
        mv MayhemIt.jar /usr/bin/MayhemIt.jar && \
        rm -rf build
    
    # Set to fuzz!
    ENTRYPOINT []
    CMD [ "/usr/bin/MayhemIt.jar", "@@" ]
    

    1
    2
    3
    4
    5
    6
    7
    8
    image: <DOCKERHUB_USERNAME>/java-base-executable-mayhemit-out-of-bounds:latest
    duration: 120
    project: mayhem-examples
    target: mayhemit-out-of-bounds
    cmds:
      - cmd: /usr/bin/MayhemIt.jar @@
        env:
          MFUZZ_JAVA: '1'
    
    1
    2
    3
    4
    5
    6
    7
    8
    image: $MAYHEM_DOCKER_REGISTRY/java-base-executable-mayhemit-out-of-bounds:latest
    duration: 120
    project: mayhem-examples
    target: mayhemit-out-of-bounds
    cmds:
      - cmd: /usr/bin/MayhemIt.jar @@
        env:
          MFUZZ_JAVA: '1'