SECSYM: Security Symposium III

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.