Automatic Fuzzer Generation

Following up my last post on fuzzing an unknown proprietary protocol, we’ve now got a collection of packet captures to start ripping through to get some semblance of a fuzzer going to send packets to our target. Theres a few routes we can go, something as simple as flipping bits and putting garbage data into the stream all the way up to building a network model. I’m not big on either of the extremes. Flipping bits definitely works, but it tends to take a long time and you have a ton of crashes to dig through, and building a full protocol model can sometimes lead to great results and sometimes lead to terrible ones because you built something that works too well.

The approach I normally take is somewhere in the middle, some knowledge of the protocol, some notion of state, and go from there. But with a protocol like this I have nowhere to start. I could start reversing the protocol, get a good idea of strings, headers, etc, but that takes a lot of time and probably won’t get me anywhere too fast if its a binary protocol without a lot of strings in it (like many of these protocols are). I thought I’d apply a bit of computational power to letting me know the important bits.

Putting together a few quick scripts to pull the payloads out of the pcaps we have (or just the files from the immunity script), and I started comparing each payload to every other payload and figuring out the longest matches between them, and what positions in the stream those matches fell. Next I did some basic statistics on it, finding the median, minimum, and maximum position, and the deviation in the set. This tended to work out well and gave me something like this:

65 Matches for 00350100: on lines [128, 1, 130, 260, 129, 136, 137, 138, 139, 12, 13, 14, 15, 16, 145, 152, 154, 283, 285, 231, 289, 290, 291, 167, 299, 257, 287, 178, 179, 180, 181, 182, 187, 188, 189, 190, 193, 194, 195, 141, 142, 228, 280, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 253, 232, 242, 243, 244, 245, 247, 249, 251, 234, 126, 255]
Med: 4, Min: 4, Max:4, Std Deviation: 0
54 Matches for 040010000035: on lines [12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65]
Med: 0, Min: 0, Max:0, Std Deviation: 0
54 Matches for e00000000000: on lines [130, 131, 133, 134, 135, 136, 137, 138, 144, 145, 146, 147, 148, 149, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 293, 294, 295, 296, 284, 298, 299, 301, 178, 179, 182, 283, 187, 189, 192, 195, 68, 289, 74, 83, 84, 292, 228, 231, 232, 244, 297]
Med: 66, Min: 20, Max:3755, Std Deviation: 804

Of course it also gave me a few thousand other matches. But reducing those down to the longest matches with 0 deviation in X% of the set, then looking for the same match with a “small” deviation from the set, and so forth a few things start to pop out. You start to see field boundaries between data, “magic numbers” in the headers pop out of the data because they’re everywhere. Work through the data a bit more, and all thats left is creating the fuzzing template.

From there its just a matter of letting the fuzzer run in the background and report any crashes to investigate. I’m working on making this process a bit less manual, but it will probably never be completely automated. There is still quite a bit of art left in the science, and a lot of “gut feel” goes into creating a good negative tester.