ather than using script, many Internet developers use Microsoft's Internet Server API (ISAPI) code because it is so fast. ISAPI code is usually C/C++ code, which Web servers use to run high-performance portions of Web sites. However, like many applications written in C/C++, it can have serious security bugsbugs that could lead to your system being compromised by a destructive worm or a hacker. I've been tracking ISAPI security practices and have found that people tend to make two crucial mistakes.
Mistake #1Overlooking the IPP and Index Server Buffer Overrun
Most ISAPI calls are written in C/C++, which means they are just one notch above the metal and have direct access to memory and pointers. Buffer overruns in C/C++ are notorious, and two famous buffer overruns have recently been found in two ISAPI applications: the Internet Printing Protocol ISAPI and the Index Server ISAPI.
The Internet Printing Protocol Buffer Overrun
The Internet Printing Protocol (IPP) buffer overrun, explained in "Unchecked Buffer in ISAPI Extension Could Enable Compromise of IIS 5.0 Server" from Microsoft TechNet, was a very simple bug that I have seen on a number of occasions. It occurs when a programmer mixes up the number of bytes and the number of characters in a Unicode string.
Here's a source code sample that leads to the buffer overrun. Can you find the problem?
#define UNICODE
TCHAR g_szName[MAX_NAME+1];
BOOL getName(EXTENSION_CONTROL_BLOCK *pECB) {
DWORD dwSize = sizeof (g_szName);
char szName [MAX_NAME + 1];
if (pECB->GetServerVariable (pECB->ConnID,
"SERVER_NAME",
szName,
&dwSize)) {
Give up? Look at the declarations of g_szName and szName, both are MAX_NAME+1 bytes in size right? Wrong. szName is MAX_NAME+1 characters in size and g_szName is MAX_NAME+1 Unicode characters in size. In other words, g_szName is twice the size of szName. If you look at the winnt.h file, you'll see that TCHAR is in fact typedef'd to a WCHAR when UNICODE is defined.
#ifdef UNICODE
typedef WCHAR TCHAR, *PTCHAR;
#else
typedef char TCHAR, *PTCHAR;
#endif
The problem is that the last argument to the ISAPI function GetServerVariable is the size of the buffer and the code incorrectly tells GetServerVariable that the buffer is twice as big as it really is. Oops! An attacker can set the HOST: header to anything he likes, and the code will copy the buffer into a szName buffer.
Here's one way to remedy the code:
#define UNICODE
TCHAR g_szName[MAX_NAME+1];
BOOL getName(EXTENSION_CONTROL_BLOCK *pECB) {
char szName [MAX_NAME + 1];
DWORD dwSize = sizeof (szName);
if (pECB->GetServerVariable (pECB->ConnID,
"SERVER_NAME",
szName,
&dwSize)) {
Always double-check any function that uses Unicode strings and takes the size of the string or buffer as an argument. They are great targets during code reviews.
The Index Server Buffer Overrun
The Index Server buffer overrun, which was partially to blame for the Code Red worm (explained in "Unchecked Buffer in Index Server ISAPI Extension Could Enable Web Server Compromise"), was a simple indexing mistake. The code walked over a string in a loop that was writing data to each element. The loop index was too big, so it wrote past the end of the buffer. Most programmers look for certain dangerous functions when searching for buffer overruns but overlook something as simple as a loop that writes to a buffer.
The core lesson: Double-check your ISAPI applications and filters for buffer overruns.
|