Fuzz and Antifuzz
Why fuzz?
It is hard to enumerate all the inputs as test cases. When we write test cases, we generally consider some common scenarios such as forward testing, reverse testing, boundary values, super long, super short, etc., but we cannot iterate through all the inputs for testing. And fuzz is also a good way for hacker to find 0 day vulnarability.
Category of fuzz:
- blind fuzzers
The oldest class of fuzzers are so-called blind fuzzers. Such fuzzers have to overcome the problem that random inputs will not exercise any interesting code within a given software.
It includes mutational fuzzing and generational fuzzing. They can only detect if the program has crashed or not and find simple bugs. For large scale, they are useless.
Mutational fuzzers require a good corpus of inputs to mutate. It needs to perform numerous executions per second to work properly.
Generational fuzzing need manual human definition and grammar.
- Coverage-guided Fuzzers
use a feedback mechanism to receive information on how an input has affected the program under test.
Static Instrumentation: via static compile time coverage
Dynamic Binary Instrumentation (DBI): by adding the relevant code at runtime.
Hardware Supported Tracing: Modern CPUs support various forms of hardware tracing.
- Hybrid Fuzzers
It includes symbolic execution and taint execution.
Symbolic execution use symbolic to map to a function int a = α, b = β, c = γ;
Taint execution and Symbolic execution are both to reverse the path which trigger the vulnerability. By using symbolic execution or taint analysis, a fuzzer is able to reason what inputs are necessary to cover new edges and basic blocks.
Analysis of Fuzzing Assumptions
Coverage Yields Relevant Feedback: for coverage-guided fuzzer, it allocates different time according to different input
Crashes Can Be Detected : most bug finding tools need the ability to tell a crashing input apart from a non-crashing input in an efficient and scalable way
Many Executions per Second : To efficiently generate input files with great coverage, the number of executions per second needs to be as high as possible.
Constraints Are Solvable with Symbolic Execution : Hybrid fuzzer has reached some difficult paths by combining taint analysis and symbol execution, which requires that these conditions be solved by symbol execution and stain analysis.
Impeding Fuzzing Audits
1, Attacking Coverage-guidance
Add irrelevant code to drowns out actual signal. Therefore, if the program always displays new coverage (due to our fake code), the fuzzer cannot distinguish between legitimate new coverage and invalid fake coverage.
It is like when the attacker sends numerous request to the website with the burp suit, when there is a different return code, mostly this input will be the right answer. But if there are some fake code in it, the attacker may receive various code, thus we cannot distinguish which input is valid.
2,Preventing Crash Detection
By using common anti-debugging measures and customize the crash signal to intentionally trigger a segfault (fake crash) that our own signal handler recognizes and ignores. Even if a crash really happens, we will catch it before report. In all of these cases, no crashes will be detected even if they still occur.
3, Delaying Execution
Fuzzer relies on speed a lot. If we detect malformed input, slow down the application. The slowdown speed will not be notice by users.
4,Overloading Symbolic Execution Engines
To prevent program analysis techniques from extracting information to solve constraints and cover more code, simple tasks can be rewritten in a way that it is a lot harder to reason about their behavior.
First, we use hash comparisons. As a second technique, we can encrypt and then decrypted the input with a block cipher.
Therefore, symbolic/concolic execution engines either carry very large expressions for each input byte, or they concretize every input byte, completely voiding the advantage they provide. Finally, common taint tracking engines will not be able to infer taint on the input, as the encryption thoroughly mixes the input bits.
ANTIFUZZ with the LAVA-M dataset [18], which consists of four applications (base64, who, uniq and md5sum)