Increasing Security: Fuzz Testing C++
Today, I’d like to share an automated testing approach that can protect your C++ applications from memory corruptions and other security vulnerabilities.
What is Fuzz Testing? How Does it Help Find C++ Security Vulnerabilities?
Fuzz testing is one of the most effective ways to find bugs and security issues in software. Using this approach, engineers at Google have already found more than 25,000 bugs in Chrome, 75% of which were memory issues, such as heap buffer overflows. Effectively, the Chromium team has almost completely automated their security testing for memory issues with this testing approach.
Fuzz Testing is a dynamic testing method for finding functional bugs and security issues in software. During a fuzz test, a program or a function under test gets executed with thousands of invalid, unexpected, or random inputs in order to crash the application. a stress test for your application code. However, the fuzzer gets feedback on the structure of the code and the states reached by the automatically generated inputs. With this information, the fuzzer can adjust and mutate its inputs to produce additional test cases that are highly likely to trigger even more errors and crashes in the system under test.
What Bugs Can You Find With Fuzzing in C++?
With fuzzing, you can find all sorts of vulnerabilities that can cause your application to crash, among other issues. The bugs you can find include:
- Memory Issues
- Buffer Overflows
- Use After Free
- Out of Bounds
- Memory Leaks
- Uninitialized reads
- Resource Usage Bugs
- Memory Exhaustion
- Hangs or Infinite Loops
- Infinite Recursions
- Denial of Services (DoS)
- Logical Bugs
- Discrepancies between two implementations of the same protocol
- Round-trip consistency bugs (e.g. compress the input decompress back, -compare with the original)
- Plain Crashes
- NULL deference
- Uncaught Exceptions
Fuzzing C/C++ Becomes Even More Effective When Applying Sanitizers
A sanitizer is a software library that you compile into your code to make your program crash more often. The question is, why would you want to do that in the first place?
Suppose a fuzzer generates inputs that exceed the allocated buffer size. In that case, these inputs do not necessarily cause the application to crash, since accessing information in the unallocated area might well be allowed. But you can trigger a crash during a fuzz test intentionally by restricting the program execution with a sanitizer.
For example, the AddressSanitizer (ASan) can replace the malloc and free functions in an application to create “poisoned areas” around the memory you want to allocate. So, if your application at some point is trying to access the red areas in your system, the sanitizer will throw an exception or an error message.
List of Sanitizers for Fuzzing
Here is a list of four common C/C++ sanitizers and the vulnerabilities you can find with them if you apply those sanitizers in combination with fuzzing:
The AddressSanitizer (ASan) is a memory error detector for C/C++. It finds:
- Use after free (dangling pointer dereference)
- Heap buffer overflow
- Stack buffer overflow
- Global buffer overflow
- Use after return
- Use after scope
- Initialization order bugs
- Memory leaks
The MemorySanitizer (MSan) is a detector of uninitialized memory reads in C/C++ programs.
The UndefinedBehaviorSanitizer (UBSan) is a fast undefined behavior detector implemented in Clang and Compiler-rt.
The ThreadSanitizer (TSan) is a data race detector for C/C++. It finds:
- Signed integer overflow
- Out of Bounds Array
- Out of Bounds BitShifts
- Floating Point Conversion Overflow
- Dereferencing Misaligned or Null Pointers
- Data Races
Fuzz Testing In Practice
Now that we’ve covered the basics of Fuzz Testing for C++, let’s look at performing a fuzz test in practice. I prepared a use case with a simple C/C++ application that contains two vulnerabilities, an Undefined Behavior, and a Heap Buffer Overflow.
In this video, I will explain step by step how to write a fuzz test that triggers both of those vulnerabilities: www.youtube.com/watch?v=JAFitzmGO3A
I used the CI Fuzz CLI, an easy-to-use fuzzing tool that enables you to integrate and run fuzz tests directly from your command line.
All tools and code examples used in this tutorial are open-source.
Getting started with fuzzing is not always easy, and many open-source fuzzers require a lot of skills and knowledge to set up your first fuzz test. But I hope this tutorial and the CI Fuzz CLI can make it easier for you to get started with fuzzing, as it’s really one of the most effective (and fun) ways to test C++ for memory corruptions and other vulnerabilities.
If you have any questions about the tutorial or the CI Fuzz CLI, please feel free to reach out via @jochil!
Join the Meeting C++ patreon community!
This and other posts on Meeting C++ are enabled by my supporters on patreon!