Mitigation against Buffer Overflow Attacks 1 Stack Overflow
Mitigation against Buffer Overflow Attacks 1
Stack Overflow Review • A buffer on the stack has an un-checked bound. – A malicious input could modify program control flow by overwriting data on the stack, e. g. saved EIP. – Malicious code can be injected on the stack and EIP can be made to point to it. • Key to a successful stack overflow attack – The modified control gets loaded into EIP • e. g. the vulnerable function successfully “returns; ” – Must be able to predict the address of the injected code – The injected code must be executable 2
Mitigation 1: stack address randomization • The OS randomly picks a location for the program stack. – The chance the attacker can guess the correct stack location is slim. – Where shall EIP point to? • However, there are multiple ways to get around it. 3
Getting around stack randomization through indirect jump beginning of the buffer NOP sled Shell Code EIP Shell Code ESP 0 x 42122 ba 7: JMP ESP (0 xffe 4) 4
Some Useful Points • ldd program_name – Displays the dynamically linked libraries and their entrance addresses • You can search the jump code directly in any program’s address space as long as it links the same libraries at the same locations as the target program 5
Thoughts • Any register that points to somewhere after the beginning of the vulnerable buffer could work. • We can look for the “jump code” by searching the virtual memory space. – System libraries are a good place to start. – A library’s code may not even have the jump code in its instructions, but we could still find the jump code anyway (Why? ). 6
Stack. Guard • A compile-time mechanism that detects/prevents modification of saved EIP during function execution. – When the function starts, a “canary word” is put on the stack in between the function’s local variables and saved EIP. – If a local buffer is overrun, the canary will have to be “killed” before the saved EIP can be modified. – Before function returns, checks whether the canary is still intact. If not, hand program control to a predefined exception handler and terminate the program. 7
. text. data heap malloc’ed data Stack. Guard > heap < address growth ESP EBP stack local AAAAAA variables AAAAAAAA A A AEBP A saved A A Aword A canary A A AEIP A saved function’s argument function’s return address main() local variables argc, **argv, **envp environment var’s bottom of stack 8
Types of Canary • Terminator canary – A character that in most cases will terminate a malicious string, e. g. NULL. • Random canary – A random value produced at program execution time – The random value is stored in a global variable • XOR canary – A random value XOR’ed with saved EIP – On function return, the canary is XOR’ed with the random value and the result compared with saved EIP 9
Limitation of Stack. Guard • Will not work if the exploit does not depend upon modifying saved EIP – Buffer overflow in certain stack layouts could give the attacker ability to modify any memory location with any value – This opens up a number of new options to hijack the program’s control flow, e. g. modify the entrance table of exception handlers or system functions • The same limitation applies to other similar mechanisms – e. g. Stack. Shield 10
Circumvent Stack. Guard . text. data heap malloc’ed data > heap < address growth ESP EBP stack AAAAAA char buf[]; AAAAAAAA char* ptr; saved EBP canary word saved EIP function’s argument main() local variables argc, **argv, **envp environment var’s bottom of stack Unsafe copy overwrites value of ptr (where). function body: … copy(buf, attacker-controlled data); … copy(ptr, attacker-controlled data); … Any copy with attacker-provided data (what) Modify any memory location (where) with arbitrary data (what). 11
Non-executable Stack • OS/architecture protection of virtual memory so that injected code cannot run – NX/XD bit: mark certain memory pages (e. g. stack pages) non-executable (DEP) – W^X protection: a page cannot be both writable and executable • Consequences – Injected shellcode on the stack cannot be executed – Deviates from von-Neumann architecture • e. g. run-time code generation may be affected 12
Limitation of non-executable stack • Will not work if the exploit does not rely on code injected on the stack. – Code can be injected in other memory segments, e. g. heap. – Or no need to inject code at all! 13
Getting around non-executable stack through return-into-libc AAAAAAAAAAAAAA ? ? EIP ? ? W 1 ESP ? ? W 2 libc’s return address libc’s argv[1] entrance address of a libc function system(…); entrance address of the next libc function you want to run, e. g. , exit(); “/bin/sh” 14
Thoughts • Whenever a new defense against software exploit is invented, a new way to get around it emerges. – These defensive mechanisms are reactive and address a particular way of attack, not the underlying vulnerability. – Nonetheless they provide an important line of defense for software vulnerabilities. – To reduce the “attack surface, ” we must also address the underlying vulnerabilities. • Defensive programming • Using type-safe languages and static code analysis 15
Implication on System Security • We must assume that software applications will have security vulnerabilities in them – Proper design of protection mechanisms is essential to mitigate threats. 16
- Slides: 16