250 likes | 264 Views
Buffer Overflow is a security issue where a program overwrites data outside allocated memory bounds. This article discusses the risks of buffer overflow, common related problems, and strategies for prevention. Examples in C and C++ illustrate static and dynamic buffer allocation, unsafe string functions, and pitfalls to avoid.
E N D
Buffer Overflow Chapter 6
Buffer Overflow • Buffer Overflow occurs when the program overwrites data outside the bounds of allocated memory • It was one of the first exploited security issues (Morris 1988) • Many buffer overflow problems are related to string manipulations • In the year 2000, 50% of CERT warnings were related to buffer overflow. • Any language like C and C++ that does not enforce memory safety and type safety is a potential risk to buffer overflow.
Example void trouble () { int a = 32; char line[128]; gets(line); }
Buffer Over Attack return address a line return address a line return address a line
Buffer Allocation Strategies • Static • Use a fixed size allocation. Alter the program behavior if the data does not fit or truncate the data. • Buffer overflow mistakes can be checked by automated tools or humans. • Dynaminc • Resize the buffer as needed • More difficult to check for code problems. • Mixing static and dynamic allocation can cause problems.
Static Allocation Example #define BUFSIZE 1024 #define SUCCESS 0 int main(int argc, char **argv) { char str[BUFSIZE]; int len; len = snprintf(str, BUFSIZE, “%S(%d)”, argv[0], argc); printf(“%s\n”, str); if (len >= BUFSIZE) { printf(“length truncated (from %d)\n”, len); } return SUCCESS; }
Dynamic Allocation Example #define BUFSIZE 1024 #define SUCCESS 0 int main(int argc, char **argv) { char *str; int len; if ((str = (char *)malloc(BUFSIZE)) == NULL) { return -1; } len = snprintf(str, BUFSIZE, “%S(%d)”, argv[0], argc); if (len >= BUFSIZE) { free(str); if ((str = (char *)malloc(len + 1)) == NULL) { return -1; } snprintf(str, len+1, “%S(%d)”, argv[0], argc); } printf(“%s\n”, str); free(str); str = NULL; return SUCCESS; }
Dynamic Allocation • Issues • More difficult to manage. • Can introduce memory leaks • Use-after-free • Double free • Solutions • Enforce Null-After-Free • Tracking buffer sizes
Tracking Buffer Sizes • C and C++ do not track buffer sizes • Programmers have to do it on their own • Some languages track buffer sizes. • Errors in tracking buffer sizes could lead to buffer overflow conditions
Unsafe String functions • gets() • scanf() • strcpy() • sprintf()
gets() and friends • gets() reads input stream into a buffer until a new line is found. • Very dangerous function and it should be avoided. • To use gets() you must be 100% sure you trust the input. • C++ >> operator repeated the same mistake as gets().
scanf() and friends • %s specifier in the format string can cause a buffer overflow condition. • scanf() can be used safely if the format specifier properly bounds the amount of data to be read.
strcpy() and friends • strcpy() copies one buffer to another until a null character is found. • If source buffer is larger than destination or source is not null terminated buffer overflow condition may occur.
sprintf() and friends • To avoid buffer overflow the destination buffer must be large enough to accommodate the combination of all source arguments. • %s can be a variable string length and can cause buffer overflow. • Bounded format string can make sprintf() safer to use.
Risk of reimplementation • Programmers should be careful not to duplicate the same mistakes made in the dangerous standard C functions. • Implementation of similar functions can be harder to detect.
Example of reimplementaion void get_word(char *word) { int c; while (isspace(c = getchar())) {} while (c = getchar()) { if (c == -1) { break; } if (isspace(c)) { *word = ‘\0’; break; } *word = c; word++; } }
strncpy() and strncat() pitfalls • The size incorrectly specified • char s1[S1_SIZE], s2[S2_SIZE] • strncpy (s1, s2, S2_SIZE) • strncat (s1, s2, S1_SIZE) • strncpy does not always null terminate the destination. • strncat destination and source must be terminated.
Truncation Errors • A truncation after copying a buffer can cause unpredictable problems. • Some examples • Check access control on a file then copy the file to another smaller buffer. The new buffer points to another file. • Check the validity of a host name then copy to a smaller buffer. New buffer now contains a new hostname.
Maintaining null terminator • Many libc functions rely on the null char at the end of a string. • Examples: strlen, strcpy, strncpy, strncat • Some functions that are designed to operate on memory blocks may not null terminate a string • Examples: fread(), recvmsg(), strncpy() • Programmers must ensure strings are null terminated to avoid runtime errors and buffer overflows. • Catching errors due to failure of null terminating a string is very difficult and may not be possible until the program is running in production. • One way to ensure strings are terminated is to explicitly add a null char at the end of a buffer.
Character Sets • Today several character sets exist and are used for input and output. • ISO-8859-1, UTF-8, UTF-16 and UTF-32 are some of the most commonly used. • ISO-8859-1 and UTF-32 are fixed-width encoding. • UTF-16 and UTF-8 are variable-width encoding. • New type wchar_t was introduced to handle other character sets.
Characters and buffer overflow • Mismatch between the string length and the number of bytes in the buffer can cause buffer overflow issues. • Operation that expects bounds in bytes is passed bound in characters or vice-versa • Functions that convert from one encoding to another magnify the problem.
Format Strings • When a variable string is passed as a format string to a function that can cause a format string vulnerability. while (fgets(buf, sizeof buf, f)) { lreply(200, buf) ... } void lreply(int n, char *fmt, ... ) { char buf[BUFSIZ]; ... vsnprintf(buf, sizeof buf, fmt, ap); ... }
Format Strings • Most format string vulnerabilities are caused by misuse of functions that require a format string • Example: printf(str) instead of printf (“%s”, str) • Read data from the stack by passing formatting characters • Use %n directive to write arbitrary positions in memory.
Preventing Format String exploits • Always pass a static format string • If static string is too restrictive choose from a list of format strings • If a format string must be read from input perform input validation.
Better String Classes and Libraries • std::string class in STL • Microsoft CString in ATL/MFC • Vstr library • Designed to work with readv() and writev() • SafeStr library