FFW Fenrir Update

FFW was initially conceived at sleepless night in the Luxor hotel in Las Vegas, between Blackhat and Defcon. With this the basic fundamental data structures FFW uses are a bit... shitty. I called my attempt to rewrite these data structures "Fenrir", the beast:

800px-Odin_and_Fenris-1

Basically, the initial data structures were a catastrophe. Multiple independant modules, each loading/storing their own data in their own way - especially between the Interceptor, Fuzzer and Verifier (network data records, network data records fuzzed, network data records fuzzed + crash information). Compatibility was hard. I decided to rewrite the whole thing from scratch - this led to a nearly complete rewrite of FFW, as every component needed to be touched.

Main data structures

We have a hierchy of data structures:

  • NetworkData: contains an array of the intercepted network messages. These are never stored alone.
  • CorpusData: basically the NetworkData with some more information (parent), and functions to read/write it from file.
    • Note: a CorpusData can get fuzzed, which creates a NEW CorpusData.
    • IF this NEW CorpusData accesses new functionality in the target, and honggmode is being used, we store it as Corpus.
    • This duality of corpus/fuzzed is not really visible in the CorpusData data structure, and also doesnt really matter.
  • If a crash was observed with a particular CorpusData, a CrashData will be created with some basic crash information.
  • If a crash was verified, a VerifyData is created, with the CrashData inside. Detailed crash information is stored in VerifyData.
  • Therefore, for example we have verifyData.crashData.corpusData.networkData.messages[0]
                                     +--------------------------+
                                     | NetworkData              |
                                     +--------------------------+
                                     | * messages[]             |
                                     | * seed                   |
                                     |                          |
                                     |                          |
                                     |                          |
                                     +--------------------------+ <---+
                                                                      |
                                                                      |
                                                                      |
+----------------------+-----------> +-------------------------+      |
| CorpusManager        |             | CorpusData              |      |
+----------------------+             +-------------------------+      |
| * CorpusData[]       |             | * filename              |      |
|                      |             | * parentFilename        +------+
|                      |             | * networkData           |
|                      |             | * write()               |
|                      |             | * read()                |
+----------------------+             +-------------------------+ <----+
                                                                      |
                                                                      |
                                                                      |
+----------------------+-----------> +-------------------------+      |
| CrashManager         |             | CrashData               |      |
+----------------------+             +-------------------------+      |
| * CrashData[]        |             | * filename              |      |
|                      |             | * parentFilename        |      |
|                      |             | * corpusData            +------+
|                      |             | * write()               |
|                      |             | * read()                |
+----------------------+             +-------------------------+ <-----+
                                                                       |
                                                                       |
                                                                       |
+----------------------+-----------> +-------------------------+       |
| VerifyManager        |             | VerifyData              |       |
+----------------------+             +-------------------------+       |
| * CrashData[]        |             | * filename              |       |
|                      |             | * parentFilename        |       |
|                      |             | * crashData             +-------+
|                      |             | * write()               |
|                      |             | * read()                |
+----------------------+             +-------------------------+



  +-------------------------+     +-----------------------------+
  | FuzzerInterface         |     | NetworkManager              |
  +-------------------------+     +-----------------------------+
  | * fuzz(CorpusData)      |     | * send(NetworkData)         |
  |                         |     |                             |
  |                         |     |                             |
  |                         |     |                             |
  |                         |     |                             |
  +-------------------------+     +-----------------------------+

Honggmode is a bit special:

+----------------------+-----------> +------------------------------+
| HonggCorpusManager   |             | HonggCorpusData(CorpusData)  |
+----------------------+             +------------------------------+
| * CorpusData[]       |             | * isExternal                 |
|                      |             | * isProcessed                |
|                      |             |                              |
|                      |             | * write()                    |
|                      |             | * read()                     |
+----------------------+             +--------------+---------------+
                                                    |
                                                    |
                                                    |
                                       +------------v------------+
                                       | CorpusData              |
                                       +-------------------------+
                                       | * filename              |
                                       | * parentFilename        |
                                       | * networkData           |
                                       | * write()               |
                                       | * read()                |
                                       +-------------------------+

The CorpusData needs some additional information, for HonggCorpusManager. It is necessary to know if that Corpus was created by the current fuzzer instance, or another one. In the latter case, the Corpus has to be sent to the target, but the result ignored.

ASCII gfx made with the awesome ASCIIFlow

About unit tests

As the Fenrir touches basically everything in FFW, I had to make sure it still works as expected - I had to tame the beast Fenrir. This led me to consequently use unit tests for the first time.

Unit tests and integration tests rock. After writing the basic functionality of a class, I wrote a quick unit test to check if it really works as intended. This:

  • Made bug fixing the initial development easier (tests run quickly)
  • Identified easy to identify mistakes in the new classes
  • Allowed me to improve the interface of the class, and the consumer
  • By writing the test, or even a Mockup Server, improved the code of future classes/code
  • Discover hard to identify bugs

Noteworthy example is the CorpusManagerTest, who uses a file watcher to add corpus files from other fuzzers. The basic functionality of adding an external file to its own repo, but ignore his own added files, should just work reliably.
Also the InterceptorTest required a mockup network- server and client, which has shown some troubles with the target/baseport specification, and how different components handle it differently - including the user.

Additionally I now have much more trust that things work. While previously I needed to really perform tests on an actual fuzzing project, the unit tests now cover most of the basic funtionality. I dont make a concise distinction between unit- and integration test. As the amount of tests grow with time, i may need to split the slow tests into their own folder.

Next up I want to add some more high level integration tests on the example vulnerable server.

Interestingly i had quite a big bug, where the NetworkNamespaces did not work at all for some time. This surprised me, as i had a unit-test for this. But this unit-test was hastiliy written and wrong on several levels... completely useless. Lesson learned.