Fuzz Testing is one of the most effective methods to find bugs and vulnerabilities in software. With the open-source fuzzing framework OSS-Fuzz alone, security researchers were able to find more than 36,000 bugs in over 550 open-source projects over the last four years. However, most of these projects were written in C/C++.
Among some developers, this observation apparently led to the impression that fuzzing is only useful to uncover memory corruptions in C++. Therefore, some developers are still sceptical when it comes to fuzz testing in other languages than C++.
I want to break with this misconception and demonstrate that fuzzing is also useful to prevent bugs in memory-safe languages such as Java, Go and Python.
Update: The most recent version of our Java fuzzer can even detect the RCE that caused the logj4 vulnerability. We've made this functionality available to the open-source community within Jazzer and OSS-Fuzz.
No Bugs Are Safe From Feedback-Based Fuzzing
Fuzzing or fuzz testing is an automated security testing technique in which invalid, unexpected, or random data are provided as input to a computer program. It forces the application to crash and is therefore particularly useful for functional and stability tests.
But fuzz testing uncovers all kinds of bugs and vulnerabilities. For example:
- Crashes, Timeouts and Hangs
- Memory Corruption errors like Buffer Overflows and Leaks
- Race Conditions
- Excessive Resource Consumption
- Uncaught Exceptions
- Undefined Behavior
- Inconsistent Implementations
- Infinite Loops
- SQL Injections
- XSS (Framework, Sanitizers, …)
- RCE (Jakarta, Serialization, …)
Common Security Vulnerabilities in Memory-Safe Languages
Memory Safe Languages, such as Java, Python, or Go, get their name from effective runtime error prevention mechanisms that prevent most memory corruption. Nevertheless, even in projects that are written in these languages, you will find many functional bugs and critical vulnerabilities that can seriously harm your applications. However, instead of memory corruptions, other vulnerabilities become more prominent.
Typical Bugs for Memory Safe Languages are Infinity Loops, Denial-of-Service (DoS-Bugs), Crashes, OutOfMemoryErrors, Cross-Site-Scripting (XXS) and Wrong Handled Exceptions. These bugs are particularly annoying and can have a huge impact on the usability of your applications. Some of them can even be dangerous. Attackers would use these vulnerabilities to shut down all services and cause serious damage to your software and your reputation. A particularly critical example is CVE-2020-28362 (DoS-Bug), which could have crashed the entire Ethereum network.
Don’t Underestimate the Threat of Memory Corruptions
I also want to emphasize that memory corruptions in C++ can also affect systems written in other languages. Almost all memory-safe programming languages provide ways to interface with libraries written in other programming languages. A widespread use case is native libraries that are written in C/C++ for performance or legacy reasons. These libraries can be used via a Foreign Function Interface (FFI) such as the Java Native Interface (JNI). Since the memory management in the interfacing code often has to be performed manually, this often leads to memory corruptions in the Java to C/C++ glue code, as in CWE-111 (Direct Use of Unsafe JNI).
Domain-Specific Vulnerabilities Using the Example of OWASP
Fuzzing memory-safe languages is particularly useful for web services because of the high degree of interconnectivity. However, web services are particularly difficult to secure. Not only the different systems themselves have to be secured but also the APIs that connect them. Automated testing approaches, like feedback-based fuzzing, will usually provide the best results in a web environment.
The OWASP organization regularly ranks the most critical security vulnerabilities in web applications. And I would like to refer to two of these lists in particular. The Top 10 Web Application Security Risks and the Top 10 API Security Risks. Since these bugs are highly dangerous and prevalent, you should regularly test your web applications for them.
Securing a CVE That Would Have Exposed Hundreds of Projects…
A good example where feedback-based fuzzing outperformed other testing approaches in a memory-safe environment is CVE-2021-23899 in the JSON Sanitizer. The JSON Sanitizer is a popular Java library that is supposed to take potentially buggy JSON input and create valid JSON files from it as output. The vulnerability would have allowed attackers to inject HTML and XML files into the code. Although the code was tested with other testing approaches before, none of them were able to find this CVE. Thanks to the instrumentation capacities of feedback-based fuzzing, this critical bug was uncovered and fixed within a few minutes.
Fuzz Your First Application Today
As you can see in these examples, it is quite useful to fuzz applications that are written in memory-safe languages, like Java. You will probably find many bugs that would have remained undetected with other testing approaches. So, if fuzzing is new to you, I would like to encourage you to give it a try! It’s really not that hard, and it will instantly improve your code quality.
Try to start with an open-source fuzzer like Atheris (for Python) or Jazzer (for Java). If you’re feeling more comfortable and want to try fuzzing in a more complex environment, there are plenty of enterprise solutions, like CI Fuzz, that comes with many additional features like reporting, CI/CD, dev tool integration, and WebAPI fuzzing.
Tutorial: How to Fuzz Java Libraries with Jazzer
Related Article: Best Practices for Java Testing