Error #1: Copying untrusted data
Take a line of code such as the following:

   while (*c != '\\') *p++ = *c++;

What's the problem here? The copy process is limited by the source data, not the destinatioin buffer size.

Copying untrusted data is one of the most prevalent causes of security issues. Buffer overruns, SQL injection and cross-site scripting are all due to input trust issues. Just because the RFC says that an integer value must be within a certain range doesn't mean for a moment that an attacker will follow the RFC!

Buffer Overruns
A buffer overrun occurs when the external data is larger than the destination; overflowing the destination causes the application to change the execution flow to the attacker's code included in the data, usually by trampling on the return address in the stack. C and C++ are by far the most common victims to this kind of attack, because they allow direct access to memory.

Buffer overruns are common - approximately 25 to 30% of the security bulletins being issued across all operating systems involve buffer overruns. They are prevalent because of the quantity of C/C++ code, coupled with the fact that many data structures jump to code. For example, if a v-table can be modified, your server is "owned". The threat is constantly evolving. Stack overruns were once seen as the only threat; now heap-based buffer overruns are becoming prevalent. Even integer overflow attacks can cause buffer overruns.

Here's an example of an integer overflow:

   int concatstring(char*buf1, char* buf2, size_t len1, size_t len2)
   {
      char buf[256];
      if ((len1 + len2) > 256 return -1;
      memcpy(buf, buf1, len1);
      memcpy(buf + len1, buf2, len2);
   }

What if len1 = 0xFFFFFFFE and len2=0x00000102? Then you're going to try and copy large quantities of data into a 100-byte buffer. In this case, all that will happen is an Access Violation, but MS03-008 is an integer overflow bug that can be used to cause a heap overrun and ultimately compromise a system. This type of attack wasn't even conceived of three years ago.

Remedies
One remedy is to enforce less error-prone constructs. For example, the C runtime function gets() is dangerous because there's no way to validate the size of the input. During the WIndows Server 2003 security push, the team created strsafe.h - a library of string library functions that are safer and are available on MSDN. Microsoft has now submitted a set of "safe" string functions (e.g. strcpy_s) to the C standards bodies.

The /GS switch in C++ uses a "canary in a coalmine" approach to check for buffer overruns, but whilst tools like this mitigate against overruns, it's vital to get the code right in the first place. Visual C++ .NET 2003 also swaps the buffers and other variables around, which means you have to create a buffer underrun instead - a much harder proposition.

Another remedy is to use higher-level languages such as C#. For example, in Windows Server 2003, UDDI Server is entirely written in managed code. However, the best defence is to reduce your attack surface - switching a feature off, and running with a lower level of privilege.