DEV Community

Cover image for How to fuzz java code with jazzer?
Ramin Farajpour Cami
Ramin Farajpour Cami

Posted on

How to fuzz java code with jazzer?

What is fuzzing?

Modern fuzzing solutions analyze the structure of the code they are testing and generate thousands of automated test cases per second. The process is designed to reach as many new program states as possible with the generated inputs . In addition, the fuzzer also marks the individual paths followed by these inputs and thus receives detailed feedback on the test coverage achieved when executing the source code. In this way, fuzzers learn more about the structure of the expected input with each iteration.

Type Of Fuzzing

1- Dumb Fuzzer
2- Generation Fuzzer
3- Coverage Guided Fuzzer

What is Dumb Fuzzer ?

Dumb fuzzer works without having any knowledge about the data attempts to random input, also no understanding of file format/network protocol is required. also can take lot of time (depending up on your luck).

Ex Radmasa

What is Generation Fuzzer?

In contrast to Dumb Fuzzers, here an understanding of the file format / protocol is very important. It’s about “generating” the inputs from the scratch based on the specification/format.

Ex ( Peach, Sulley )

What is Coverage Guided Fuzzer?

Coverage guided fuzzing uses program instrumentation to trace the code coverage and monitors program flow by using instrumentation. no knowledge of the file format is required and It modifies the file using its own algorithms and check for new code path coverage/crash.

Ex ( AFL, WinAFL, HonggFuzz, LibFuzzer, Jazzer )

What is Jazzer?

Today, we will dive into the Java world and check out the most popular Java fuzzing solution, Jazzer is used to automatically generate malicious inputs for Java programs.

Tools setup :

We will now go through the process of installing Jazzer so you can easily follow along on my VM machine (Ubuntu 20.04).

Jazzer has the following dependencies when being built from source:

1- Install Bazel 4 or later
2- Install JDK 8 or later (e.g. OpenJDK)
3- Install Clang and LLD 9.0 or later

Compilation :

$ git clone https://github.com/CodeIntelligenceTesting/jazzer
$ cd jazzer
$ ./bazelisk-linux-amd64 run //:jazzer                                                                                                                                                                                               
Starting local Bazel server and connecting to it...
INFO: Analyzed target //:jazzer (79 packages loaded, 1410 targets configured).
INFO: Found 1 target...
Target //:jazzer up-to-date:
  bazel-bin/jazzer
INFO: Elapsed time: 43.920s, Critical Path: 7.21s
INFO: 83 processes: 4 internal, 79 linux-sandbox.
INFO: Build completed successfully, 83 total actions
INFO: Build completed successfully, 83 total actions
driver/jazzer_driver: error while loading shared libraries: libjvm.so: cannot open shared object file: No such file or directory

Enter fullscreen mode Exit fullscreen mode

We have a error
libjvm.so: cannot open shared object file: No such file or directory
If you have this error for solution we should define LD_LIBRARY_PATH

$ wget https://enos.itcollege.ee/~jpoial/allalaadimised/jdk15/jdk-15.0.2_linux-x64_bin.tar.gz

$ export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/home/ubuntu/jdk-15.0.2/lib/server/

$ ./bazelisk-linux-amd64 run //:jazzer  
INFO: Analyzed target //:jazzer (0 packages loaded, 0 targets configured).
INFO: Found 1 target...
Target //:jazzer up-to-date:
  bazel-bin/jazzer
INFO: Elapsed time: 0.205s, Critical Path: 0.00s
INFO: 1 process: 1 internal.
INFO: Build completed successfully, 1 total action
INFO: Build completed successfully, 1 total action
Java HotSpot(TM) 64-Bit Server VM warning: Sharing is only supported for boot loader classes because bootstrap classpath has been appended
INFO: Loaded 8 hooks from com.code_intelligence.jazzer.sanitizers.Deserialization
INFO: Loaded 1 hooks from com.code_intelligence.jazzer.sanitizers.ReflectiveCall
Missing argument --target_class=<fuzz_target_class>
Enter fullscreen mode Exit fullscreen mode

Choose your java lib or code for fuzzing (Ex : generex)

1- Add "com.github.mifmif:generex:1.0.2" lib to nano maven.bzl


load("@rules_jvm_external//:specs.bzl", "maven")

JAZZER_API_VERSION = "0.10.0"
JAZZER_API_COORDINATES = "com.code-intelligence:jazzer-api:%s" % JAZZER_API_VERSION

# **WARNING**: These Maven dependencies have known vulnerabilities and are only used to test that
#              Jazzer finds these issues. DO NOT USE.
MAVEN_ARTIFACTS = [
    "junit:junit:4.12",
    "org.apache.commons:commons-imaging:1.0-alpha2",
    "com.mikesamuel:json-sanitizer:1.2.1",
    "com.google.code.gson:gson:2.8.6",
    "com.fasterxml.jackson.core:jackson-core:2.12.1",
    "com.fasterxml.jackson.core:jackson-databind:2.12.1",
    "com.fasterxml.jackson.dataformat:jackson-dataformat-cbor:2.12.1",
    "com.alibaba:fastjson:1.2.75",
    "com.beust:klaxon:5.5",
    "javax.validation:validation-api:2.0.1.Final",
    "javax.xml.bind:jaxb-api:2.3.1",
    "javax.el:javax.el-api:3.0.1-b06",
    "org.hibernate:hibernate-validator:5.2.4.Final",

    "com.github.mifmif:generex:1.0.2",

    maven.artifact("org.apache.logging.log4j", "log4j-api", "2.14.1", testonly = True),
    maven.artifact("org.apache.logging.log4j", "log4j-core", "2.14.1", testonly = True),

]

Enter fullscreen mode Exit fullscreen mode

2- Editing $ nano examples/BUILD.bazel to this :

java_fuzz_target_test(
    name = "GenerexFuzzer",
    srcs = [
        "src/main/java/com/example/GenerexFuzzer.java",
    ],
    target_class = "com.example.GenerexFuzzer",
    deps = [
        "@maven//:com_github_mifmif_generex",
    ],
)

Enter fullscreen mode Exit fullscreen mode

3- Create java file for fuzzing GenerexFuzzer.java

$ nano /home/jazzer/examples/src/main/java/com/example/GenerexFuzzer.java
Enter fullscreen mode Exit fullscreen mode

Add my code for fuzzing by Jazzer

package com.example;

import com.code_intelligence.jazzer.api.FuzzedDataProvider;
import com.mifmif.common.regex.Generex;

// Found the issues.
public class GenerexFuzzer {
  public static void fuzzerTestOneInput(FuzzedDataProvider data) {
    try {
        Generex generex = new Generex(data.consumeRemainingAsString());
        generex.random();
    } catch (IllegalArgumentException ignored) {
        }
  }
}
Enter fullscreen mode Exit fullscreen mode

4- Now starting for fuzzing :

$ ./bazelisk-linux-amd64 run //examples:GenerexFuzzer
INFO: Analyzed target //examples:GenerexFuzzer (0 packages loaded, 0 targets configured).
INFO: Found 1 target...
Target //examples:GenerexFuzzer up-to-date:
  bazel-bin/examples/GenerexFuzzer
INFO: Elapsed time: 0.121s, Critical Path: 0.00s
INFO: 1 process: 1 internal.
INFO: Build completed successfully, 1 total action
INFO: Build completed successfully, 1 total action
exec ${PAGER:-/usr/bin/less} "$0" || exit 1
Executing tests from //examples:GenerexFuzzer
-----------------------------------------------------------------------------
Java HotSpot(TM) 64-Bit Server VM warning: Sharing is only supported for boot loader classes because bootstrap classpath has been appended
INFO: Loaded 8 hooks from com.code_intelligence.jazzer.sanitizers.Deserialization
INFO: Loaded 1 hooks from com.code_intelligence.jazzer.sanitizers.ReflectiveCall
INFO: Loaded 8649 no-throw method signatures
INFO: Instrumented com.example.GenerexFuzzer (took 42 ms, size +37%)
INFO: libFuzzer ignores flags that start with '--'
INFO: Running with entropic power schedule (0xFF, 100).
INFO: Seed: 2735196724
INFO: Loaded 1 modules   (512 inline 8-bit counters): 512 [0x7fcec02c9010, 0x7fcec02c9210), 
INFO: Loaded 1 PC tables (512 PCs): 512 [0x7fce8abfe010,0x7fce8ac00010), 
INFO: -max_len is not provided; libFuzzer will not generate inputs larger than 4096 bytes
INFO: Instrumented com.mifmif.common.regex.Generex (took 16 ms, size +49%)
INFO: Instrumented com.mifmif.common.regex.util.Iterable (took 1 ms, size +0%)
INFO: Instrumented com.mifmif.common.regex.util.Iterator (took 0 ms, size +0%)
INFO: New number of inline 8-bit counters: 1024
INFO: Instrumented dk.brics.automaton.RegExp (took 17 ms, size +104%)
INFO: Instrumented dk.brics.automaton.RegExp$Kind (took 2 ms, size +42%)
INFO: Instrumented dk.brics.automaton.RegExp$1 (took 1 ms, size +102%)
INFO: Instrumented dk.brics.automaton.BasicAutomata (took 11 ms, size +130%)
INFO: New number of inline 8-bit counters: 2048
INFO: Instrumented dk.brics.automaton.Automaton (took 9 ms, size +82%)
INFO: Instrumented dk.brics.automaton.State (took 2 ms, size +55%)
INFO: Instrumented dk.brics.automaton.Transition (took 2 ms, size +74%)
INFO: Instrumented dk.brics.automaton.TransitionComparator (took 1 ms, size +97%)
INFO: A corpus is not provided, starting from an empty corpus
#2      INITED cov: 71 ft: 71 corp: 1/1b exec/s: 0 rss: 114Mb
#3      NEW    cov: 176 ft: 191 corp: 2/3b lim: 4 exec/s: 0 rss: 114Mb L: 2/2 MS: 1 CopyPart-
#5      NEW    cov: 178 ft: 286 corp: 3/6b lim: 4 exec/s: 0 rss: 114Mb L: 3/3 MS: 2 ChangeByte-InsertByte-
#10     NEW    cov: 178 ft: 378 corp: 4/10b lim: 4 exec/s: 0 rss: 114Mb L: 4/4 MS: 5 InsertByte-ChangeBit-ChangeBinInt-InsertByte-CopyPart-
#21     NEW    cov: 181 ft: 384 corp: 5/13b lim: 4 exec/s: 0 rss: 114Mb L: 3/4 MS: 1 ChangeBit-
#6375   NEW    cov: 975 ft: 4248 corp: 243/1071b lim: 8 exec/s: 6375 rss: 154Mb L: 7/8 MS: 1 CrossOver-
#6391   NEW    cov: 975 ft: 4250 corp: 244/1079b lim: 8 exec/s: 6391 rss: 154Mb L: 8/8 MS: 1 CopyPart-

== Java Exception: com.code_intelligence.jazzer.api.FuzzerSecurityIssueLow: Stack overflow (truncated to likely cause)
        at com.mifmif.common.regex.Generex.prepareRandom(Generex.java:366)
Caused by: java.lang.StackOverflowError
        at java.base/java.util.TimSort.countRunAndMakeAscending(TimSort.java:355)
        at java.base/java.util.TimSort.sort(TimSort.java:220)
        at java.base/java.util.Arrays.sort(Arrays.java:1232)
        at dk.brics.automaton.State.getSortedTransitionArray(Unknown Source)
        at dk.brics.automaton.State.getSortedTransitions(Unknown Source)
        at com.mifmif.common.regex.Generex.prepareRandom(Generex.java:340)
        at com.mifmif.common.regex.Generex.prepareRandom(Generex.java:366)
        at com.mifmif.common.regex.Generex.prepareRandom(Generex.java:366)
        at com.mifmif.common.regex.Generex.prepareRandom(Generex.java:366)
        at com.mifmif.common.regex.Generex.prepareRandom(Generex.java:366)
        at com.mifmif.common.regex.Generex.prepareRandom(Generex.java:366)
        at com.mifmif.common.regex.Generex.prepareRandom(Generex.java:366)
Enter fullscreen mode Exit fullscreen mode

LibFuzzer crashing input :

MS: 2 ChangeBit-CMP- DE: "\x00\x00\x00\x05"-; base unit: b5d43fd7e3064418d903c4d27d2238f390e23c62
0x7e,0x2f,0x7d,0x0,0x0,0x0,0x5,
~/}\x00\x00\x00\x05
artifact_prefix='/root/.cache/bazel/_bazel_root/c82b104c68f93e19e57160becd18f8f0/execroot/jazzer/bazel-out/k8-opt/testlogs/examples/GenerexFuzzer/test.outputs/'; Test unit written to /root/.cache/bazel/_bazel_root/c82b104c68f93e19e57160becd18f8f0/execroot/jazzer/bazel-out/k8-opt/testlogs/examples/GenerexFuzzer/test.outputs/crash-101076ac3391a62fb4622589093c2543063de037
Base64: fi99AAAABQ==
Enter fullscreen mode Exit fullscreen mode

Congratulations! We found Stack overflow Vulnerability.

I hope enjoy,
Thanks, Ramin

Top comments (2)

Collapse
 
nehringmarion profile image
Marion Nehring

Wow Thank You Ramin for the great example on how fuzzing can support finding voulnerabilities early on in the development process! Great Read!

Collapse
 
raminfp profile image
Ramin Farajpour Cami

🙌