In my talk at FuzzCon Europe 2021, I unveiled the latest features of the open-source Java fuzzer Jazzer. Since its integration into Google’s OSS-Fuzz early this year, Jazzer found over 200 bugs in onboarded open-source projects (130 security-critical, 10 CVEs affecting released versions). In the most recent Jazzer release, we added major improvements in terms of more intuitive onboarding, usability improvements, and bug detection capabilities.
Autofuzz explained at FuzzCon Europe 2021
No More Writing Test Harnesses or Fuzz Targets
Most fuzzers require users to create fuzz targets or test harnesses manually. To ease fuzzing integration, our main improvement in the new Jazzer release is the autofuzz mode, making the creation of fuzz targets obsolete. All you need to do is specify the method to be tested from any Java library (by simply pointing to a jar file), and the rest will be generated in a structure-aware manner by Jazzer, recursively following the Java type declarations. This makes fuzzing with Jazzer as simple as:
jazzer --cp=commons-compress-1.20.jar --autofuzz = org.apache.commons.compress.archivers.sevenz.SevenZFile::new
From here, Jazzer performs semantic fuzzing, meaning that Jazzer creates valid objects as required by the tested method. Jazzer handles various ways how objects are created, e.g., public constructors, builder patterns, etc. If the parameters are interfaces or abstract classes, Jazzer looks for implementing classes that can be instantiated.
In this particular example, Jazzer sets out to invoke public SevenZFile constructors, recursively constructing required instances of classes such as File or SeekableByteChannel. All exceptions thrown during these intermediate objects' creations are ignored, but any exceptions during the actual invocation of a SevenZFile constructor with valid parameters are reported as findings. In this way, Jazzer performs semantic, structure-aware fuzzing of Java methods.
Jazzer's Autofuzz mode is available as a stand-alone Docker image with which you can quickly run the example above as follows:
docker run -it cifuzz/jazzer-autofuzz org.apache.commons:commons-compress:1.20 org.apache.commons.compress.archivers.sevenz.SevenZFile::new --autofuzz_ignore=java.nio.file.InvalidPathException,java.lang.NullPointerException
Note the --autofuzz_ignore flag which we used to ignore some "boring" exceptions thrown by the SevenZFile constructors for valid invocations with semantically invalid arguments (e.g., null or files with invalid paths).
Going Beyond OWASP & DoS
We are often asked whether fuzzing for Java can go beyond finding vulnerabilities that impact "just" the stability and availability of applications (e.g. via high CPU or memory usage or undeclared exceptions). While we find most of the typical OWASP vulnerabilities, such as SQL Injections or XSS, with our commercial solution, with the latest Jazzer release, we are open-sourcing more and more bug detectors (Jazzer’s equivalent of Google's Sanitizers) for high-impact vulnerability classes such as expression language injections and remote code executions due to unsafe deserialization.
Further Updates to Support More Use Cases
In addition to various bug fixes and code coverage improvements, we also added support for further fuzzing use cases. Up to now, Jazzer was only available for Linux (or in a Docker image). Since many Java developers work on macOS or Windows, we have now added the often requested native support for these platforms.
Also, we added Jazzer support to the official Bazel rules for fuzzing. See their README for instructions on how to use Jazzer in a Java Bazel project.
About the Author
Fabian Meumertzheim is a Senior Software Engineer at Code Intelligence. A mathematician by education, he has always been passionate about IT security. He maintains and contributes to multiple open-source projects, such as Chromium, system, and Android Password Store, all with the aim of making security unobtrusive and ubiquitous.