Transcript
Page 1: Buffer Overflows James Walden Northern Kentucky University

Buffer Overflows

James Walden

Northern Kentucky University

Page 2: Buffer Overflows James Walden Northern Kentucky University

CSC 666: Secure Software Engineering

Topics

1. What is a Buffer Overflow?

2. Buffer Overflow Examples

3. Program Stacks

4. Smashing the Stack

5. Shellcode

6. Mitigations

Page 3: Buffer Overflows James Walden Northern Kentucky University

CSC 666: Secure Software Engineering

Buffer Overflows

A program accepts too much input and stores it in a fixed length buffer that’s too small.

char A[8];short B=3;

A A A A A A A A B B

0 0 0 0 0 0 0 0 0 3

A A A A A A A A B B

o v e r f l o w s 0

gets(A);

Page 4: Buffer Overflows James Walden Northern Kentucky University

CSC 666: Secure Software Engineering

Buffer Overflow Examples

Morris WormTook down most of Internet in 1988.

Exploited a buffer overflow in fingerd.

Subsequent worms used overflow attacks too.

CVE-2012-4172: Adobe ShockwaveOverflow in Shockwave Player <11.6.8.638

Allows arbitrary remote code execution.

Adobe released patch to fix with 4 other CVEs

Page 5: Buffer Overflows James Walden Northern Kentucky University

CSC 666: Secure Software Engineering

Buffer Overflow Example #1

What’s the mistake in this program?

int main() {

int array[5] = {1, 2, 3, 4, 5};

printf("%d\n", array[5]);}

Program output:

> gcc -o buffer buffer.c

> ./buffer7077876

Page 6: Buffer Overflows James Walden Northern Kentucky University

CSC 666: Secure Software Engineering

Buffer Overflow Example #2

Writing beyond the buffer:int main() { int array[5] = {1, 2, 3, 4, 5}; int i;

for( i=0; i <= 255; ++i ) array[i] = 41;}

Program output: > gcc -o bufferw bufferw.c> ./bufferwSegmentation fault (core dumped)

Page 7: Buffer Overflows James Walden Northern Kentucky University

CSC 666: Secure Software Engineering

What happened to our program?

The buffer overflow:Overwrote memory beyond buffer with 41.

Memory page was not writable by program.

OS terminated prog with segmentation fault.

Do overflows always produce a crash?Most of the time, yes.

Careful attacker can access valid memory.

Page 8: Buffer Overflows James Walden Northern Kentucky University

CSC 666: Secure Software Engineering

Why do we keep making the same mistake?

C/C++ inherently unsafe.

No bounds checking.

Unsafe library functions: strcpy(), sprintf(), gets(), scanf(), etc.

D, Java, Python, Ruby largely immune.C/C++ gains performance by not checking.

Page 9: Buffer Overflows James Walden Northern Kentucky University

CSC 666: Secure Software Engineering

Process Memory Layout

argv, env

stack

heap

bss

data

text

high mem

low mem

Argv/Env: CLI args and environment

Stack: generally grows downwards

Heap: generally grows upwards

BSS: unitialized global data

Data: initialized global data

Text: read-only program code

Page 10: Buffer Overflows James Walden Northern Kentucky University

CSC 666: Secure Software Engineering

Memory Layout Example

/* data segment: initialized global data */int a[] = { 1, 2, 3, 4, 5 };/* bss segment: uninitialized global data */int b;

/* text segment: contains program code */int main(int argc, char **argv) /* ptr to argv */{ /* stack: local variables */ int *c; /* heap: dynamic allocation by new or malloc */ c = (int *)malloc(5 * sizeof(int));}

Page 11: Buffer Overflows James Walden Northern Kentucky University

CSC 666: Secure Software Engineering

Program Stack Layout

b() {

}

a() {

b();

}

main() {

a();

}

Unallocated

Stack Frame for b()

Stack Frame for a()

Stack Frame for main()

High Memory

Low Memory

Page 12: Buffer Overflows James Walden Northern Kentucky University

CSC 666: Secure Software Engineering

Stack Frames

A function call produces a stack frame.– Return address of the caller.– Actual arguments used in function call.– Local variables.

Register EBP points to current frame. Stack frame is deallocated on return.

Page 13: Buffer Overflows James Walden Northern Kentucky University

CSC 666: Secure Software Engineering

C Calling Convention

1. Push params on stack in reverse order.Parameter #N

Parameter #1

2. Issue a call instruction.1. Pushes address of next instruction (the

return address) onto stack.

2. Modifies EIP to point to start of function.

Page 14: Buffer Overflows James Walden Northern Kentucky University

CSC 666: Secure Software Engineering

Stack before Function Executes

Frame Pointer

Stack Pointer

old stack frame

parameter #N

parameter #1

return address

Page 15: Buffer Overflows James Walden Northern Kentucky University

CSC 666: Secure Software Engineering

Function Initialization

1. Function pushes FP (%ebp) onto stack.pushl %ebp

2. Sets FP to current SP.Allows function to access params as fixed indexes from frame pointer.

movl %esp, %ebp

3. Reserves stack space for local vars.subl $12, %esp

Page 16: Buffer Overflows James Walden Northern Kentucky University

CSC 666: Secure Software Engineering

Stack at Function Start

Frame Pointer

Stack Pointer

old stack frame

parameter #N

parameter #1return addressold FP

local vars

Page 17: Buffer Overflows James Walden Northern Kentucky University

CSC 666: Secure Software Engineering

Function Return

1. Stores return value in %eax.movl $1, %eax

2. Restores stack and frame pointers.movl %esp, %ebppopl %ebp

3. Pops return address off stack and transfers control to that address. ret

Page 18: Buffer Overflows James Walden Northern Kentucky University

CSC 666: Secure Software Engineering

Controlling Execution

Let’s make the program an infinite loop by changing the return value to start of main().

(gdb) disassemble mainDump of assembler code for main:0x080483c1 <main+0>: push %ebp0x080483c2 <main+1>: mov %esp,%ebp0x080483c4 <main+3>: call 0x804839c <printInput>0x080483c9 <main+8>: leave0x080483ca <main+9>: ret

Page 19: Buffer Overflows James Walden Northern Kentucky University

CSC 666: Secure Software Engineering

Sending a non-ASCII Value

void main() {

char addr[44]; int i; for( i=0; i<=40; i+=4 ) *(long *) &addr[i]=0x080483c1; puts(addr);}

Page 20: Buffer Overflows James Walden Northern Kentucky University

CSC 666: Secure Software Engineering

Does it work?

(./address; cat) | ./overflowinput1input1input2input2input3Segmentation fault (core dumped)

Page 21: Buffer Overflows James Walden Northern Kentucky University

CSC 666: Secure Software Engineering

Code and Data

What’s the difference between code and data?

Page 22: Buffer Overflows James Walden Northern Kentucky University

CSC 666: Secure Software Engineering

Code Injection

Use a two step process:1. Use buffer overflow to write machine

code (shellcode) onto stack.

2. Rewrite return address to point to machine code on the stack.

Program will do whatever we tell it to do in those machine instructions.

Page 23: Buffer Overflows James Walden Northern Kentucky University

CSC 666: Secure Software Engineering

Shellcode

Shellcode is machine code that starts a command shell. With a shell, you can run any command.

Page 24: Buffer Overflows James Walden Northern Kentucky University

CSC 666: Secure Software Engineering

Shellcode

Shellcode in C.int main() { char *name[2]; name[0] = "/bin/sh"; name[1] = 0x0; execve(name[0], name, 0x0);}

Running the program.> gcc –ggdb –static –o shell shellcode.c> ./shellsh-3.00$ exit

Page 25: Buffer Overflows James Walden Northern Kentucky University

CSC 666: Secure Software Engineering

From C to Machine Language

char shellcode[] ="\xeb\x1f\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89\x46\x0c\xb0\x0b""\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31\xdb\x89\xd8\x40\xcd""\x80\xe8\xdc\xff\xff\xff/bin/sh";

void main() { int *ret; ret = (int *)&ret + 2; (*ret) = (int)shellcode;}

> gcc -o testsc2 testsc2.c> ./testsc2sh-3.00$ exit

Page 26: Buffer Overflows James Walden Northern Kentucky University

CSC 666: Secure Software Engineering

Writing an Exploit

1. Construct shellcode to inject.2. Find exploitable buffer in a program.3. Estimate address of buffer.4. Run program with an input that:

1. Injects shellcode into stack memory.2. Overwrites return address with address of

your shellcode.

Page 27: Buffer Overflows James Walden Northern Kentucky University

CSC 666: Secure Software Engineering

Improving the Odds

Determining the correct address of your shellcode is difficult.What if you could use multiple addrs?

Pad buffer with NOP instructions preceding the shellcode.If function returns anywhere in NOP pad, it will continue executing until it executes the shellcode.

Page 28: Buffer Overflows James Walden Northern Kentucky University

CSC 666: Secure Software Engineering

Overflow Exploits w/o the Stack

Overflows can exist in other segments.

Only the stack has return addresses.

Must rewrite other addressesFunction pointers

Longjmp buffers

Or alter security critical variables.

Page 29: Buffer Overflows James Walden Northern Kentucky University

CSC 666: Secure Software Engineering

Buffer Overflow Mitigations

1. Use language with bounds checking.

2. Do your own bounds checking.

3. Avoid unsafe functions.

4. Use safe functions securely.

5. Operating system defenses.

6. Compiler-based defenses.

Page 30: Buffer Overflows James Walden Northern Kentucky University

CSC 666: Secure Software Engineering

Languages with Bounds Checking

High-level languages do bounds checks Java JavaScript OCaml Python Ruby Scheme Smalltalk

C variants CCured Cyclone D

Page 31: Buffer Overflows James Walden Northern Kentucky University

CSC 666: Secure Software Engineering

Bounds CheckingCheck input length before copying into buffer.

int myfunction(const char *str) { char buf[1024];

/* strlen() doesn’t count NULL */

if (strlen(str) >= sizeof(buf)) { /* str too long */ exit(1); }}

Page 32: Buffer Overflows James Walden Northern Kentucky University

CSC 666: Secure Software Engineering

Unsafe Functions: Input

gets(char *s)Always an overflow. Cannot be checked.

Use fgets(char *s, int size, FILE *stream);

scanf(const char *fmt, …)Similar: _tscanf, wscanf, sscanf, fscanf, …

Use of “%s” format allows overflow.

Use “%Ns” to limit length of input.

Page 33: Buffer Overflows James Walden Northern Kentucky University

CSC 666: Secure Software Engineering

Unsafe Functions: strcat

strcpy(char *dst, char *src)Similar: wscpy, wcscpy, mbscpy

Overflow if dst smaller than src.

strncpy(char *dst, const char *src, size_t n)Similar: _tcsncpy, wcscpyn, _mbsncpy, …

No NULL termination if src >= dst.

Page 34: Buffer Overflows James Walden Northern Kentucky University

CSC 666: Secure Software Engineering

Bounded Function Pitfalls

1. Destination buffer overflows because bound depends on size of source data, not destination buffer.

2. Destination buffer left without null terminator, often as result of off-by-one error.

3. Destination buffer overflows because its bound is specified as the total size of the buffer, rather than space remaining.

4. Programs writes to arbitrary location in memory as destination buffer is not null-terminated and function begins writing at location of first null in destination buffer.

Page 35: Buffer Overflows James Walden Northern Kentucky University

CSC 666: Secure Software Engineering

Safe String Libraries

UNIX LibrariesC

BstrlibMT-SafeSafeStrstrlcpy(), strlcat()Vstr

C++std::string (STL)

Windows LibrariesC

Safe CRTstrlcpy(), strlcat()StrSafe

C++CString (MFC)Safe C++std::string (STL)

Page 36: Buffer Overflows James Walden Northern Kentucky University

CSC 666: Secure Software Engineering

strlcpy() and strlcat()

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

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

Size is max size of dest buffer (not maximum number of chars to copy), including NULL.

Destination buffer always NULL terminated Return how much space would be required in

destination buffer to perform operation. BSD-style open source license.

Page 37: Buffer Overflows James Walden Northern Kentucky University

CSC 666: Secure Software Engineering

Character Sets

Chars represented using encoding forms that map code points to printable chars.

Fixed Width ISO-8859-1 UTF-32

Variable Width UTF-8 UTF-16 (Java, .NET)

Character Encoding Code Point

s ISO-8859-1UTF-8

7373

ÿ ISO-8859-1UTF-8

FFC3 BF

Page 38: Buffer Overflows James Walden Northern Kentucky University

CSC 666: Secure Software Engineering

Wide Characters

C/C++ char contains 1-byte characters wchar_t is 2-byte, 4-byte on some platforms

Java and .NET strings UTF-16

Buffer Overflow issues Mixing up different character-set string types. Are sizes measured in bytes or characters?

Page 39: Buffer Overflows James Walden Northern Kentucky University

CSC 666: Secure Software Engineering

C++ String Dangers

Using C-style strings with cinchar username[16];

cin >> username;

The [] operator does no bounds checking.

Converting from C++ to C-style strings:string::data() output is not NULL terminated.

string::c_str() output is NULL terminated.

Page 40: Buffer Overflows James Walden Northern Kentucky University

CSC 666: Secure Software Engineering

Dealing with Overly Long Inputs

Prevent operation with an error message. Possibly exit program too.

Truncate input to allowed length. Can lead to null-termination errors. Can cause input to be misinterpreted later.

Resize the buffer to accomodate input. Limit resizing to avoid memory DoS.

Page 41: Buffer Overflows James Walden Northern Kentucky University

CSC 666: Secure Software Engineering

Dynamic vs. Static Allocation

Static Simple Easy to track buffer size for bounds checks. Inflexible. Limited options if size is too small. Waste memory if size is too large.

Dynamic Complex Manually tracking buffer sizes can lead to overflows due

to stale size data. Flexible Can lead to memory exhaustion if no limits. Possibility of use after free and double free errors.

Page 42: Buffer Overflows James Walden Northern Kentucky University

CSC 666: Secure Software Engineering

Non-executable Stack

Memory protection prevents exploit code from being executed.– Some applications execute code on the stack/heap.– x86 arch doesn’t have exec bit in page tables.– Segment limits can divide memory into two parts:

executable and non-executable.• Keep program code in low memory.• Keep data and stack in high memory.• Coarse-grained.

– NX Technology• Exec bit for page tables.• Added in AMD64 and newer Intel P4 processors.• Only works in PAE 64-bit page table format.

Page 43: Buffer Overflows James Walden Northern Kentucky University

CSC 666: Secure Software Engineering

Return-Oriented Programming

ROP transfers control to code that already exists in memory.

Put function arguments on stack.Change return address to that function.libc has functions to start a shell.Allows exploit even if stack non-executable.

Sophisticated ROP attacks create multiple stack frames to run multiple functions that are in memory.

Page 44: Buffer Overflows James Walden Northern Kentucky University

CSC 666: Secure Software Engineering

Address Randomization

Randomize layout of memory space Stack location. Shared library locations. Heap location.

PIE: Position Independent Executable Default format: binary compiled to work at an address

selected when program was compiled. Gcc can compile binaries to be freely relocatable

throughout address space. gcc flags: -fpie –pie Program loaded at different address for each invocation.

Page 45: Buffer Overflows James Walden Northern Kentucky University

CSC 666: Secure Software Engineering

Defence: Stackguard

Compiler extension for gcc code must be compiled w/ Stackguard

Detects altered return address before function returns adds “canary” word to stack must overwrite canary to change return addr use random canary words for each function to

avoid guessing attacks

Page 46: Buffer Overflows James Walden Northern Kentucky University

CSC 666: Secure Software Engineering

Stackguard Stack Layout

Frame Pointer Stack Pointer

old frame

param1

param2

old PC

canary word

old FP

local vars

Page 47: Buffer Overflows James Walden Northern Kentucky University

CSC 666: Secure Software Engineering

Stackguard Effectiveness

Code dependencies are dynamic libraries stackguarded?

Compatibility Recompiled entire RedHat Linux system.

Small performance cost canary insert and check overhead on each call

Protects against future stack attacks. Similar tools:

gcc -fstack-protector flag Visual Studio 2005

Page 48: Buffer Overflows James Walden Northern Kentucky University

CSC 666: Secure Software Engineering

Buffer Overflow: Key Points

Buffer overflow attacks. C/C++ perform no bounds checking. There is no difference btw code and data. Smashing the stack.

Mitigating buffer overflows. Use a language with bounds checking. Check your own bounds in C/C++. Use safe functions, string libraries.

Page 49: Buffer Overflows James Walden Northern Kentucky University

References

1. Aleph Null, “Smashing the Stack for Fun and Profit,” Phrack 49, 1996.2. Brian Chess and Jacob West, Secure Programming with Static Analysis, Addison-

Wesley, 2007.3. Johnathan Bartlett, Programming from the Ground Up, Bartlett Publishing, 2004.4. Matt Conover & w00w00 Security Team, “w00w00 on Heap Overflows,”

http://www.w00w00.org/files/articles/heaptut.txt5. Mark Graff and Kenneth van Wyk, Secure Coding: Principles & Practices, O’Reilly,

2003.6. Horizon, “Bypassing Non-executable Stack Protection on Solaris,”

http://packetstormsecurity.nl/groups/horizon/stack.txt7. Greg Hoglund and Gary McGraw, Exploiting Software: How to Break Code,

Addison-Wesley, 2004.8. Michael Howard and David LeBlanc, Writing Secure Code, 2nd edition, Microsoft

Press, 2003.9. Koziol, et. al, The Shellcoder’s Handbook: Discovering and Exploiting Security

Holes, Wiley, 2004.10. Robert C. Seacord, Secure Coding in C and C++, Addison-Wesley, 2006.11. John Viega and Gary McGraw, Building Secure Software, Addison-Wesley, 2002.12. David Wheeler, Secure Programming for UNIX and Linux HOWTO,

http://www.dwheeler.com/secure-programs/Secure-Programs-HOWTO/index.html, 2003.


Top Related