Chapter 6 Buffer Overflow. Buffer Overflow occurs when the program overwrites data outside the...

Preview:

Citation preview

Chapter 6

Buffer Overflow

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

line areturnaddress

line areturnaddress

line areturnaddress

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 0int 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 0int 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