memory corruption james walden northern kentucky university csc 666: secure software engineering

70
Memory Corruption James Walden Northern Kentucky University CSC 666: Secure Software Engineering

Upload: emma-lloyd

Post on 11-Jan-2016

216 views

Category:

Documents


1 download

TRANSCRIPT

Page 1: Memory Corruption James Walden Northern Kentucky University CSC 666: Secure Software Engineering

Memory Corruption

James Walden

Northern Kentucky University

CSC 666: Secure Software Engineering

Page 2: Memory Corruption James Walden Northern Kentucky University CSC 666: Secure Software Engineering

CSC 666: Secure Software Engineering

Topics

1. Buffer Overflows

2. Stack Overflows

3. Heap Overflows

4. Use after Free

5. Memory Corruption Mitigations

6. Return Oriented Programming

7. Writing Secure Code

Page 3: Memory Corruption James Walden Northern Kentucky University CSC 666: Secure Software Engineering

CSC 666: Secure Software Engineering

Memory Corruption

Memory corruption occurs when contents of a memory location are modified in a way unintended by the programmer. Modifications can result from

Buffer overflows Format string attacks (%n) Use after free

Memory corruption vulnerabilities can result in Execution of attacker-supplied code. Attacker hijacking of program control flow. Alteration of program data. Information leak.

Page 4: Memory Corruption James Walden Northern Kentucky University CSC 666: Secure Software Engineering

CSC 666: Secure Software Engineering

Buffer Overflows

buffer: limited contiguously allocated set of memory. static: char buffer[32] dynamic: malloc(), new

What happens when you attempt to access an element beyond the end of the buffer? Bounds checking prevents such accesses in most

languages like Python, Ruby, and Java. But in C, C++, Objective C, Forth, and assembly large

inputs can overflow the buffer, overwriting adjacent data in memory.

Page 5: Memory Corruption James Walden Northern Kentucky University CSC 666: Secure Software Engineering

C Strings

C strings terminated with \0 character. Many operating systems and software

components are written in C Interfaces inherit semantic “strings end with \0”. Some components don’t handle \0 embedded in

string gracefully, even if programming language can.

Note that UTF-16/UTF-32 include many byte 0s. Note that \0 takes space – account for it!

Overwriting can create string doesn’t end. Formal name is NUL character

H e l l o \0

Page 6: Memory Corruption James Walden Northern Kentucky University CSC 666: Secure Software Engineering

CSC 666: Secure Software Engineering

An Example Buffer Overflow

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 7: Memory Corruption James Walden Northern Kentucky University CSC 666: Secure Software Engineering

CSC 666: Secure Software Engineering

Out-of-Bounds Read

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 8: Memory Corruption James Walden Northern Kentucky University CSC 666: Secure Software Engineering

CSC 666: Secure Software Engineering

Out of Bounds Write

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 9: Memory Corruption James Walden Northern Kentucky University CSC 666: Secure Software Engineering

CSC 666: Secure Software Engineering

What happens when a buffer overflows?

What happened to our buffer overflow?

1. Overwrote memory beyond buffer with 41.

2. Program crashed with Segmentation fault.1. Directly or indirectly accessed unmapped

memory.

2. Creates a page fault exception.

3. OS does not find mapping on page table.

4. OS sends segmentation fault signal to process.

Do overflows always produce a crash? Unintentional overflows usually do, but Attackers will restrict writes to mapped pages.

Page 10: Memory Corruption James Walden Northern Kentucky University CSC 666: Secure Software Engineering

CSC 666: Secure Software Engineering

History of Overflows 1972: Computer Security Technology Planning Study. 1988: Morris Worm spreads with fingerd overflow. CERT formed. 1989: CERT published CA-1989-01 for BSD 4.3 passwd overflow. 1995: Thomas Lopatic posts info on httpd overflow to Bugtraq. 1996: Aleph One publishes “Smashing the Stack for Fun and Profit” 1997: Solar Designer describes return-to-libc technique. 1999: Compiler-based mitigations proposed. 2001: Code Red worm exploits overflow in IIS. 2003: Slammer worm infects every vulnerable server in an hour. 2004: AMD and Intel add non-executable bit in page tables. 2008: Twilight hack unlocks Wii consoles. 2010: Android 2.3 adds support for non-exec stack. 2013: Unicode SSIDs crash iPhones. 2015: GHOST overflow impacts glibc.

Page 11: Memory Corruption James Walden Northern Kentucky University CSC 666: Secure Software Engineering

Process Memory Map

11

Stack (procedure/ method calls)

Heap(dynamically

allocated)

Heap grows, e.g.,due to “new” or malloc()

Stack grows, e.g.,due to procedure call

Stack pointer (SP)(current top of stack)

This diagram shows

how stacks grow on

Intel x86s & others;

some grow other way.

Multi-threaded programs

have multiple stacks

Heap pointer

Lower-numberedaddresses

Higher-numberedaddresses

Warning: Some

diagrams elsewhere

show lower-numbered

addresses at the bottom

Text (compiled program code)

Oftenread-only

Initializedglobal “data”

Uninitializedglobal “data”

Usedfor globalconstants

& variables

Set oncodeload

Page 12: Memory Corruption James Walden Northern Kentucky University CSC 666: Secure Software Engineering

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 13: Memory Corruption James Walden Northern Kentucky University CSC 666: Secure Software Engineering

CSC 666: Secure Software Engineering

Abstract data type “Stack”

“Stack”: Abstract CS concept– “A stack of objects has the property that the

last object placed on the stack will be the first object removed. This property is commonly referred to as last in, first out queue” (LIFO).

Minimum stack operations:– PUSH: Add an element to the top of the stack– POP: Removes the last element at the top of

the stack (returning it) and reduces stack size by one.

Page 14: Memory Corruption James Walden Northern Kentucky University CSC 666: Secure Software Engineering

CSC 666: Secure Software Engineering

“Stack” in process memory map

Memory area set aside to implement calls to a procedure/function/method/subroutine

For now we’ll use these terms interchangeably

In C the term is “function”

Stack is used to implement control flowWhen you call a procedure, where it “came from” is pushed on stack

When a procedure returns, the “where I came from” is popped from stack; system starts running code there

Stack also used for other data (in many cases)Parameters passed to procedures

Procedure local variables

Return values from procedure

Page 15: Memory Corruption James Walden Northern Kentucky University CSC 666: Secure Software Engineering

Call Stack Layout

b() {

}

a() {

b();

}

main() {

a();

}

Unallocated

Stack Frame for b()

Stack Frame for a()

Stack Frame for main()

High Memory

Low Memory

CSC 666: Secure Software Engineering

Page 16: Memory Corruption James Walden Northern Kentucky University CSC 666: Secure Software Engineering

CSC 666: Secure Software Engineering

What is a Stack Frame?

Block of stack data for one procedure call.

Frame pointer (FP) points to frame:– Use offsets to find local variables.– SP continually moves with push/pops.– FP only moves on function call/return.– Intel CPUs use %ebp register for FP.

Page 17: Memory Corruption James Walden Northern Kentucky University CSC 666: Secure Software Engineering

CSC 666: Secure Software Engineering

Why use stacks for function calls?

First compiled languages (e.g., FORTRAN) did not use stacks

Call data stored with fn where program “came from”

Result: Procedures could not call themselves, directly or indirectly, as that would overwrite stored information.

If functions can arbitrarily call other functionsNeed to store old state so can return back

Need dynamic allocation for call (frame) sequences

Stack is flexible & efficient

Page 18: Memory Corruption James Walden Northern Kentucky University CSC 666: Secure Software Engineering

CSC 666: Secure Software Engineering

CPUs track two stack values

Stack pointer (SP): Value of “top” of stack– Where last data was stored on stack, possibly +/-

1 depending on architecture conventions– Modified when data pushed/popped

• May even be modified during expression calculation

Frame pointer (FP): Value of “this frame”– Simplifies accessing parameters & local

variables– Points inside stack to where “this procedure”

starts– Modified on entry/exit of a procedure

Page 19: Memory Corruption James Walden Northern Kentucky University CSC 666: Secure Software Engineering

CSC 666: Secure Software Engineering

Accessing the Stack

Pushing an item onto the stack.1. Copy 4 bytes of data to stack.

2. Decrement SP by 4.

Example: pushl $12

Popping data from the stack.3. Copy 4 bytes of data from stack.

4. Increment SP by 4.

Example: popl %eax

Retrieve data without pop: movl %esp, %eax

Page 20: Memory Corruption James Walden Northern Kentucky University CSC 666: Secure Software Engineering

CSC 666: Secure Software Engineering

Calling a procedure

Given this C program:

void main() {

f(1,2,3);}

The invocation of f() might generate assembly:pushl $3 ; constant 3pushl $2 ; Most C compilers push in reverse order by defaultpushl $1call f

“call” instruction pushes instruction pointer (IP) on stack– In this case, the position in “main()” just after f(…)– Saved IP named the return address (RET)– CPU then jumps to start of “function”

Page 21: Memory Corruption James Walden Northern Kentucky University CSC 666: Secure Software Engineering

Stack: After push of value 3

Lower-numberedaddresses

Higher-numberedaddresses

Stack pointer (SP)(current top of stack)3

Page 22: Memory Corruption James Walden Northern Kentucky University CSC 666: Secure Software Engineering

Stack: After push of value 2

Lower-numberedaddresses

Higher-numberedaddresses

2Stack pointer (SP)

(current top of stack)

3 Stack grows, e.g.,due to procedure call

Page 23: Memory Corruption James Walden Northern Kentucky University CSC 666: Secure Software Engineering

Stack: After push of value 1

Lower-numberedaddresses

Higher-numberedaddresses

1

2

Stack pointer (SP)(current top of stack)

3 Stack grows, e.g.,due to procedure call

Page 24: Memory Corruption James Walden Northern Kentucky University CSC 666: Secure Software Engineering

Stack: Immediately after call

Lower-numberedaddresses

Higher-numberedaddresses

Return address in main()

1

2

Stack pointer (SP)(current top of stack)

3 Stack grows, e.g.,due to procedure call

Page 25: Memory Corruption James Walden Northern Kentucky University CSC 666: Secure Software Engineering

Function prologue

Imagine f() has local variables, e.g. in C:

void f(int a, int b, int c) {

char buffer1[5];

char buffer2[10];

strcpy(buffer2, "This is a very long string!!!!!!!");

}

Typical x86-32 assembly on entry of f() (“prologue”):

pushl %ebp ; Push old frame pointer (FP)

movl %esp,%ebp ; New FP is old SP

subl $20,%esp ; New SP is after local vars

; “$20” is calculated to be >= local var spaceIn the assembly above, “;” introduces a comment to end of line

CSC 666: Secure Software Engineering

Page 26: Memory Corruption James Walden Northern Kentucky University CSC 666: Secure Software Engineering

Stack: Immediately after call

Lower-numberedaddresses

Higher-numberedaddresses

Return address in main()

1

2

Stack pointer (SP)(current top of stack)

3 Stack grows, e.g.,due to procedure call

Page 27: Memory Corruption James Walden Northern Kentucky University CSC 666: Secure Software Engineering

Stack: After prologue

Lower-numberedaddresses

Higher-numberedaddresses

Frame pointer (FP) –use this to accesslocal variables &

parametersReturn address in main()

1

2

Saved (old) frame pointer

Local array “buffer1”

Local array “buffer2”

Stack pointer (SP)(current top of stack)

3 Stack grows, e.g.,due to procedure call

Page 28: Memory Corruption James Walden Northern Kentucky University CSC 666: Secure Software Engineering

Stack: Overflowing buffer2

Lower-numberedaddresses

Higher-numberedaddresses

Frame pointer (FP) –use this to accesslocal variables &

parametersReturn address in main()

1

2

Saved (old) frame pointer

Local array “buffer1”

Local array “buffer2”

Stack pointer (SP)(current top of stack)

3 Stack grows, e.g.,due to procedure call

Overw

rite

Page 29: Memory Corruption James Walden Northern Kentucky University CSC 666: Secure Software Engineering

CSC 666: Secure Software Engineering

Effect of Overflowing Buffer2

Overwrites whatever is past buffer2! As you go further, overwrite higher addresses

Impact depends on system details

In our example, can overwrite: Local values (buffer1) Saved frame pointer Return value (changing what we return to) Parameters to function Previous frames

Page 30: Memory Corruption James Walden Northern Kentucky University CSC 666: Secure Software Engineering

CSC 666: Secure Software Engineering

Common buffer overflow attack

Send too large data as user input. Overlarge data overwrites buffer

Modifies return value, to point to something the attacker wants us to run

Maybe with different parameters, too On return, runs attacker-selected code But it gets worse…

Page 31: Memory Corruption James Walden Northern Kentucky University CSC 666: Secure Software Engineering

CSC 666: Secure Software Engineering

Shellcode Injection

Attacker can also include machine code that they want us to run.

If they can set the “return” value to point to this malicious code, on return the victim will run that code Unless something else is done

Significant portion of “Smashing the Stack” paper describes how to insert such code.

Page 32: Memory Corruption James Walden Northern Kentucky University CSC 666: Secure Software Engineering

Stack: Overflow with Shellcode

Lower-numberedaddresses

Higher-numberedaddresses

Frame pointer (FP) –use this to accesslocal variables &

parametersReturn address in main()

1

2

Saved (old) frame pointer

Local array “buffer1”

Local array “buffer2”

Stack pointer (SP)(current top of stack)

3 Stack grows, e.g.,due to procedure call

Malicious code

Ptr to malicious code

Page 33: Memory Corruption James Walden Northern Kentucky University CSC 666: Secure Software Engineering

Stack: Shellcode + NOP Sled

Lower-numberedaddresses

Higher-numberedaddresses

Frame pointer (FP) –use this to accesslocal variables &

parametersReturn address in main()

1

2

Saved (old) frame pointer

Local array “buffer1”

Local array “buffer2”

Stack pointer (SP)(current top of stack)

3 Stack grows, e.g.,due to procedure call

Ptr to malicious code

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

NOP sled: \x90\x90\x90\x90\x90….NOP sleds let attacker jump anywhere to

attack; real ones often more complex (to evade detection)

Shellcode often has odd constraints, e.g.,

no byte 0

Page 34: Memory Corruption James Walden Northern Kentucky University CSC 666: Secure Software Engineering

Shellcode Shellcode is a small piece of machine code

inserted into a program by exploiting a vulnerability. Called shellcode since it is often used to start a

command shell under control of attacker.

Example shellcode Remote shell (like ssh) Reverse shell (opens connection to attacker server) Remote desktop (RDP, VNC, etc.) Downloader (installs remote control tools)

CSC 666: Secure Software Engineering

Page 35: Memory Corruption James Walden Northern Kentucky University CSC 666: Secure Software Engineering

CSC 666: Secure Software Engineering

Off-by-One Overflows

Even 1 byte overflow can allow attacker to control execution by overwriting low order byte of FP.

Page 36: Memory Corruption James Walden Northern Kentucky University CSC 666: Secure Software Engineering

CSC 666: Secure Software Engineering

Heap Overflows

Programs allocate memory on heap via C: malloc() and free() C++: new and delete

To run shellcode, attack overwrites function pointer Function pointers in C. C++ methods implemented as function pointers. C++ exceptions result in following a function pointer.

Page 37: Memory Corruption James Walden Northern Kentucky University CSC 666: Secure Software Engineering

CSC 666: Secure Software Engineering

Memory Allocation

Memory allocators typically Allocate memory in chunks. Chunks stored in a linked list of bins. Chunks contain header, pointers, and data. Each bin contains chunks of a specific size. Final chunk contains free space information.

Memory corruption attacks target Header information, and Pointers.

Page 38: Memory Corruption James Walden Northern Kentucky University CSC 666: Secure Software Engineering

CSC 666: Secure Software Engineering

Malloc Data Structure

Page 39: Memory Corruption James Walden Northern Kentucky University CSC 666: Secure Software Engineering

CSC 666: Secure Software Engineering

Malloc Example

char *a, *b, *c;a = malloc(32)b = malloc(32);c = malloc(32);…free(c)free(b)free(a)

Page 40: Memory Corruption James Walden Northern Kentucky University CSC 666: Secure Software Engineering

CSC 666: Secure Software Engineering

Malloc Example Memory Layout

Page 41: Memory Corruption James Walden Northern Kentucky University CSC 666: Secure Software Engineering

CSC 666: Secure Software Engineering

Malloc Layout after Free

Page 42: Memory Corruption James Walden Northern Kentucky University CSC 666: Secure Software Engineering

CSC 666: Secure Software Engineering

Overflowing Dynamic Buffers

Page 43: Memory Corruption James Walden Northern Kentucky University CSC 666: Secure Software Engineering

CSC 666: Secure Software Engineering

Overwriting vtable Pointers

Page 44: Memory Corruption James Walden Northern Kentucky University CSC 666: Secure Software Engineering

CSC 666: Secure Software Engineering

free() vulnerabilities

To de-allocate memory, free(void *) must Use pointer to find chunk to de-allocate. Modify pointers in chunk header to remove chunk

from the list of in-use chunks. Loop: if adjacent chunk is free, combine chunks to

avoid memory fragmentation.

To exploit free(), an attacker can Overwrite adjacent chunk metadata. Cause free() to overwrite a specific word in memory

with attacker specified data. Attacker will choice location to be that of a pointer (lib

function, vtable ptr, ret addr, etc.) to control execution.

Page 45: Memory Corruption James Walden Northern Kentucky University CSC 666: Secure Software Engineering

CSC 666: Secure Software Engineering

Double free() vulnerability

1. Program free()s chunk twice, so chunk appears twice in the free list.

2. Program allocates memory, reusing part or all of chunk.

malloc() interprets first bytes as free list header. Program interprets first bytes as data.

3. Write to allocated chunk, changing first bytes.

4. Program allocates, attempts to reuse chunk. malloc() writes to location specified in first bytes,

treating bytes as free list pointer, but those bytes now point to any location specified by attacker.

Page 46: Memory Corruption James Walden Northern Kentucky University CSC 666: Secure Software Engineering

Non-executable Stack

Memory protection prevents code on the stack from being executed. Adds NX permission bit to page tables. Required CPU and OS modifications.

Limitations Some applications need to execute code on

the stack (JIT compilers for Java, JavaScript). Attackers can target other areas of memory. Buffer overflows can result in remote code

execution without running attacker generated shellcode.

Page 47: Memory Corruption James Walden Northern Kentucky University CSC 666: Secure Software Engineering

Address Space Randomization

ASLR randomly changes code/data locations to prevent memory exploits.

Problems Code must be compiled as

Position Independent Executables (PIE) to relocate code segment at cost of a 10% performance penalty.

Memory corruption can result in information leakage of address layout.

Attackers can brute force 32-bit ASLR with many copies of shellcode (heap-spraying).

CSC 666: Secure Software Engineering

Page 48: Memory Corruption James Walden Northern Kentucky University CSC 666: Secure Software Engineering

Canary Defenses

Compiler changes calling convention in two ways:– Adds a canary word to the stack (“canary in a coal

mine”)– Verifies presence of canary word before executing the

ret instruction to return to address on stack.

Protects against stack smashing since– Overflow would have to overwrite canary to reach

return value.– If canary is chosen randomly, attacker cannot know

what to overwrite to that memory location.– Does not protect against indirect memory writes.

CSC 666: Secure Software Engineering

Page 49: Memory Corruption James Walden Northern Kentucky University CSC 666: Secure Software Engineering

CSC 666: Secure Software Engineering

Canary Stack Layout

Frame Pointer Stack Pointer

old frame

param1

param2

old PC

canary word

old FP

local vars

Page 50: Memory Corruption James Walden Northern Kentucky University CSC 666: Secure Software Engineering

Return-Oriented Programming

ROP is an exploit technique in which the attacker gains control of the call stack and uses it to execute small pieces of code, called “gadgets.”

– Attacker uses existing code.– Bypasses NX defense, since no new code executed.

Gadgets are typically found in shared libraries– Gadgets can be entire functions.– Gadgets can be fragments of code that end in a ret

instruction (even unintentional instructions.)– Attacker controls order of execution and parameters

by placing data on call stack.

CSC 666: Secure Software Engineering

Page 51: Memory Corruption James Walden Northern Kentucky University CSC 666: Secure Software Engineering

CSC 666: Secure Software Engineering

Normal Programming

Instruction pointer (%eip) determines which instruction to fetch and execute.

CPU automatically increments %eip to next instruction.

Control flow by modifying %eip.

Page 52: Memory Corruption James Walden Northern Kentucky University CSC 666: Secure Software Engineering

CSC 666: Secure Software Engineering

Return Oriented Programming

• Stack pointer (%esp) determines which instruction sequence to fetch and execute.

• Move to next sequence after ret instruction.

Page 53: Memory Corruption James Walden Northern Kentucky University CSC 666: Secure Software Engineering

CSC 666: Secure Software Engineering

Finding Gadgets

Intel x86 assembly is dense Instructions are of variable length. Instruction pointer can point to any location.

As a result Any byte c3 is a ret instruction. By pointing %eip into the middle of a long

instruction, part of that instruction can be executed as a different instruction or set of instructions.

Page 54: Memory Corruption James Walden Northern Kentucky University CSC 666: Secure Software Engineering

CSC 666: Secure Software Engineering

Unintended Instructions Example

Page 55: Memory Corruption James Walden Northern Kentucky University CSC 666: Secure Software Engineering

CSC 666: Secure Software Engineering

Writing Overflow Free Code

1. Know which functions are Unsafe: guaranteed buffer overflow. Safe: no overflow if arguments correct.

2. Know how to use safe functions securely.

3. Do your own bounds checking. Be careful to avoid integer overflows.

4. Check for memory errors Security-oriented static analysis like Fortify. Memory dynamic analysis: Valgrind, Purify.

Page 56: Memory Corruption James Walden Northern Kentucky University CSC 666: Secure Software Engineering

Many C fns don’t check bounds

gets(3) – reads input without checking. Don’t use it!

strcpy(3) – strcpy(dest, src) copies from src to dest If src longer than dest buffer, keeps writing!

strcat(3) – strcat(dest, src) appends src to dest If src + data in dest longer than dest buffer, keeps writing!

scanf() family of input functions – many dangerous scanf(3), fscanf(3), sscanf(3), vscanf(3), vsscanf(3), vfscanf(3)

Many options don’t control max length (e.g., bare “%s”)

Many other dangerous functions, e.g.: realpath(3), getopt(3), getpass(3)

streadd(3), strecpy(3), and strtrns(3)

It’s not just functions; ordinary loops can overflow.

Page 57: Memory Corruption James Walden Northern Kentucky University CSC 666: Secure Software Engineering

CSC 666: Secure Software Engineering

gets()

/* * gets() version reads line from user input until EOF or newline * performs no bounds checking at all—BSS, p. 142 */int main() {

char buf[1024];gets(buf);

}

/* * fgets() version accepts a size parameter; always specify this parameter */#define BUFSZ 1024

int main() {char buf[BUFSZ];fgets(buf, BUFSZ, stdin)

}

Page 58: Memory Corruption James Walden Northern Kentucky University CSC 666: Secure Software Engineering

CSC 666: Secure Software Engineering

strcpy()

/* code examples from BSS, pp. 143-144 */strcpy(dst, src);

/* copying with explicit bounds checking */if(strlen(src) >= dst_size) {

/* error */} else {

strcpy(dst, src);}

/* * or ... use strncpy, but be careful to avoid off-by-one bugs: * if strlen(src) == dst_size, dst will not be null-terminated */strncpy(dst, src, dst_size – 1);dst[dst_size – 1] = '\0';

/* * or ... dynamically allocate right-sized buffer when you need it */dst = (char *)malloc(strlen(src) + 1);strcpy(dst, src);

Page 59: Memory Corruption James Walden Northern Kentucky University CSC 666: Secure Software Engineering

CSC 666: Secure Software Engineering

sprintf()

/* print a usage message (BSS, pp. 144-145) */int main(int argc, char **argv) {

char usage[1024];sprintf(usage, “USAGE: %s -f flag [arg1]\n”, argv[0];

}

/* attack code */int main() {

execl(“/path/to/program”, <<buffer overflow string>>, NULL);}

/* safe solution using nonstandard snprintf() code */int main(int argc, char **argv) {

char usage[1024];char fmt = “USAGE: %s -f flag [arg1]\n”;sprintf(usage, 1024, fmt, argv[0];

}

Page 60: Memory Corruption James Walden Northern Kentucky University CSC 666: Secure Software Engineering

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 61: Memory Corruption James Walden Northern Kentucky University CSC 666: Secure Software Engineering

CSC 666: Secure Software Engineering

C11 Annex K Bounds Checking

C11 standard adds bounds-checking interfacesCreates “safer” versions of C functions

Limits lengths of results

Example: strcpy_s(s1, s1max, s2);Copies s2 to s1.

s1max > strnlen_s(s2, s1max)

Does not automatically resize.

On error, calls runtime-constraint handler function, controlled by set_constraint_handler_s(). This handler can permit returns

If it returns, returns 0 if ok, nonzero if a constraint failed

Not universally available. Provided by slibc.

Page 62: Memory Corruption James Walden Northern Kentucky University CSC 666: Secure Software Engineering

CSC 666: Secure Software Engineering

Safe String Libraries

strlcat() and strlcpy()– BSD-licensed open source routines

C++ std::string library– Dynamically-sized strings

SafeStr library provides safestr_t objects– Dynamically-sized– Cast to (char *) for read-only purposes only

Microsoft’s strsafe.h

Page 63: Memory Corruption James Walden Northern Kentucky University CSC 666: Secure Software Engineering

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 64: Memory Corruption James Walden Northern Kentucky University CSC 666: Secure Software Engineering

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 65: Memory Corruption James Walden Northern Kentucky University CSC 666: Secure Software Engineering

CSC 666: Secure Software Engineering

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

Fixed Width ISO-8859-1 UTF-32

Variable Width UTF-8 (most Internet protocols, Python, Ruby) UTF-16 (Java, .NET)

Character Encoding Code Point

s ISO-8859-1UTF-8

7373

ÿ ISO-8859-1UTF-8

FFC3 BF

Page 66: Memory Corruption James Walden Northern Kentucky University CSC 666: Secure Software Engineering

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 encoding

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

Page 67: Memory Corruption James Walden Northern Kentucky University CSC 666: Secure Software Engineering

CSC 666: Secure Software Engineering

C++ Dangers

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

cin >> username;

The [] operator does not perform bounds checking

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

Page 68: Memory Corruption James Walden Northern Kentucky University CSC 666: Secure Software Engineering

CSC 666: Secure Software Engineering

Key Points

1. Memory corruption vulnerabilities can result in Execution of attacker-supplied code. Attacker hijacking of program control flow. Alteration of program data. Information leak.

2. Memory Corruption Attack Types Buffer overflows: stack and heap Format string attacks (%n) Use after free

Page 69: Memory Corruption James Walden Northern Kentucky University CSC 666: Secure Software Engineering

CSC 666: Secure Software Engineering

Key Points (2)

3. Mitigations Non-executable Stack (OS, hardware) Address Space Layout Randomization (OS) Stack Canaries (compiler)

4. Countering Mitigations Brute force (heap spraying) Return Oriented Programming

5. Writing Secure Code Avoiding unsafe functions. Performing bounds checking.

Page 70: Memory Corruption James Walden Northern Kentucky University CSC 666: Secure Software Engineering

CSC 666: Secure Software Engineering

References

1. Aleph Null, “Smashing the Stack for Fun and Profit,” Phrack 49, 1996.

2. Erik Buchanan et al., “Return-Oriented Programming: Exploits Without Code Injection”, https://cseweb.ucsd.edu/~hovav/talks/blackhat08.html, 2008.

3. Johnathan Bartlett, Programming from the Ground Up, Bartlett Publishing, 2004.

4. James C. Foster et al., Buffer Overflow Attacks, Syngress, 2005.

5. Scot Hand, Heap Based Exploitation, https://csg.utdallas.edu/wp-content/uploads/2012/08/Heap-Based-Exploitation.pdf, 2012.

6. Koziol et al., The Shellcoder’s Handbook: Discovering and Exploiting Security Holes, Wiley, 2004.

7. Haroon Meer, “History of Memory Corruption Attacks”, http://media.blackhat.com/bh-us-10/whitepapers/Meer/BlackHat-USA-2010-Meer-History-of-Memory-Corruption-Attacks-wp.pdf, 2010.

8. Tom Plum, “The New C Standard Explored”, http://www.drdobbs.com/cpp/the-new-c-standard-explored/232901670, Dr. Dobb’s Journal, 2012.

9. Robert C. Seacord, Secure Coding in C and C++, Addison-Wesley, 2006.

10. Laszlo Szekeres et al. "Eternal war in memory." Proceedings of the 34th IEEE Symposium on Security and Privacy (SP’13), San Francisco, CA. 2013.

11. John Viega and Gary McGraw, Building Secure Software, Addison-Wesley, 2002.