980 likes | 1.24k Views
CS 242. Bugs, security vulnerabilities, and automated tools. John Mitchell. Announcements. Last class meeting Wednesday 12/6 Review session Final exam following Friday 12/15 8:30 – 11:30 AM, Closed book Gates B01 – This room!
E N D
CS 242 Bugs, security vulnerabilities, and automated tools John Mitchell
Announcements • Last class meeting Wednesday 12/6 • Review session • Final exam following Friday 12/15 • 8:30 – 11:30 AM, Closed book • Gates B01 – This room! • Course evaluations on Axess 12/4 – 17 • Reward (from Registrar): see grades when posted, only if you fill in all your course evaluations • No more paper forms: take a free pencil!
Outline • Motivation • Software bugs, Security vulnerabilities • Modified execution environments • Detecting memory errors: Purify, Stackguard • Containment and assurance: sandboxing, proof carrying code • Web security • Penetration testing • Tainting, XSS vulnerabilities • Helping programmers write better code • Static analysis – Metacompilation, Prevent, Prefix, Prefast • Based on abstract interpretation – form of denotational semantics • Race condition checkers • Based on type system for identifying race-free programs Examples: Purify, Stackguard, Perl tainting, Prevent, Race-free Java
Software bugs • Old quote Every program is either trivial or wrong - my summer job supervisor • NIST Report: bad software costs $59.5 billion/yr • 0.5% of US GDP
Serious cost of software errors • NASA Mariner 1 (July 22, 1962) • Off-course during launch, missing 'bar' in its FORTRAN software • Therac-25 (1985-1987) • Six accidents involved massive radiation overdoses to patients • Software errors combined with other problems • AT&T long distance network crash (Jan 15, 1990) • Missing break in C switch statement • Patriot MIM-104 (Feb 25, 1991) • Iraqi Scud hit barracks in Dharan, Saudi Arabia, killing 28 US soldiers • Failure to intercept Scud caused by software error related to clock skew • Ariane 5 Bug crash (June 4, 1995) • Software errors in inertial reference system, cost: $7.5 billion • Mars Orbiter (Sept 1999) • Crashed because of wrong units in a program • Mars Rover (Jan 21, 2004) • Freezes due to too many open files in flash memory
Cost of Fixing a Defect Credit: Andy Chou, Coverity
Number of Bugs Found Credit: Andy Chou, Coverity
Security vulnerabilities reported • Top categories: • Buffer overflow • Cross-site scripting • SQL injection http://www.cert.org/stats/
Questions • How can we improve software quality? • Better management procedures • Follow good design principles • Better programming languages • Type-safe languages? Good concurrency primitives? • Better tools for existing languages • Find bugs • Verify absence of bugs What do you think will be most effective?
Some example tools • Memory safety • Heap memory: Purify • Stack memory: Stackguard • Web security • Perl taining (just the tip of the iceberg) • General program bugs • Coverity Prevent, related tools • Java race condition checking
Purify • Goal • Instrument program to find memory errors • Out-of-bounds: access to unallocated memory • Use-before-init • Memory leaks • Technique • Works on relocatable object code • Link to modified malloc that provides tracking tables • Tracks heap locations only • Memory access errors: insert instruction sequence before each load and store instruction • Memory leaks: GC algorithm
Stackguard • Run-time detection of buffer overflow
Parameters Return addr Control link Local vars Linux process memory layout Activation Record 0xC0000000 User Stack %esp Shared libraries 0x40000000 brk Heap SP Loaded from exec 0x08048000 Unused 0
topofstack buf sfp ret-addr str topofstack ret str *str Buffer overflows • Suppose a web server contains a function:void func(char *str) { char buf[128]; strcpy(buf, str); do-something(buf); } • When the function is invoked the stack looks like: • What if *str is 136 bytes long? After strcpy:
topofstack *str ret Code for P Program P: exec( “/bin/sh” ) Basic stack exploit • Main problem: no range checking in strcpy(). • Suppose *str is such that after strcpy stack looks like: • When func() exits, the user will be given a shell !! • Note: attack code runs in stack. • To determine ret guess position of stack when func() is called. (exact shell code by Aleph One)
Exploiting buffer overflows • Suppose web server calls func() with given URL. • Attacker sends a 200 byte URL. Gets shell on web server. • Some complications: • Program P should not contain the ‘\0’ character. • Overflow should not crash program before func() exists. • Sample remote buffer overflows of this type: • (Old) overflow in MIME type field in MS Outlook. • (Old) overflow in Symantec Virus Detection Set test = CreateObject("Symantec.SymVAFileQuery.1") test.GetPrivateProfileString "file", [long string]
Finding buffer overflows • To find overflow: • Run web server on local machine. • Issue requests with long tags. All long tags end with “$$$$$”. • If web server crashes, search core dump for “$$$$$” to find overflow location. • Some automated tools exist. (e.g. eEye Retina). • Then use disassemblers and debuggers (e..g IDA-Pro) to construct exploit.
Preventing overflow attacks • Main problem: • strcpy(), strcat(), sprintf() have no range checking. • “Safe” versions strncpy(), strncat() are misleading • strncpy() may leave buffer unterminated. • strncpy(), strncat() encourage off by 1 bugs. • Defenses: • Type safe languages (Java, ML). Legacy code? • Mark stack as non-execute • Static source code analysis • Run time checking: StackGuard, Libsafe, SafeC, (Purify)
Marking stack as non-execute • Basic stack exploit can be prevented by marking stack segment as non-executable. • NX-bit on AMD Athlon 64, XD-bit on Intel P4 “Prescott”. • NX bit in every Page Table Entry (PTE) • Support in SP2. Code patches exist for Linux, Solaris. • Limitations: • Does not defend against `return-to-libc’ exploit. • Overflow sets ret-addr to address of libc function. • Does not block more general overflow exploits: • Overflow on heap: overflow buffer next to func pointer. • Some apps may use executable stack (e.g. LISP interpreters)
Run time checking: StackGuard • Many many run-time checking techniques … • Here, only discuss methods relevant to overflow protection. • Solutions 1: StackGuard (WireX) • Run time tests for stack integrity • Embed “canaries” in stack frames and verify their integrity prior to function return Frame 2 Frame 1 topofstack sfp ret str local canary sfp ret str local canary
Canary Types • Random canary: • Choose random string at program startup. • Insert canary string into every stack frame. • Verify canary before returning from function. • To corrupt random canary, attacker must learn current random string. • Terminator canary:Canary = 0, newline, linefeed, EOF • String functions will not copy beyond terminator. • Hence, attacker cannot use string functions to corrupt stack.
StackGuard (Cont.) • StackGuard implemented as a GCC patch • Program must be recompiled • Minimal performance effects:8% for Apache • Newer version: PointGuard • Protects function pointers and setjmp buffers by placing canaries next to them • More noticeable performance effects • Note: Canaries don’t offer fullproof protection • Some stack smashing attacks can leave canaries untouched.
Some example tools • Memory safety • Heap memory: Purify • Stack memory: Stackguard • Web security • Perl taining (just the tip of the iceberg) • General program bugs • Coverity Prevent, related tools • Java race condition checking
Perl tainting • Run-time checking of Perl code • Perl used for CGI scripts; security sensitive • Taint checking stops some potentially unsafe calls • Tainted strings • User input, values derived from user input • Except result of matching against untainted string • Prohibited calls • print $form_data{"email"} . "\n"; • OK since print is safe (???) • system("mail " . $form_data{"email"}); • Flagged system call with user input as argument
Safe Perl mail command (?) • Check email string against pattern and parse $email = $form_data{"email"}; if ( $email =~ /(\w{1}[\w-.]*)\@([\w-.]+)/) { $email = "$1\@$2"; } else { warn ("TAINTED DATA SENT BY …"); $email = ""; # successful match did not occur } • What does this accomplish? • Only send email to address that “looks good” • Programmer responsible for “good” pattern • Perl cannot guarantee that email addr is OK
Some example tools • Memory safety • Heap memory: Purify • Stack memory: Stackguard • Web security • Perl taining (just the tip of the iceberg) • General program bugs • Coverity Prevent, related tools • Java race condition checking
Bugs to Detect • Some examples • Crash Causing Defects • Null pointer dereference • Use after free • Double free • Array indexing errors • Mismatched array new/delete • Potential stack overrun • Potential heap overrun • Return pointers to local variables • Logically inconsistent code • Uninitialized variables • Invalid use of negative values • Passing large parameters by value • Underallocations of dynamic data • Memory leaks • File handle leaks • Network resource leaks • Unused values • Unhandled return codes • Use of invalid iterators Slides: From Andy Chou’s CS155 guest lecture last year
Prototype for open() syscall: Typical mistake: Result: file has random permissions Check: Look for oflags == O_CREAT without mode argument Open_args int open(const char *path, int oflag, /* mode_t mode */...); fd = open(“file”, O_CREAT);
chroot() changes filesystem root for a process Confine process to a “jail” on the filesystem Doesn’t change current working directory Chroot checker chroot() chdir(“/”) open(“../file”,…)
Race condition between time of check and use Not applicable to all programs TOCTOU check(“foo”) use(“foo”)
#include <stdlib.h> #include <stdio.h> void say_hello(char * name, int size) { printf("Enter your name: "); fgets(name, size, stdin); printf("Hello %s.\n", name); } int main(int argc, char *argv[]) { if (argc != 2) { printf("Error, must provide an input buffer size.\n"); exit(-1); } int size = atoi(argv[1]); char * name = (char*)malloc(size); if (name) { say_hello(name, size); free(name); } else { printf("Failed to allocate %d bytes.\n", size); } } Example Code
Callgraph main atoi exit free malloc say_hello fgets printf
Reverse Topological Sort 8 main atoi exit free malloc say_hello 7 3 4 5 6 fgets printf 1 2
Apply Library Models 8 main atoi exit free malloc say_hello 7 3 4 5 6 fgets printf 1 2
Bottom Up Analysis 8 main atoi exit free malloc say_hello 7 3 4 5 6 fgets printf 1 2
Bottom Up Analysis 8 main atoi exit free malloc say_hello 7 3 4 5 6 fgets printf 1 2
Bottom Up Analysis 8 main atoi exit free malloc say_hello 7 3 4 5 6 fgets printf 1 2
#define SIZE 8 void set_a_b(char * a, char * b) { char * buf[SIZE]; if (a) { b = new char[5]; } else { if (a && b) { buf[SIZE] = a; return; } else { delete [] b; } *b = ‘x’; } *a = *b; } Finding Local Bugs
Control Flow Graph char * buf[8]; if (a) a !a b = new char [5]; if (a && b) !(a && b) a && b buf[8] = a; delete [] b; *b = ‘x’; *a = *b; END
Path Traversal char * buf[8]; if (a) a !a b = new char [5]; if (a && b) !(a && b) a && b buf[8] = a; delete [] b; *b = ‘x’; *a = *b; END
Apply Checking Null pointers Use after free Array overrun char * buf[8]; if (a) !a if (a && b) !(a && b) delete [] b; *b = ‘x’; *a = *b; END
Apply Checking Null pointers Use after free Array overrun char * buf[8]; “buf is 8 bytes” if (a) !a if (a && b) !(a && b) delete [] b; *b = ‘x’; *a = *b; END
Apply Checking Null pointers Use after free Array overrun char * buf[8]; “buf is 8 bytes” if (a) !a “a is null” if (a && b) !(a && b) delete [] b; *b = ‘x’; *a = *b; END
Apply Checking Null pointers Use after free Array overrun char * buf[8]; “buf is 8 bytes” if (a) !a “a is null” if (a && b) Already knew a was null !(a && b) delete [] b; *b = ‘x’; *a = *b; END
Apply Checking Null pointers Use after free Array overrun char * buf[8]; “buf is 8 bytes” if (a) !a “a is null” if (a && b) !(a && b) delete [] b; “b is deleted” *b = ‘x’; *a = *b; END
Apply Checking Null pointers Use after free Array overrun char * buf[8]; “buf is 8 bytes” if (a) !a “a is null” if (a && b) !(a && b) delete [] b; “b is deleted” *b = ‘x’; “b dereferenced!” *a = *b; END
Apply Checking Null pointers Use after free Array overrun char * buf[8]; “buf is 8 bytes” if (a) !a “a is null” if (a && b) !(a && b) delete [] b; “b is deleted” *b = ‘x’; “b dereferenced!” *a = *b; No more errors reported for b END
What is a bug? Something the user will fix. Many sources of false positives False paths Idioms Execution environment assumptions Killpaths Conditional compilation “third party code” Analysis imprecision … False Positives p = 0; *p; fatal(“ouch”);
A False Path char * buf[8]; if (a) a !a b = new char [5]; if (a && b) !(a && b) a && b buf[8] = a; delete [] b; *b = ‘x’; *a = *b; END