Download - 1.Buffer Overflows

Transcript
Page 1: 1.Buffer Overflows

Course 2: Programming Issues,Section 1Pascal Meunier, Ph.D., M.Sc., CISSPUpdated September 28, 2004Developed thanks to the support of Symantec Corporation,NSF SFS Capacity Building Program (Award Number 0113725)and the Purdue e-Enterprise CenterCopyright (2004) Purdue Research Foundation. All rights reserved.

Page 2: 1.Buffer Overflows

Course 2 Learning Plan

Buffer Overflows

Format String Vulnerabilities

Code Injection and Input Validation

Cross-site Scripting Vulnerabilities

Links and Race Conditions

Temporary Files and Randomness

Canonicalization and Directory Traversal

Page 3: 1.Buffer Overflows

Learning objectives

Understand the definition of a buffer overflow

Learn the importance of buffer overflows

Know how buffer overflows happen

Know how to handle strings safely with regular "C"functions

Learn safer ways to manipulate strings and buffers

Page 4: 1.Buffer Overflows

"C" Programming Issues: Outline

Definition

Importance

Examples

Fundamental "C" problems

Survey of unsafe functions

Related Issues: Truncation, Character Encoding

Safe string libraries

Preventing buffer overflows without programming

Lab: Write string manipulation functions

Page 5: 1.Buffer Overflows

Buffer Overflows

a.k.a. "Buffer Overrun"

A buffer overflow happens when a programattempts to read or write data outside of thememory allocated for that data

– Usually affects buffers of fixed size

Special case of memory management and inputvalidation

Page 6: 1.Buffer Overflows

An Important Vulnerability Type

Most Common (over 60% of CERT advisories)

Well understood

Easy to avoid in principle

– Dont use "C" family languages, or be thorough

– Can be tricky (off-by-one errors)

– Tedious to do all the checks properly

Temptation: "I don't need to because I control this data andI *know* that it will never be larger than this"

– Until a hacker figures out how to change it

Page 7: 1.Buffer Overflows

Example Overflow

char B[10];B[10] = x;

Array starts at index zero

So [10] is 11th element

One byte outside buffer was referenced

Off-by-one errors are common and can beexploitable!

Page 8: 1.Buffer Overflows

Other Example

function do_stuff(char * a) { char b[100];... strcpy(b, a); // (dest, source)...}

What is the size of the string located at “a”?

Is it even a null-terminated string?

What if it was "strcpy(a, b);" instead?

– What is the size of the buffer pointed to by "a"?

Page 9: 1.Buffer Overflows

What happens when memory outside a bufferis accessed?

If memory doesn't exist:

– Bus error

If memory protection denies access:

– Segmentation fault

– General protection fault

If access is allowed, memory next to the buffer canbe accessed

– Heap

– Stack

– Etc...

Page 10: 1.Buffer Overflows

Real Life Example: efingerd.c, v. 1.6.2

int get_request (int d, charbuffer[], u_short len) { u_short i; for (i=0; i< len; i++) { ... } buffer[i] = ‘\0’; return i;}

What is the value of "i" at the end of the loop?

Which byte just got zeroed?

It's tricky even if you try to get things right...

Page 11: 1.Buffer Overflows

Real Life Example: efingerd.c, v. 1.5

CAN-2002-0423static char *lookup_addr(structin_addr in) { static char addr[100]; struct hostent *he; he = gethostbyaddr(...) strcpy (addr, he->h_name); return addr;}

How big is he->h_name?

Who controls the results of gethostbyaddr?

How secure is DNS? Can you be tricked intolooking up a maliciously engineered value?

Page 12: 1.Buffer Overflows

A Typical Stack Exploit

The stack contains:

– Parameters (arguments) to function

– Return Address

– Local variables

– Anything pushed on the stack

addr[100+] overwritesthe return address

addr[0] typicallycontains exploitcode

Return address ischosen to point at exploitcode!

Arguments

Return Address

Low Addresses

High Addresses

Stack

grows

this way

addr[99]

addr[0]

Page 13: 1.Buffer Overflows

Fundamental "C" Problems

You can't know the length of buffers just from apointer

– Partial solution: pass the length as a separate argument

"C" string functions aren't safe

– No guarantees that the new string will be null-terminated!

– Doing all checks completely and properly is tedious andtricky

Page 14: 1.Buffer Overflows

Strlen

What happens when you call strlen on animproperly terminated string?

Strlen scans until a null character is found

– Can scan outside buffer if string is not null-terminated

– Can result in a segmentation fault or bus error

Strlen is not safe to call!

– Unless you positively know that the string is null-terminated...

Are all the functions you use guaranteed to return a null-terminated string?

Page 15: 1.Buffer Overflows

Strcpy

char * strcpy(char * dst, const char* src);

How can you use strcpy safely?

– Set the last character of src to NUL

According to the size of the buffer pointed to by src or a sizeparameter passed to you

Not according to strlen(src)!

Wide char array: sizeof(src)/sizeof(src[0]) -1 is the index ofthe last element

– Check that the size of the src buffer is smaller than orequal to that of the dst buffer

– Or allocate dst to be at least equal to the size of src

Page 16: 1.Buffer Overflows

Strncpy

char * strncpy(char * dst, const char* src, size_t len);

"len" is maximum number of characters to copy

– What is the correct value for len?

Initial answer by most people: size of dst

– If dst is an array, sizeof(dst)

What if src is not NUL-terminated?

– Don't want to read outside of src buffer

– What is the correct value for "len" given that?

Minimum buffer size of dst and src, -1 for NUL byte

If arrays,

– MIN(sizeof(dst), sizeof(src)) - 1

Page 17: 1.Buffer Overflows

Strncpy (Cont.)

Other issue: "dst" is NUL-terminated only if lessthan "len" characters were copied!

– All calls to strncpy must be followed by a NUL-terminationoperation

Page 18: 1.Buffer Overflows

Question

What’s wrong with this?

function do_stuff(char * a) { char b[100];... strncpy(b, a, strlen(a));...}

Page 19: 1.Buffer Overflows

Question Answer

What’s wrong with this?

function do_stuff(char * a) { char b[100];... strncpy(b, a, strlen(a));...}

The string pointed to by "a" could be larger thanthe size of "b"!

Page 20: 1.Buffer Overflows

Question

What’s wrong with this?

function do_stuff(char * a) { char *b;...

b = malloc(strlen(a)+1); strncpy(b, a, strlen(a));...}

Page 21: 1.Buffer Overflows

Question Answer

What’s wrong with this?

function do_stuff(char * a) { char *b;...

b = malloc(strlen(a)+1); strncpy(b, a, strlen(a));...}

Are you absolutely certain that the string pointed toby "a" is NUL-terminated?

Page 22: 1.Buffer Overflows

Strlcpy

size_t strlcpy(char *dst, const char *src, size_t size);

Guarantees to null-terminate string pointed to by "dst"if "size">0

The rest of the destination buffer is not zeroed as forstrncpy, so better performance is obtained

"size" can simply be size of dst (sizeof if an array)

– If all functions are guaranteed to null-terminate strings, then itis safe to assume src is null-terminated

– Not safe if src is not null-terminated!

See http://www.courtesan.com/todd/papers/strlcpy.html forbenchmarks and more info

– Used in MacOS X, OpenBSD and more (but not Linux)

Page 23: 1.Buffer Overflows

Note on Strlcpy

As the remainder of the buffer is not zeroed, therecould be information leakage

Page 24: 1.Buffer Overflows

Corrected Efinger.c (v.1.6)

sizeof is your friend, when you can use it (if anarray)

static char addr[100];he = gethostbyaddr(...);if (he == NULL) strncpy(addr, inet_ntoa(in),sizeof(addr));else strncpy(addr, he->h_name,sizeof(addr));

What is still wrong?

Page 25: 1.Buffer Overflows

Corrected Efinger.c (v.1.6)

Notice that the last byte of addr is not zeroed, sothis code can produce non-NUL-terminated strings!

static char addr[100];he = gethostbyaddr(...);if (he == NULL) strncpy(addr, inet_ntoa(in),sizeof(addr));else strncpy(addr, he->h_name,sizeof(addr));

Page 26: 1.Buffer Overflows

Strcat

char * strcat(char * s, const char * append);

String pointed to by "append" is added at the endof the string contained in buffer "s"

No check for size!

– Need to do all checks beforehand

– Example with arrays:

if (sizeof(s)-strlen(s)-1 >= strlen(append)) strcat(s, append);

Need to trust that "s" and "append" are NUL-terminated

– Or set their last byte to NUL before the checks and call

Page 27: 1.Buffer Overflows

Strncat

char * strncat(char * s, const char * append, size_tcount);

No more than "count" characters are added, andthen a NUL is added

Correct call is complex:

– strncat(s, append, sizeof(s)-strlen(s)-1)

Not a great improvement on strcat, because you still needto calculate correctly the count

– And then figure out if the string was truncated

Need to trust that "s" and "append" are NUL-terminated

– Or set their last byte to NUL before the checks and call

Page 28: 1.Buffer Overflows

Strlcat

size_t strlcat(char *dst, const char *src, size_t size);

Call semantics are simple:

– Strlcat(dst, src, dst_len);

– If an array:

strlcat(dst, src, sizeof(dst));

Safety: safe even if dst is not properly terminated

– Won't read more than size characters from dst whenlooking for the append location

Not safe if src is not properly terminated!

– If dst is large and the buffer for src is small, then it couldcause a segmentation fault or bus error, or copyconfidential values

Page 29: 1.Buffer Overflows

Issues with Truncating Strings

Subsequent operations may fail or open upvulnerabilities

– If string is a path, then it may not refer to the same thing,or be an invalid path

Truncation means you weren't able to do what youwanted

– You should handle that error instead of letting it go silently

Page 30: 1.Buffer Overflows

Truncation Detection

Truncation detection was simplified by strlcpy andstrlcat, by changing the return value

– The returned value is the size of what would have beencopied if the destination had an infinite size

if this is larger than the destination size, truncation occurred

Source still needs to be NUL-terminated

Inspired by snprintf and vsprintf, which do the same

However, it still takes some consideration to makesure the test is correct:

– if (strlcpy(dest, src, sizeof(dest)) >=sizeof(dest)) goto toolong;

Page 31: 1.Buffer Overflows

Multi-Byte Character Encodings

Handling of strings using variable-width encodingsor multi-byte encodings is a problem

– e.g., UTF-8 is 1-4 bytes long

How long is the string?

– In bytes

– In characters

Overflows are possible if size checks do notproperly account for character encoding!

.NET: System.String supports UTF-16

– Strings are immutable - no overflow possible there!

Page 32: 1.Buffer Overflows

Safestr

Free library available at: http://zork.org

Features:

– Works on UNIX and Windows

– Buffer overflow protection

– String format protection

– "Taint-tracking" (à la Perl's taint mode)

Limitations and differences:

– Does not handle multi-byte characters

– License: binaries must reproduce a copyright notice

– NUL characters have no special meaning

– Must use their library functions all the time (butconversion to regular "C" strings is easy)

Page 33: 1.Buffer Overflows

Microsoft Strsafe

Null-termination guaranteed

Option for using either number of characters orbytes (for Unicode character encoding), anddisallowing the other

Option to treat truncation as a fatal error

Define behavior upon error

– Output buffer set to "" or filled

Option to prevent information leaks

– Pad rest of buffer

However, correct calculations still needed

– e.g., wcsncat requires calculating the remaining space inthe destination string...

Page 34: 1.Buffer Overflows

Future Microsoft

Visual Studio 2005 will have a new series of safestring manipulation functions

– strcpy_s()

– strncpy_s()

– strncat_s()

– strlen_s()

– etc...

http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dncode/html/secure05202002.asp

Visual Studio 2005 (as of Beta 1) by default issuesdeprecation warnings on strcpy, strncpy, etc… Saygoodbye to your old friends, they're too dangerous!

Page 35: 1.Buffer Overflows

Other Unsafe Functions: sprintf family

int sprintf(char *s, const char *format, /* args*/ ...);

– Buffer "s" can be overflowed

int snprintf(char *s, size_t n, const char *format,/* args*/ ...);

– Does not guarantee NUL-termination of s on someplatforms (Microsoft, Sun)

– MacOS X: NUL-termination guaranteed

– Which is it on the class server? Check with "mansprintf"

int vsprintf(char * str, const char * format, va_listap);

– Buffer "str" can be overflowed

Page 36: 1.Buffer Overflows

Gets, fgets

char * gets(char *str);

– Buffer "str" can be overflowed

char * fgets(char * str, int size, FILE * stream);

– Buffer "str" is not NUL-terminated if an I/O error occurs

– If an error occurs, returns NULL

– If end-of-file occurs before any characters are read,returns NULL also (and buffer is unchanged)

– Callers must use feof(3) and ferror(3) to determine whichoccurred.

Page 37: 1.Buffer Overflows

Conclusion

Buffer sizes should be passed as a parameter withevery pointer

– Applies to other buffer manipulations besides strings

Need simple truncation detection

Page 38: 1.Buffer Overflows

Preventing Buffer Overflows WithoutProgramming

Idea: make the heap and stack non-executable

– Because many buffer overflow attacks aim at executingcode in the data that overflowed the buffer

Doesn't prevent "return into libc" overflow attacks

– Because the return address of the function on the stackpoints to a standard "C" function (e.g., "system"), thisattack doesn't execute code on the stack

e.g., ExecShield for Fedora Linux (used to beRedHat Linux)

Page 39: 1.Buffer Overflows

Canaries on a Stack

Add a few bytes containing special values betweenvariables on the stack and the return address.

Before the function returns, check that the valuesare intact.

– If not, there's been a buffer overflow!

Terminate program

If the goal was a Denial-of-Service then it stillhappens

– At least the machine is not compromised

If the canary can be read by an attacker, then abuffer overflow exploit can be made to rewrite them

– e.g., see string format vulnerabilities

Page 40: 1.Buffer Overflows

Canary Implementations

StackGuard

Stack-Smashing Protector (SSP)

– Formerly ProPolice

– gcc modification

– Used in OpenBSD

– http://www.trl.ibm.com/projects/security/ssp/

Windows: /GS option for Visual C++ .NET

These can be useful when testing too!

Page 41: 1.Buffer Overflows

Protection Using Virtual Memory Pages

Page: A chunk (unit) of virtual memory

POSIX systems have three permissions for eachpage.

– PROT_READ

– PROT_WRITE

– PROT_EXEC

Idea: manipulate and enforce these permissionscorrectly to defend against buffer overflows

– Make injected code non-executable

Page 42: 1.Buffer Overflows

OpenBSD

PROT_* purity (correct enforcement of permissionsfor pages in VM system; i386 and PowerPCarchitectures limit this)

W^X (write permission is exclusive of execute)

– Data shouldn't need to be executed!

– Limits also self-modifying (machine) code

.rodata (read-only data is enforced to be read-onlyon a separate page)

Page 43: 1.Buffer Overflows

Windows Execution Protection

"NX" (No Execute)

Windows XP service pack 2 feature

– Somewhat similar to POSIX permissions

Requires processor support

– AMD64

– Intel Itanium

Page 44: 1.Buffer Overflows

Question

A buffer overflow is not exploitable if:

a) It happens in the heap

b) It happens in the stack

c) It happens where memory is not executable

d) None of the above

Page 45: 1.Buffer Overflows

Question

A buffer overflow is not exploitable if:

a) It happens in the heap

b) It happens in the stack

c) It happens where memory is not executable

d) None of the above

Page 46: 1.Buffer Overflows

Question

Making some memory locations non-executableprotects against which variants of buffer overflowattacks?

a) Code in the overwritten data

b) Return into libc

c) Variable corruption

Page 47: 1.Buffer Overflows

Question

Making some memory locations non-executableprotects against which variants of buffer overflowattacks?

a) Code in the overwritten data

b) Return into libc

c) Variable corruption

Page 48: 1.Buffer Overflows

Buffer Overflow Lab

Create your own safe version of the strlen, strcpy,strcat

– Name them mystrlen, mystrcpy and mystrcat

– Pass buffer sizes for each pointer argument

– Return 0 if successful, and 1 if truncation occurred

Other error codes if you wish

– Make your implementation pass all test cases

int mystrlen(const char *s, size_t s_len);

– In this case, return the string length, not zero or one.

int mystrcpy(char * dst, const char * src, size_t dst_len, size_t src_len);

int mystrcat(char * s, const char * append, size_t s_len, size_t a_len);

Page 49: 1.Buffer Overflows

Things to Ponder

What about 0 as source size? Error or not?

What if “s” is NULL?

What about overlapping buffers? Undefined everytime,or only in certain cases?

What if reach the end in mystrlen?

How efficient to make it -- how many passes at sourcestring are made?

What to check first?

Reuse mystrlen within mystrcpy or mystrcat?

Compare your implementations to strl*, strsafe, safestr,str*_s.

Page 50: 1.Buffer Overflows

Questions or Comments?

Page 51: 1.Buffer Overflows

About These Slides

You are free to copy, distribute, display, and perform the work; and

to make derivative works, under the following conditions.

– You must give the original author and other contributors credit

– The work will be used for personal or non-commercial educational uses

only, and not for commercial activities and purposes

– For any reuse or distribution, you must make clear to others the terms of

use for this work

– Derivative works must retain and be subject to the same conditions, and

contain a note identifying the new contributor(s) and date of modification

– For other uses please contact the Purdue Office of Technology

Commercialization.

Developed thanks to the support of SymantecCorporation

Page 52: 1.Buffer Overflows

Pascal [email protected]:Jared Robinson, Alan Krassowski, Craig Ozancin, TimBrown, Wes Higaki, Melissa Dark, Chris Clifton, GustavoRodriguez-Rivera


Top Related