Title: Buffer overflows and Security vulnerabilities
1Buffer overflows and Security vulnerabilities
- Apoorv Kashyap
- CS-599, Spring 2004
February 18th, 2004
2Contents
- Motivation
- Whats the problem?
- Basis Structure of Process Memory
- The Buffer Overflow Problem
- In and Out of the Stack!
- Changing the Flow of Control
- Attack Targets
- Lets C Explanation in programming terms
- Static Analysis
- Dynamic Analysis
- STOBO
- StackGuard
- Stack Shield
- ProPolice
- Libsafe and Libverify
- Others
- Comparisons
- Common Problems
- Conclusion
3Motivation
- Increasing Software size and complexity
- Buffer Overflows constitute for about 50 of the
vulnerabilities reported by CERT( Coordination
Center at CMU) - In future, software companies may be charged for
not preventing intrusion - Educate the Software Programmers not an easy
way out! - Legacy code
- Lets face it! No one can claim to have written a
100 bug free software
4What is the Problem?
- An Intrusion or a successful attach aims to
change the flow of control, letting the
attacker execute arbitrary code - One way to achieve the above is by exploiting
Buffer Overflow - Test Data is not sufficient to expose
- Most of the classic applications are in good-old
C!
5Basic Structure of Process Memory
6The Buffer Overflow Problem
- Buffer is a contiguous block of memory, of a
fixed size - Buffer overflow is a spill, fill over the top, or
bounds. - Buffers can be over flown with too much data, if
not checked - This can be exploited by malicious program to
change the flow of control to the malicious code
7In and Out of The Stack!
- Stack is a contiguous block of memory
- Stack Pointer (SP)
- Bottom of stack is a fixed address
- PUSH and POP operations defined on stack
- Stack consists of logical stack frames
- Frame Pointer (FP)
8Changing the Flow of Control
- Step 1 Injecting attack code into process memory
of the vulnerable process - Step 2 Overflowing a buffer in stack, that
writes to memory of process to alter data that
controls the execution flow
3. Contiguous Memory
Flow of Execution
Bad Pointer
Bad Code
Over flown
Buffer
9Changing the Flow of Control (cont)Attack
Targets
- The return address, allocated on the Stack
- The old base pointer, also on Stack
- Function pointers, allocated on Heap, in the BSS,
or Data segment, or on Stack either as local
variable or as a parameter - int (func_ptr) (char)
- Longjmp buffers, on Heap, in the BSS, or on Data
segment, or on the Stack either as local variable
or as a parameter - Not going through the chain of return addresses
10Lets C
- // example1.c
- void function( int a, int b, int c)char
buffer1 5char buffer210 - int main()function( 5, 1, 7)return( 1)
gcc S o example1.s example1.c pushl
3 pushl 2 pushl 1 call function pushl
ebp movl esp, ebp subl 20, esp
11Lets C (cont) Buffer Overflow
- // example2.c
- void function( char str)char buffer
16strcpy( buffer, str) - int main()char large_strlarge_str calloc(
256, A) - function(large_str)return(1)
Segmentation fault!!! Why?
12Previous Work
Static Analysis or Static Intrusion Prevention
- Looks for security bugs in source code
- ITS4
- Scans source code for known dangerous library
calls - Checks arguments to function calls and reports
severity of threat - Checks for other potential problems and race
conditions - Integer range analysis to locate potential buffer
overflows - Tracks allocated memory and possible length of
strings - This method is imprecise
- Someone has to keep an updated database of
programming flaws to test for
13Previous Work (Cont)
Dynamic Analysis or Dynamic Intrusion Prevention
- Examines program execution to determine whether
buffer overflow occur during execution - Compilers can add code to check bounds, or to
arrange data structures in memory to cause
hardware faults if bounds exceeds - Purify detects memory errors, out-of-bound
errors - Does its own memory bookkeeping
- Fuzz tests programs
- Provides programs with large, random streams of
characters - Property based testing program satisfy certain
properties - Main Problem Need of test data that causes
overflow - Tries to solve known security problems
14Interesting Functions!
- strcat( s, suffix) // is alloc(s) lt
len(s) alloc( suffix)? - strncat(dst, src, n) // is n len(dst)
gt alloc(dst)? - sprintf( dst, s, src) // is alloc( dst) lt
alloc( src)? - snprintf(dst, n, s, src)// is n gt alloc(
dst)? - fgest( s, n, ) // is alloc(s) lt
n? - memcpy(dst, src, n) // is ngt alloc(dst)?
- memncpy( dst, src, c, n) // is ngt alloc( dst)?
- memmove( dst, src, n) // is n gt alloc( dst)?
- bcopy( scr, dst, n) // is n gt alloc(
dst)?
15STOBO (Systematic Testing Of Buffer Overflow)
- Input source file
- Preprocessed
- Has the same behavior has P- Special function
calls replace each variable declaration,
declaring buffer, and standard C library
functions managing dynamically allocated memory
- Uses coverage metrics of interesting
functions
- Void func() char buf1100, buf2100,
buf3200 - Void func1() // STOBO outputchar buf1100,
buf2100, buf3200__STOBO_first_stack_buf(
buf1, sizeof( buf1))__STOBO_stack_buf( buf2,
sizeof( buf2))__STOBO_stack_buf( buf3, sizeof(
buf3))/ do stuff /
Description
Type
0
Src Dst statically allocated
Src dynamically allocated Dst statically
allocated
1
2
Dst dynamically allocated
16STOBO (cont ) (Systematic Testing Of Buffer
Overflow)
- // sample STOBO outputchar buf30char ptr1,
ptr2 -
- __STOBO_stack_buf(buf, sizeof( buf))
- ptr2 __STOBO_const_mem_malloc( 20)ptr1
buf 19__STOBO_strcpy( ptr1, ptr2)
- ptr1 is 10 bytes long
- ptr2 is 20 bytes long
- ptr2 is dynamically allocated buffer of constant
size - Issues a warning of type 0 for the strcpy()
operation
17Evaluation of STOBO on wu-ftpd
- Test Bed
- Wu-ftpd 2.4.2-beta-18, 2.5.0, 2.6.2
- Redhat 7.2 for i386
- wu-ftpd 2.4.2-beta-18 has some known bugs
misuse of strcat - These were uncovered with a warning of type 0
- Wu-ftpd 2.5.0 has 2 known bugs
- Misuse of strcat uncovered with a type 0
warning - Series of calls to sprintf and strcpy uncovered
with a type 0 and a type 1 warning
18Evaluation of STOBO on wu-ftpd (cont)Comparison
with ITS4
19Evaluation of STOBO on net-tools
- Test Bed
- net-tools-1.46
- Redhat 7.2 for i386
- // bug uncovered type 1 warning
-
- if (( np getnetbyname(name))! (struct netent
) NULL) - sin-gtsin_addr.s_addr htonl(np-gtn_net)
strcpy( name, np-gtn_name) return 1
20Evaluation of STOBO
- Authors claim STOBO did a good job
- Wu-ftpd-2.6.2 false positive rate was 0.67
fp/tp whereas ITS4s was 4.97 - type 2 warnings are false positive
- Programmers usually determine the amount of
dynamically allocated destination storage
correctly - STOBO found none involving functions that take a
buffer length parameter, strncpy, strncat,
snprintf - When programmers fill buffers using functions
that take a length parameter, they tend to use
the length parameter correctly - Suggest use of strlcpy instead of strncpy
- Makes it harder to commit off-by-one error
- STOBO failed for segments of code that were in
if else endif preprocessor statements
21StackGuard
- Designed for detecting and stopping stack-based
overflows targeting the return address - Key idea buffer overflow attacks overwrites
everything on their way towards their target
return address. Place a dummy value somewhere in
between canary - Check to see if this dummy value is intact
22StackGuard ( cont)
- Canary can still be intact if the attacker
overwrites it with the correct value - Solution use random canary value
- Use terminator canary consists of all string
terminator sequences NULL, \r, \n, -1 - Attacker can still point to the return address
and change it, without worrying about the canary - This is a short-coming of StackGuard
- Can be dealt by XORing the canary value and
return address to detect if return address
has changed
23Stack Shield
- Compiler patch for GCC, providing 3 types of
protection - return address overwriting protection
- Global Ret Stack
- Maintains a global array of 32-bit entries,
maximum of 256 entries - The return address being pushed on normal stack
is also copied onto this array, and while
retrieval is copied back to normal stack - No detection, just prevention
- Ret Range Check
- Maintains a global variable, stores the return
address of the current function, and copies back
when pushed out the normal stack - Checks if both are same, halts execution if not
detect attack!
24Stack Shield (cont)
- function pointer overwriting protection
- Assumes that programmer doesnt use dynamically
function pointers - Attacker can only put malicious code in
Data/BSS/Heap/Stack - Check to see that a function pointer is not
pointing back to any other location than Text
segment - Uses a global variable to mark the Text segments
boundary - Adds checking code before all function calls to
see if its pointing anywhere other than Text
segment - Does Detection
25ProPolice
- Perhaps most sophisticated compiler protection
- Rearrange local variables such that char buffers
always are allocated at bottom addresses ( top of
the stack), and are guarded by a Guard Value - Does not work fine with small buffers somewhat
unstable
26Libsafe and Libverify
- These tools are combination of static and dynamic
intrusion prevention - Statically, it patches library functions that
constitute potential buffer overflow
vulnerabilities - Dynamically, libverify uses similar approach as
StackGuard
Local Variables
Lower address
Old Base Pointer
BoundaryAddress
Return Address
Arguments
Higher address
8. LibSafe Stack Frame
27Libsafe and Libverify (cont)
- Libsafe estimates safe bounds for buffers on
stack at run-time and checks this boundary before
any vulnerable function is allowed to write to
buffer - Uses old base pointer as safe boundary
- Enforced using overloading vulnerable functions
- Overflows within local variables on stack, such
as function pointers, are not stopped - Vulnerable Functions
- Strcpy, strcat, getwd, gets, scanf, realpath,
sprintf
28Libsafe and Libverify (cont)
- Libsafe enhancement libverify enforces return
address verification like StackGuard - Canary stack located in Heap, all return
addresses copied onto this - Execution halted if both addresses dont match
- Doesnt protect integrity of canary stack
29Comparison of StackGuard, Stack Shield,
ProPolice, Libsafe, Libverify
- Test Bed
- Techniques
- Overflow all the way to the target
- Overflow buffer to redirect a pointer to target
- Locations
- Stack
- Heap
- BSS Segment
- Data Segment
- Attack Targets
- Return address
- Old base pointer
- Function pointer
- Longjmp buffers
30Comparison of StackGuard, Stack
Shield,ProPolice, Libsafe, Libverify ( cont)
- Buffer overflow on stack all the way to target
- Return address
- Old base pointer
- Function pointer as local variable
- Function pointer as parameter
- Longjmp buffer as local variable
- Longjmp buffer as function parameter
- Buffer overflow on Heap/BSS/Data all the way to
target - Function pointer
- Longjmp buffer
- Buffer overflow of a pointer on stack and then
pointing at target - Return address
- Old base pointer
- Function pointer as variable
- Function pointer as parameter
- Longjmp buffer as variable
- Longjmp buffer as function parameter
- Buffer overflow of a pointer on Heap/BSS/Data and
then pointing at target - Return address
31Absolutely NO preventionor detection for buffer
overflowin Heap/BSS/Data Segments
32Theoretical tests doesnt matchempirical test
results
33Others Dynamic Solutions
- Return Address Defender (RAD)
- Idea similar to Stack Shield
- Stack Ghost, GCC patch
- Both XORing the random canary value with return
address( as StackGuard), as well as keeping a
separate stack for return address ( as Stack
Shield, RAD, libverify) - Also suggest cryptographic methods instead of XOR
- CCured and Cyclone
- Both extensions of C programming language
- Differentiates between various kinds of pointers
- Average of 10 lines of code to be change when
migrating from C to Cyclone - Richard Jones and Paul Kelly GCC compiler patch
- More than 400 performance penalty
- Non-Executable Stack
- Injection of attack code in stack useless
- David Wagner and Drew Dean Good behavior of
program - Good behavior defined via static analysis
- Any deviation from this triggers an intrusion
alarm
34Common Problems
- Denial of Service Attacks
- Tools tend to Halt execution upon detection of
intrusion - Storage Protection
- Separate stacks used along with normal stack to
verify return addresses and function pointer
bounds can be corrupted - StackGuard with terminator canary offers storage
protection - Recompilation of Code
- Compiler patcher require recompilation
- Libsafe/libverify are more convenient
- Limited Nesting Depth
- When keeping separate stacks with copies of
return address, nesting depth of process is
limited
35The Defense Against The Dark ArtsConclusion
- No software can be 100 bug free
- We can not possibly predict the thought process
of a malicious user - As of now, the tools that we have can only
prevent us from known attacks - Security flaws like buffer overflows can be
reduced by enforcing better programming practices
from the very early stages of Software
Engineering - Use of wrappers
- Use of available tools to reduce the number of
flaws - Training software programmers with Good
programming practices - Use of memn() functions instead of str()
functions - calloc() instead of malloc()
- Proper free()ing of memory
- Proper use of static, auto, global variables
- Explicit initialization and resetting of
variables - Modularization for easier debugging
- Use of Artificially Intelligent Agents for
intrusion detection!