310 likes | 442 Views
Defeating Security Attacks Through Runtime Mechanisms. Jun Xu Center for Reliable and High-Performance Computing Coordinated Science Lab. & Dept. of Computer Science University of Illinois at Urbana-Champaign http://www.crhc.uiuc.edu/DEPEND/. Secure and Dependable Computing.
E N D
Defeating Security Attacks Through Runtime Mechanisms Jun Xu Center for Reliable and High-Performance Computing Coordinated Science Lab. & Dept. of Computer Science University of Illinois at Urbana-Champaign http://www.crhc.uiuc.edu/DEPEND/
Secure and Dependable Computing • Experimental Analysis of Security and Dependability • Measurement-based study of operational data • 200 machine-years Windows failure data from Microsoft • Security vulnerability data from CERT and SecurityFocus • Test-bed for experimentation with security attacks and fault injections • Study of a broad spectrum of security attacks • Impact of errors on security –fault injection, SAN model (with S. Chen) • Runtime software/hardware mechanisms for vulnerability masking • Two generic and complimentary software protection mechanisms • Transparent Runtime Randomization • Control Data Randomization • Architectural support for security • Reliability and Security Engine (with N. Nakka, Y. Perzov) • Secure Return Address Stack (SRAS)
Motivation • 60% of all CERT security advisories (1999-2002) • Programming bugs introduced when implementing software • Buffer overflow, format string, double free, integer overflow • Observation: • Implementation bugs are fact of life • Customized solutions exist for some subclasses vulnerabilities • Generic techniques needed for masking broad-range of vulnerabilities
Outline • Introduction • Transparent Runtime Randomization (TRR) • Control Data Randomization (CDR) • Architecture support for security • Reliability and Security Engine (RSE) • Secure Return Address Stack (SRAS) • Conclusion and Future Work
p m msg.fptr = printf msg.fptr = m msg.buf[96] … malicious code malicious code m How Attacks Work? • Two conditions for a successful attack • Injecting malicious code/data at address m in app. memory • Changing control data at address p to point to m struct message { char buf[96]; int (*fptr)(char*); }; struct message msg; int get_message(…){ msg.fptr = printf; gets(msg.buf); msg.fptr(msg.buf); }
Characteristic of the Attacks • Key to a successful attack • Correctly determine the runtime values of m or p • An attacker’s approach • Determine the type/version of the target OS and application • Configure a pilot system, experiment with it • Construct the malicious input • Why runtime values of m or p can be determined? • Memory layout is fixed and addresses are highly predictable • Lack of diversity in modern systems • O.S. memory management is fixed • Once compiled and deployed, a program’s memory layout remain fixed across its lifetime • Uniformity becomes unnecessary burden
Transparent Runtime Randomization • Introduce diversity into a system • Dynamically randomize the memory layout of a program • Each invocation has a different layout • Defeating attacks • Breaks memory layout assumption • Make it hard to determine m/p • Implementation – transparent to application • Modify Linux kernel and dynamic program loader • Memory regions that can be randomly placed • Position independent regions: stack, heap, shared libraries • Position dependent regions: global offset table (GOT)
Position Independent Regions • Different sections at different fixed locations • Change the kernel routines • Part of the process initialization modules • Random offset is applied to different regions 0xFFFFFFFF Kernel space 0xC0000000 0xBFFFFFFC - Rand user stack shared libraries 0x40000000 ± Rand user heap End_of_bss + Rand bss static data use code 0x08048000
Position Dependent Region Relocated GOT new_got_printf: addr of printf() heap GOT got_printf: addr of printf() GOT got_printf: addr of printf() data PLT plt_printf: jmp *got_printf Changed PLT plt_printf: jmp *new_got_printf code Program code call plt_printf Program code call plt_printf
Operations of TRR – An Example user type netscape shell creates new process using fork load & init netscape using execve() syscall execve() syscall: 1. maps executable to memory 2. sets code/data segments 3. TRR randomly places stack, heap, dynamic program loader 4. transfers control to dynamic program loader dynamic program loader 1. maps shared libs to memory 2. TRR randomly relocates prog. GOT and rewrite PLT netscape begins to execute
Performance Evaluation • Program initialization overhead • Kernel instrumentation: btw. execve and start of program execution • Measured in number of clock cycles, converting to micro-seconds • Overhead – 1% to 6% • NO overhead once the program begins execution • Memory cost – extra copy of GOT – 200 Byte to 3.5 KB
Summary – Transparent Runtime Randomization • Transparently introduce diversity into a system • Makes address values unpredictable • Breaks the memory assumption by attackers • Low overhead, transparent to applications • Problem • Data segment cannot be randomized
Outline • Introduction • Transparent Runtime Randomization (TRR) • Control Data Randomization (CDR) • Architecture support for security • Reliability and Security Engine (RSE) • Secure Return Address Stack (SRAS) • Conclusion and Future Work
p m msg.fptr = printf msg.fptr = m msg.buf[96] … malicious code malicious code m How Attacks Work? • Two conditions for a successful attack • Injecting malicious code/data at address m in app. memory • Changing control data at address p to point to m struct message { char buf[96]; int (*fptr)(char*); }; struct message msg; int get_message(…){ msg.fptr = printf; gets(msg.buf); msg.fptr(msg.buf); }
Control Data Randomization • Control data • Data used for control flow transfer – return address, function pointer • Control data are in writable memory, can be maliciously overwritten • Control data randomization – detect malicious change • Encode control data when they are defined • Decode control data whenever they are used • Without knowing the key, cannot take control of a program • Decoding and use of un-encoded value causes crash • Randomization key is generated each time a program invoked • Formally • a: addr. of data, v: real value of data, k : the encoding key • decode(k , encode(k , v)) = v • val(a) encode(k , v) • c_val (a) = decode(k , val(a)) = decode(k , encode(k , v)) = v • An attacker overwrites addr a using value v’ val(a) = v’ c_val(a) = decode(k , val(a)) = decode(k , v’)v
encoding decoding Example of Control Data Randomization struct message { char buf[96]; int (*fptr)(char*); }; struct message msg; int get_message(…){ msg.fptr = printf; gets(msg.buf); msg.fptr(msg.buf); } struct message { char buf[96]; int (*fptr)(char*); }; struct message msg; int get_message(…){ msg.fptr = printf; msg.fptr = msg.fptr XOR KEY gets(msg.buf); tmp_fptr = msg.fptr XOR KEY tmp_fptr(msg.buf); }
Function Pointers • Not all cases of define/use should be randomized • May force an FP’s value into an unknown state • Define of fp: • From symbolic function name: fp printf (encode) • Implicit define: return printf, func(printf) … • From value propagation: fp fp’ • Use of fp: • For control flow transfer: call *fp (decode) • For explicit value propagation: fp’ fp • For implicit propagation: return fp, func(fp) …
Function Pointer Define & Use Example int (*global_fptr) () = main; int main() { static int (*static_fptr)() = main; int (*auto_fptr)() = main; global_ftpr = open; auto_fptr = main; return open; open(main) auto_fptr = global_fptr; open(global_fptr); return auto_fptr; (*auto_fptr)(); } definition from symbol Implicit definition from symbol use – value propagation use – control transfer
Initialized Function Pointer • Function pointer initialization in declaration • FP as Automatic variables • Initialization is done through compiler generated code • CDR generates extra code to encode FP at runtime • FP as global/static variables • No code is generated by the compiler • The linker determines the value of FP, stores in the executable file. • Global/static FP Initialization Handling • Not possible to encode at link time – key not available • CDR solution: • Tag initialized global/static FP in parsing phase • Place the address of FP in a special read-only section in the object file • Merge all such sections from object files into one section at link time • Generates special code in the executable to encode these FP when the process is initialized
Function Pointer Initialization Example int (*global_fptr) () = main; int main() { static int (*static_fptr)() = main; int (*auto_fptr)() = main; global_ftpr = open; auto_fptr = main; return open; open(main) auto_fptr = global_fptr; (*auto_fptr)(); } global/static variable pointer initialization automatic FP init
CDR Implementation • Change the GNU C compiler gcc. • At parsing phase, RTL phase, assembly generation phase, linking phase • Code instrumentation done before optimization phase • For function pointers – parsing phase • Determine if encoding/decoding needed • Add extra nodes to intermediate tree for encoding and decoding • Special handling initialized global/static FPs – parsing, assemble, linking • For return addresses – RTL phase • Encode immediately after entering the function • Decode immediately before returning • Current encoding and decoding function: XOR • Random key generated at process initialization time, stored a read-only location
Performance Evaluation • SPEC 2000 Integer Benchmarks • C Library is also compiled using the new compiler • Performance Overhead ranges from 1% to 5% • Most overhead is due to randomization of RA (return address)
Evaluation – Effectiveness • Experimental evaluation • Security test-bed, real-world application, vulnerabilities and attacks • Representing different types of vulnerabilities • Result • Local or remote shell – attack succeeds; Crash – attack fails • Crash is preferred to being hijacked • Contributions – mask a broad range of vulnerabilities
Outline • Introduction • Transparent Runtime Randomization (TRR) • Control Data Randomization (CDR) • Architecture support for security • Reliability and Security Engine (RSE) • Secure Return Address Stack (SRAS) • Conclusion and Future Work
checker 1 checker 2 checker n Reliability and Security Engine (RSE) Processor Fetch Decode Execute MEM Write Reliability & Security Engine instruction queue
f1() f2() f3() return address 1 return address 2 return address 3 saved ebp saved ebp saved ebp Local variables Local variables Local variables Protection Return Address – Safe Copy • Current unified stack shares storage for: • Control information (return address) • Data: parameters, temporary variables, buffers • When buffer is overrun, the return information is tampered • A Safe Copy of Return Address • Save an extra copy for detection
Malicious Data & Code return address 3 return address 1 return address 1 return address 2 return address 3 return address 2 saved ebp saved ebp saved ebp saved ebp saved ebp saved ebp Local variables Local variables Local variables Local variables Local variables Local variables return address 1 return address 1 return address 2 return address 2 return address 3 return address 3 Safe Copy Safe Copy Memory Stack Memory Stack Safe Copy of Return Address Safe copy is immune! Attack
Secure Return Address Stack (SRAS) • Software Implementation • Changed the C Compiler, overhead up to 20% • Exploiting existing hardware mechanism to reduce overhead • Return Address Stack (RAS) • Implemented in fetch stage of modern processor • Improve effective fetch bandwidth • High prediction rate > 99% • Redundant hardware copy of return addresses • SRAS • Utilize the redundant hardware copy • Hardware copy is immune from buffer overrun • Detect return address tampering (stack smashing) when misprediction occurs
SRAS Design Options • Speculative SRAS • Use the existing RAS, exception if misprediction • Source of misprediction: speculative update, overflow, attack • Non-speculative SRAS • An extra copy of RAS at commit stage • Source of misprediction: overflow, attack • Non-speculative SRAS with overflow handling • As Non-speculative SRAS • Handles SRAS overflow • Source of misprediction: attack
Summary and Future Directions • Summary • Transparent Runtime Randomization • breaking attacks by making address values unpredictable • Control Data Randomization • breaking attacks by encoding/decoding control data • Reliability & Security Engine, Secure Return Address Stack • A step toward architectural support for security • Future Directions • Check-pointing and Recovery mechanisms for TRR and CDR • Large scale data analysis on causes of vulnerabilities • Identify patterns and build checking tools • Continue the work on Reliability and Security Engine • Intrusion detection and tolerance in wired and wireless environment • Security and dependability for future ubiquitous wireless access network • Experimentally study the underlying issues • Investigate trust-relationship and failure behavior in the hierarchy