I got a lot of interesting comments from my TechEd 2008 presentation entitled, "How To Review Your Code And Test For Security Bugs," but the most comments and questions were reserved for fuzz testing; I was blown away by the number of people who thought fuzz testing was hard, or that you only left fuzz testing to ‘leet hackers.
During the presentation I mentioned in some depth how to perform fuzz testing, and what parts of an application should be fuzz testing targets. I also introduced an idea (that's not new) to help people who have never performed fuzz testing begin fuzz testing with very little cost and friction. The idea is to add a small layer of code to an application to automatically mutate untrusted data as it comes into an application; I called that code layer "a layer of hurt."
Before I continue, I want to point out that fuzzing is an SDL requirement, but the idea in this blog post is not an SDL requirement, it's just another way to help meet SDL fuzzing requirements.
Adding a layer of hurt, as shown in the picture below, is pretty simple as it involves adding code to an application to tweak data as it comes into an application. You can work out where to place the fuzzing code by looking at your threat models to see where data crosses trust boundaries. You could also simply grep the code looking for APIs that read data, for example:
You get the picture.
The fuzzing code should appear right after the API that reads that data.
For example, C or C++ code that reads from a UDP socket and then fuzzes the data before it's consumed by the rest of the application might look like this:
char RecvBuf[1024];int BufLen = sizeof(RecvBuf);
int result = recvfrom( RecvSocket, RecvBuf, BufLen, 0, (SOCKADDR *)&SenderAddr, &SenderAddrSize);
#ifdef _FUZZ Fuzz(RecvBuf,&BufLen);#endif
Or, in C#, code that reads from an untrusted file:
FileStream fileStream = new FileStream(filename, FileMode.Open, FileAccess.Read);uint len = (uint)(fileStream.Length);byte[] fileData = new byte[fileStream.Length];fileStream.Read(fileData, 0, (int)len);fileStream.Close();
#if _FUZZ_ Malform pain = new Malform(); fileData = pain.Fuzz(fileData);#endif
In both code examples, Fuzz() mutates the incoming data. In the C++ case, the fuzzing code looks like this:
void Fuzz(_Inout_bytecap_(*pcbBuf) char *pBuf, _Inout_ size_t *pcbBuf) { if (!pcbBuf || !pBuf || !*pcbBuff || *pBuf) return; if ((rand() % 100) > 5) return; // fuzz about 5% of Buffers
size_t cLoop = 1 + (rand() % 4);
for (size_t j = 0; j < cLoop; j++) {
size_t i=0, iLow = rand() % *pcbBuf, iHigh = 1+rand() % *pcbBuf, iIter = 1+rand() % 8; if (iLow > iHigh) {size_t t=iHigh; iHigh=iLow; iLow=t;}
char ch=0; switch(rand() % 9) {
case 0 : // reset upper bits for (i=iLow; i < iHigh; i++) pBuf[i] &= 0x7F; break;
case 1 : // set upper bits for (i=iLow; i < iHigh; i++) pBuf[i] |= 0x80; break;
case 2 : // toggle all bits for (i=iLow; i < iHigh; i++) pBuf[i] ^= 0xFF; break;
case 3 : // set to random chars for (i=iLow; i < iHigh; i++) pBuf[i] = (char)(rand() % 256); break;
case 4 : // set NULL chars to (possibly) non-NULL for (i=iLow; i < iHigh; i++) if (!pBuf[i]) pBuf[i] = (char)(rand() % 256); break;
case 5 : // swap adjacent bytes for (i=iLow; i < __max(iHigh-1,iLow); i+= iIter) {char t=pBuf[i]; pBuf[i] = pBuf[i+1]; pBuf[i+1]=t;} break; case 6 : // set to random chars every n-bytes for (i=iLow; i < __max(iHigh-1,iLow); i+= iIter) pBuf[i] = (char)(rand()%256); break;
case 7 : // set bytes to one random char ch=(char)(rand() % 256); for (i=iLow; i < iHigh; i++) pBuf[i] = ch; break;
default: // truncate stream *pcbBuf = iHigh; break; } }}
The sample C# and C++ fuzzing code is available as a ZIP file at the end of this post.
This code is an example of dumb-fuzzing, which is fuzzing with little or no regard for the data structure being manipulated. If you've never performed any kind of fuzz testing in the past, then you will probably find bugs with this simple fuzzing technique. Once you have weeded out the low-hanging bugs, you may need to turn your attention to smarter fuzzers. For example, in theory, this code would find few if any bugs in a PNG parser, because PNG files have a built in check-sum, so if you fuzz a PNG file, you'd have to recalculate the checksum to get decent code coverage.
When I showed this code during my presentation, I urged people to add it to their applications today if they currently don't do fuzz testing, and simply run their applications through their normal testing processes. Within three days of my presentation I received emails from people saying they had found bugs. I have no doubt others did too.
One of the comments I made during the session was,"If you can't spend the time on great fuzzing, fuzz anyway" and adding a "layer of hurt" is a reasonable start.
Please feel free to sound off if you have ideas to help improve the code and let us know what you think, either through email or comments to this post.
I just wrote a post over on the SDL blog about how to get started with fuzzing,...
I like to compare fuzzing to the job of testing bullet proof vests.
See also:
Fuzzing: Brute Force Vulnerability Discovery by Michael Sutton, Adam Greene, Pedram Amini
a {color : #0033CC;} a:link {color: #0033CC;} a:visited.local {color: #0033CC;} a:visited {color : #800080;}
Hello, Michael here... Over the last couple of years, I've released information about various Microsoft