480 likes | 788 Views
Buffer Overruns. Jon Pincus Senior Researcher Systems and Networking Area Microsoft Research Microsoft Corporation. The History Of Buffer Overruns (Condensed). 1988: “The Internet Worm” (aka the Morris worm) 1996: AlephOne’s Smashing the Stack for Fun and Profit
E N D
Buffer Overruns Jon Pincus Senior Researcher Systems and Networking Area Microsoft Research Microsoft Corporation
The History Of Buffer Overruns (Condensed) • 1988: “The Internet Worm” (aka the Morris worm) • 1996: AlephOne’s Smashing the Stack for Fun and Profit • 1997: SolarDesigner’s exploit for NX stack patch • 1998: DilDog teaches The Tao of Windows Buffer Overruns • 2000: Buffer overruns named “Bug of the decade” • 2001: Code Red; Halvar Flake: “heap overruns will be the next wave” • 2002: Slapper; heap overruns are in fact the next wave; exploits of integer overflows published in Phrack • 2003: Slammer, Blaster; Linux kernel integer overflow attack; Point-and-click exploit tools; CERT advisories for overruns on Windows, sendmail, Cisco, OpenSSL, Oracle, Sun XDR, …
Agenda • Introduction • Key characteristics of buffer overruns • Spot the defect! • Defenses against buffer overruns • What is Microsoft doing?
Buffer OverrunsThe problem • A buffer overrun occurs when the program attempts to write beyond the end of a bounded array (aka "buffer") • This is due to at least one defect in the code • A buffer overrun typically leads to a vulnerability • These vulnerabilities can have major consequences
Exploits Take Advantage Of A Vulnerability To Accomplish A Goal • In C/C++, exploits of buffer overruns can result in elevation of privilege (EoP) • Worst case: exploitable via anonymous remote access • Worst case #1: Remotely rooting a machine • Worst case #2: Exploit + payload = worm • One way to accomplish EoP is via arbitrary code execution • In “safer” environments (Java, .NET) exploits of buffer overruns still result in Denial of Service (DoS) • May indirectly lead to EoP • Still, this is a much, much better situation
Who Can Exploit Buffer Overruns? • 20th century: “Rreally smart people” • Early 00s: Competent programmer • Well-described techniques for finding, exploiting overruns • Tools starting to make life easier for exploiters • “Really smart people” continue to develop more complex exploits • Today: Script kiddies, once the patch has come out • Good tools, toolkits are available • Competent programmers can now enhance/package them • Slashdot: “Looks like a 14-year-old kid can do it” • Tomorrow: Script kiddies, preschoolers, …
HistoryBuffer overrun defenses (condensed) • 1988: We all stop using gets() • 1996: strlcpy/strlcat, OpenBSD code sweep • 1997: SolarDesigner’s non-executable patch • 1998: StackGuard (stack canaries) • 1999: Grep-like analysis tools (ITS4, RATS, etc.) • 2000: More powerful static analysis tools (PREfix, splint, etc.) • 2001: PaX ASLR randomization • 2002: C-Cured, Program shepherding: promising research approaches • 2003: W^X, binary-based static-analysis tools
Defenses Against Buffer Overruns • Prevention: Keep them out of the code in the first place • Examples: Better libraries, training • Detection: Find them and remove them • Examples: Code review, fuzz testing, static analysis • Mitigation: Reduce consequences of remaining ones • Typically: Crash instead of allowing code injection • Examples: Stack canaries, disable functionality by default, recode into a safer language • These are all valuable approaches … • … but there are limitations to all of them
Agenda • Introduction • Key characteristics of buffer overruns • Spot the defect! • Defenses against buffer overruns • What is Microsoft doing?
Three Key Characteristics Of A Buffer Overrun • What kind of memory is overrun? • How many bytes of memory are overrun? • What is the code-level defect? • Important both from an exploit and a defense perspective
What Kind Of Memory Is Overrun? • 20th century • Stack buffer overruns easy to exploit by “stack smashing” • Today • Stack buffer overruns easy to exploit by many different techniques • Some heap overruns are easy to exploit by “heap smashing” • Tomorrow • Stack, heap overruns will be even easier to exploit • Shared memory, etc., will also be threats • Defense perspective: consider all kinds of memory
How Many Bytes Are Overrun? • 20th century: Large overruns are usually exploitable in the wild • Typically need enough bytes for a shellcode and “no-op sled” (200+), and to clobber the saved return address • Today: Four-byte overruns are often exploitable in the wild • “All I need is an arbitrary pointer write ...” • Soon: One-byte overruns likely to be exploitable in the wild • Defense perspective: Have to worry about one-byte and up
A Buffer Overrun Has Multiple Causes, Typically Including ... • One or more code-level defects • At the code level, every buffer overrun is caused by a missing, or insufficient, or incorrect check for validity of user-supplied input • Design/architecture choices • Some designs and architectures are less likely to lead to buffer overruns • Language/library choice • Some libraries (e.g., self-resizing strings) make buffer overruns less likely • Some languages (e.g., VB, Java, C#) make the consequences of buffer overruns less severe • Human fallibility • If programmers were perfect, these mistakes wouldn’t happen!
What Is The Code-Level Defect? • 20th century • String function abuse • Simple bounds errors • Today • Loops • Integer overflows • Signed/unsigned mismatches, other arithmetic problems • Tomorrow: Race conditions? • Defense perspective: Have to worry about all of these • “It’s not just strcpy and strncpy any more!”
Agenda • Introduction • Key characteristics of buffer overruns • Spot the defect! • Defenses against buffer overruns • What is Microsoft doing?
void f(char *src1, char* src2) { char dest[DEST_SIZE]; // check to make sure first string fits if (strlen(src1) > sizeof(dest)) return; strcpy(dest, src1); // copy as much of the second string as will fit strncat(dest, src2, sizeof(dest)); ... } Spot The Defect! (1)
void f(char *src1, char* src2) { char dest[DEST_SIZE]; // check to make sure first string fits if (strlen(src1) > sizeof(dest)) return; strcpy(dest, src1); // copy as much of the second string as will fit strncat(dest, src2, sizeof(dest)); ... } See Miller and deRaadt, strlcpyand strlcat Spot The Defect! (1)String function abuse strncat’s 3rd param is # of chars to copy, not the buffer size
#ifdef UNICODE #define _sntprintf _snwprintf #define TCHAR wchar_t #else #define _sntprintf _snprintf #define TCHAR char #endif TCHAR buff[MAX_SIZE]; _sntprintf(buff, sizeof(buff), _T(”%s:%s...”), in1, in2); Spot The Defect! (2)
#ifdef UNICODE #define _sntprintf _snwprintf #define TCHAR wchar_t #else #define _sntprintf _snprintf #define TCHAR char #endif TCHAR buff[MAX_SIZE]; _sntprintf(buff, sizeof(buff), _T(”%s:%s...”), in1, in2); Spot The Defect! (2)SI/Unicode mismatch _snwprintf’s 2nd param is # of chars in buffer, not # of bytes
extern TCHAR g_szName[MAX_PATH + 1]; static const TCHAR c_szServerName[] = "SERVER_NAME"; DWORD dwSize = sizeof(g_szName); TCHAR szAnsiName[MAX_NAME_LENGTH + 1]; GetVariable (connID, c_szServerName, // variable name to get szAnsiName, // output dwSize);// size of output Spot The Defect! (3)
extern TCHAR g_szName[MAX_PATH + 1]; static const TCHAR c_szServerName[] = "SERVER_NAME"; DWORD dwSize = sizeof(g_szName); TCHAR szAnsiName[MAX_NAME_LENGTH + 1]; GetVariable (connID, c_szServerName, // variable name to get szAnsiName, // output dwSize);// size of output in bytes Spot The Defect! (3)
extern TCHAR g_szName[MAX_PATH + 1]; static const TCHAR c_szServerName[] = "SERVER_NAME"; DWORD dwSize = sizeof(g_szName); TCHAR szAnsiName[MAX_NAME_LENGTH + 1]; GetVariable (connID, c_szServerName, // variable name to get szAnsiName, // output dwSize);// size of output Spot The Defect! (3)Simple bounds error the wrong size is passed in: MAX_PATH + 1 instead of MAX_NAME_LENGTH + 1
char buff1[MAX_SIZE], buff2[MAX_SIZE]; out = buff1; // make sure it’s a valid URL and will fit if (! isValid(url)) return; if (strlen(url) > MAX_SIZE – 1) return; // copy up to first separator do { // skip spaces if (*url != ’ ’) *out++ = *url; } while (*url++ != ’/’); strcpy(buff2, buff1); ... Spot The Defect! (4)
char buff1[MAX_SIZE], buff2[MAX_SIZE]; out = buff1; // make sure it’s a valid URL and will fit if (! isValid(url)) return; if (strlen(url) > MAX_SIZE – 1) return; // copy up to first separator do { // skip spaces if (*url != ’ ’) *out++ = *url; } while (*url++ != ’/’); strcpy(buff2, buff1); ... Spot The Defect! (4)Loop termination what if there is no ‘/’ in the URL?
char buff1[MAX_SIZE], buff2[MAX_SIZE]; out = buff1; // make sure it’s a valid URL and will fit if (! isValid(url)) return; if (strlen(url) > MAX_SIZE – 1) return; // copy up to first separator do { // skip spaces if (*url != ’ ’) *out++ = *url; } while (*url++ != ’/’) && (*url != 0); strcpy(buff2, buff1); ... Spot The Defect! (5)
char buff1[MAX_SIZE], buff2[MAX_SIZE]; out = buff1; // make sure it’s a valid URL and will fit if (! isValid(url)) return; if (strlen(url) > MAX_SIZE – 1) return; // copy up to first separator do { // skip spaces if (*url != ’ ’) *out++ = *url; } while (*url++ != ’/’) && (*url != 0); strcpy(buff2, buff1); ... Spot The Defect! (5)Loop termination again • order of tests is wrong. • what about 0-length URLs? • buff1 is not 0-terminated
void *ConcatBytes(void *buf1, size_t len1, char *buf2, size_t len2){ void *buf = malloc(len1 + len2); if (buf == NULL) return; // allocation failed memcpy(buf, buf1, len1); memcpy(buf + len1, buf2, len2); ... Spot The Defect! (6)
void *ConcatBytes(void *buf1, size_t len1, char *buf2, size_t len2){ void *buf = malloc(len1 + len2); if (buf == NULL) return; // allocation failed memcpy(buf, buf1, len1); memcpy(buf + len1, buf2, len2); ... Spot The Defect! (6)Integer overflow What if: len1 == 0xFFFFFFFE len2 == 0x00000102 Then only 0x100 bytes are malloc’ed
Spot The Bug On Channel 9 • Shameless plug: if you enjoyed Spot the Defect, visit Channel9 and play Spot the Bug in the TechOff forum! • http://channel9.msdn.com/ShowPost.aspx?PostID=65412 • http://channel9.msdn.com/ShowPost.aspx?PostID=55931 • http://channel9.msdn.com/ShowPost.aspx?PostID=46264
Abuse of string function Simple bounds error Unicode/ANSI mismatch Loop termination Arithmetic error (e.g., integer overflow, signed/unsigned) Common Code-level Causes Of Buffer Overruns Classic “20th century buffer overruns” CodeRed Blaster A cool new name coming soon?
Agenda • Introduction • Key characteristics of buffer overruns • Spot the defect! • Defenses against buffer overruns • What is Microsoft doing?
Defenses Against Buffer Overruns (Recap) • Prevention: Keep them out of the code in the first place • Detection: If they’re in the code, find them and remove them • Mitigation: Reduce the consequences of the remaining ones
Key Prevention Techniques • Education • Training • Better libraries • Or at least avoiding dangerous parts of existing libraries
PreventionState of the art (2005) • Good books and articles exist • Good string libraries exist • Self-resizing strings for C++ (and C#, Java) • Counted strings, for C • strlcat, snprintf, and SafeStr if you really really need to deal with character arrays • Issues: Existing code, breaking old developer habits • No general approach to preventing integer overflows, etc • but see recent Integer Handling with the C++ SafeInt Class at http://msdn.microsoft.com/columns/secure.asp
Detection Techniques • Code review • Issues: Imperfect, very time-consuming • Testing • “Fuzz testing” is especially useful • Issues: Incomplete coverage, “smart fuzzing” is still something of an art • Static analysis • Source-based or binary-based • Issues: Existing tools do not find all defects, “noise”
DetectionState of the art (2/2004) • Making progress • There are still significant limitations • Proof by example (1): Sendmail • Code-reviewed and tested for years and years … • The test case of choice for static analysis tools ... • ... but new buffer overruns continue to be discovered • Proof by example (2): Microsoft aggressively develops and deploys static analysis tools, code review, testing, but ...
Mitigation Techniques • Attack surface reduction (e.g., disabling functionality by default) • Bounds checking • Issues: Performance, compatibility • Stack canaries and stack cookies • Issues: Vulnerability to implementation-level attacks, limited to stack overruns • Heap meta-data checking, heap cookies • NX (non-executable stack/heap) and W^X • Issues: Compatibility, limited to “code injection” attacks • Randomization • Pointer encryption • Program shepherding
MitigationState of the art (2005) • OS’s shipping with mitigations enabled, e.g. • Microsoft Windows Server 2003 SP1 and XPSP2 with Visual Studio /GS stack cookies, /SafeSEH exception handling checking, NX, heap checking • OpenBSD with W^X and ProPolice • Add-ons are also available: Wirex, PaX, OpenWall, ... • Effectiveness is still limited in practice
Case StudyMitigations • MS03-026 was the vulnerability exploited by Blaster • Several mitigations are effective against Blaster • /GS stack cookies • non-executable stack • But other exploits of MS03-026 defeat those mitigations • LSD, NGSS, and Cigital have all discovered exploits that defeat the version of /GS used in Windows Server 2003 • X-otic has published an exploit that gets around NX • If /GS and/or NX had been widely deployed, somebody probably would have built Blaster around these more powerful exploits
Agenda • Introduction • Key characteristics of buffer overruns • Spot the defect! • Defenses against buffer overruns • What is Microsoft doing?
Microsoft Product Development Timeline (subset) Security push Learn and Refine Security review External review Concept / Requirements Designs Complete Test plansComplete Code Complete Ship Post Ship Training Review old defects Check-ins checked Secure coding guidelines Use static analysis, testing tools Code reviews Data mutation & Fuzz Tests Design Review
Key Defense Techniques At Microsoft • Prevention: SafeStr, SafeInt<T>, Secure C Runtime, training • See Writing Secure Code, 2nd edition • Code review • At checkin time, system-wide review as part of “security push” • Developing tools to make code review more effective • Testing: Developer tests, stress tests, fuzz tests • Additional run-time checks to find “latent” buffer overruns • Static analysis: PREfix, PREfast, espX • Major effort: Adding annotations to improve tools’ effectiveness • Mitigations: /GS, NX, “secure by default”
But We’re Obviously Not Perfect … • Any “MSRC-class” defect reveals multiple failures, e.g. • Code review missed the defect • Static analysis missed the defect • Testing/fuzzing missed the defect • We do a root cause analysis focused on two major questions • Why did these failures occur? • How to improve?
Sample Analyses And Action Items • Training did not cover the coding construct • Immediately: Add it to training (duh) • Short term: Look for other coding constructs that may be overlooked • Code reviewers missed the defect • Immediately code review all code for this and similar defects • Longer term: Look at how to improve code reviews in general • Static analysis tools missed the defect due to known limitations • Immediately introduce some new “very-high-noise” warnings into tools, and run revised tools on entire code base • Longer term: Continue work (already in progress) on new analyses that can find this problem with low noise
Conclusion • Attackers are improving • “Anybody can do it!” • Cleverer exploits • Defenses are improving too, in several dimensions • Prevention, detection, mitigation • Our goal: get to the point where buffer overruns are no longer the most critical security-related defects
Buffer Overruns Jon Pincus Senior Researcher Systems and Networking Area Microsoft Research Microsoft Corporation
© 2005 Microsoft Corporation. All rights reserved. This presentation is for informational purposes only. Microsoft makes no warranties, express or implied, in this summary.