How To Recognize Buffer Overflow Vulnerabilities

From Guidance Share

Jump to: navigation, search

There are many real-world examples of buffer overflows, including many popular "industrial" applications, such as E-mail servers and Web servers. In code, here is a simple, if contrived example:

void example(char *s) 
{
  char buf[1024];
  strcpy(buf, s);
}

int main(int argc, char **argv) 
{
  example(argv[1]);
}

Since argv[1] can be of any length, more than 1024 characters can be copied into the variable buf.

Reviewing Managed Code for Buffer Overflow Vulnerabilities

When you review managed code for buffer overflows, focus your review efforts on your code that calls unmanaged code through the P/Invoke or COM interop layers. Managed code itself is significantly less susceptible to buffer overflows because array bounds are automatically checked whenever an array is accessed. As soon as you call a Win32 DLL or a COM object, you should inspect the API calls closely.

The following process helps you to locate buffer overflow vulnerabilities:

1. Locate calls to unmanaged code. Scan your source files for System.Runtime.InteropServices which is the namespace name used when you call unmanaged code.

2. Check the string parameters passed to unmanaged APIs. These parameters are a primary source of buffer overflows. Check that your code checks the length of any input string to verify that it does not exceed the limit defined by the API. If the unmanaged API accepts a character pointer, you may not know the maximum allowable string length unless you have access to the unmanaged source. A common vulnerability is shown in the following code fragment:

void SomeFunction( char *pszInput )
{
  char szBuffer[10];
  // Look out, no length checks. Input is copied straight into the buffer
  // Should check length or use strncpy.
  strcpy(szBuffer, pszInput);
  . . .
}

Buffer overflows can still occur if you use strncpy because it does not check for sufficient space in the destination string and it only limits the number of characters copied. If you cannot inspect the unmanaged code because you do not own it, rigorously test the API by passing in deliberately long input strings and invalid arguments.

3. Check file path lengths. If the unmanaged API accepts a file name and path, check that your wrapper method checks that the file name and path do not exceed 260 characters. This is defined by the Win32 MAX_PATH constant. Also note that directory names and registry keys can be 248 characters maximum.

4. Check output strings. Check if your code uses a StringBuilder to receive a string passed back from an unmanaged API. Check that the capacity of the StringBuilder is long enough to hold the longest string the unmanaged API can hand back, because the string coming back from unmanaged code could be of arbitrary length.

5. Check array bounds. If you use an array to pass input to an unmanaged API, check that the managed wrapper verifies that the array capacity is not exceeded.

6. Check that your unmanaged code is compiled with the /GS switch. If you own the unmanaged code, use the /GS switch to enable stack probes to detect some kinds of buffer overflows.

Personal tools