These fuzzing engines produce input completely randomly, without considering what input format is expected. A dumb fuzzer is relatively easy and inexpensive to set up, but is also very inefficient.
These types of fuzzers produce inputs that are based on valid input formats. This is very useful, since some programs only execute when inputs match certain patterns. In case invalid inputs are provided, the applications cannot be run and thus cannot be tested. A smart fuzzer recognizes what input format is desired and produces inputs matching this format. This type of fuzzing requires detailed knowledge about input format and thus takes longer to set up, meaning that more costs are involved.
Feedback-based fuzzing (or coverage-based fuzzing) uses code coverage information when generating new inputs. As a result, feedback-based fuzzers can cover and test more paths in programs than smart fuzzers. Due to measuring code coverage, the fuzzer can monitor which parts of the program were reached with a given input and reach other program parts by generating similar inputs with random but small changes.
Mutation-based fuzzing mutates original valid inputs by introducing small changes that may still keep the input valid, yet exercise new behavior.
Generation-based fuzzing can generate new inputs from scratch. As opposed to mutation-based fuzzers, no original valid input is needed to start producing new inputs. It is important, however, that generated inputs are based on a certain data model, so that corresponding code coverage can be reached.
Read next: Anatomy of a Fuzzer