secure programming lecture 6: memory corruption iv ... · É a safe compiler to automatically...

43
Secure Programming Lecture 6: Memory Corruption IV (Countermeasures) David Aspinall, Informatics @ Edinburgh 30th January 2014

Upload: others

Post on 23-Sep-2020

0 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: Secure Programming Lecture 6: Memory Corruption IV ... · É a safe compiler to automatically generate checking code that checks bounds or types dynamically, during execution. É

Secure Programming Lecture 6: MemoryCorruption IV (Countermeasures)

David Aspinall, Informatics @ Edinburgh

30th January 2014

Page 2: Secure Programming Lecture 6: Memory Corruption IV ... · É a safe compiler to automatically generate checking code that checks bounds or types dynamically, during execution. É

Outline

Announcement

Recap

Containment and curtailment

Stack tamper detection

Memory mode protection

Diversification

Secure programming

Summary

Page 3: Secure Programming Lecture 6: Memory Corruption IV ... · É a safe compiler to automatically generate checking code that checks bounds or types dynamically, during execution. É

Outline

Announcement

Recap

Containment and curtailment

Stack tamper detection

Memory mode protection

Diversification

Secure programming

Summary

Page 4: Secure Programming Lecture 6: Memory Corruption IV ... · É a safe compiler to automatically generate checking code that checks bounds or types dynamically, during execution. É

Lab session tomorrow

The first Secure Programming Laboratory will betomorrow!

Friday 31st January, 2pm-5.30pm in AT 5.04.

Please arrive on time, the lab will start with a demointroduction.

Recommended:

É find someone to work with (pairs rather than largergroups).

É preparation: study the lectures on overflowscarefully, try out some examples.

Page 5: Secure Programming Lecture 6: Memory Corruption IV ... · É a safe compiler to automatically generate checking code that checks bounds or types dynamically, during execution. É

Outline

Announcement

Recap

Containment and curtailment

Stack tamper detection

Memory mode protection

Diversification

Secure programming

Summary

Page 6: Secure Programming Lecture 6: Memory Corruption IV ... · É a safe compiler to automatically generate checking code that checks bounds or types dynamically, during execution. É

Memory corruption attacks

We’ve seen memory corruption attacks on the heap, onthe stack and elsewhere.

Overflow vulnerabilities in code are caused by, forexample:

É unchecked buffer boundariesÉ out-by-one errorsÉ integer overflowÉ type confusion errors

Page 7: Secure Programming Lecture 6: Memory Corruption IV ... · É a safe compiler to automatically generate checking code that checks bounds or types dynamically, during execution. É

Memory corruption countermeasures

Two basic programming-related countermeasures:

1. Treat the symptoms:É special technologies in execution or compilationÉ limit the damage that can be done by attacksÉ containment and curtailment

2. Treat the causeÉ ensure that code does not contain vulnerabilitiesÉ secure programming through code review,

analysis tools

Question. Why might choice 2 be impossible?

Page 8: Secure Programming Lecture 6: Memory Corruption IV ... · É a safe compiler to automatically generate checking code that checks bounds or types dynamically, during execution. É

Outline

Announcement

Recap

Containment and curtailment

Stack tamper detection

Memory mode protection

Diversification

Secure programming

Summary

Page 9: Secure Programming Lecture 6: Memory Corruption IV ... · É a safe compiler to automatically generate checking code that checks bounds or types dynamically, during execution. É

Generic defences

Defensive technologies are not a real substitute forproper fixes, but:

É give defence in depth security that can protect incase of accidently running malware or regressionsto vulnerable code;

É sometimes code replacement is simply prohibitivelyexpensive or impossible (e.g. non-upgradeablefirmware)

Page 10: Secure Programming Lecture 6: Memory Corruption IV ... · É a safe compiler to automatically generate checking code that checks bounds or types dynamically, during execution. É

Defences against overflows

Several generic protection mechanisms have beeninvented to prevent overflow attacks and new ones areevolving.

These reduce the attackers chance of reliably exploitinga bug on the host system.

We will look at:

É Tamper detectionÉ Memory protection in OS and hardwareÉ Diversification methods

Page 11: Secure Programming Lecture 6: Memory Corruption IV ... · É a safe compiler to automatically generate checking code that checks bounds or types dynamically, during execution. É

Outline

Announcement

Recap

Containment and curtailment

Stack tamper detection

Memory mode protection

Diversification

Secure programming

Summary

Page 12: Secure Programming Lecture 6: Memory Corruption IV ... · É a safe compiler to automatically generate checking code that checks bounds or types dynamically, during execution. É

Canaries on the stack

Each stack frame includes vulnerable location pointerswhich may be corrupted in a stack overflow attack.

Idea:

É wrap frame with protective layer, a “canary”É canary sits below return addressÉ attacker overflows stack buffer to hit return address

É necessarily overwrites canary

É generated code adds and checks canaries

Early proposal: StackGuard compiler.

Page 13: Secure Programming Lecture 6: Memory Corruption IV ... · É a safe compiler to automatically generate checking code that checks bounds or types dynamically, during execution. É

Stack without canaries

Page 14: Secure Programming Lecture 6: Memory Corruption IV ... · É a safe compiler to automatically generate checking code that checks bounds or types dynamically, during execution. É

Stack with canary

Question. How might this mechanism be defeated?

Page 15: Secure Programming Lecture 6: Memory Corruption IV ... · É a safe compiler to automatically generate checking code that checks bounds or types dynamically, during execution. É

GCC’s Stack Smashing Protector

Consider this C program:

#include <stdio.h>#include <string.h>

int fun1(char *arg) {char buffer[1024];strcpy(buffer,arg);

}

void main(int argc, char *argv[]) {fun1(argv[1]);

}

Page 16: Secure Programming Lecture 6: Memory Corruption IV ... · É a safe compiler to automatically generate checking code that checks bounds or types dynamically, during execution. É

fun1: ; code without SSPpushl %ebpmovl %esp, %ebpsubl $1048, %espmovl 8(%ebp), %eaxmovl %eax, 4(%esp)leal -1032(%ebp), %eaxmovl %eax, (%esp)call strcpyleaveret

main:pushl %ebpmovl %esp, %ebpandl $-16, %espsubl $16, %espmovl 12(%ebp), %eaxaddl $4, %eaxmovl (%eax), %eaxmovl %eax, (%esp)call fun1leaveret

Page 17: Secure Programming Lecture 6: Memory Corruption IV ... · É a safe compiler to automatically generate checking code that checks bounds or types dynamically, during execution. É

fun1: ;; code with SSP (main function stays the same);; Note: GS register points to per-CPU thread;; memory storagepushl %ebpmovl %esp, %ebpsubl $1064, %espmovl 8(%ebp), %eaxmovl %eax, -1052(%ebp)movl %gs:20, %eax ; set EAX=canary valuemovl %eax, -12(%ebp) ; store near return addressxorl %eax, %eaxmovl -1052(%ebp), %eaxmovl %eax, 4(%esp)leal -1036(%ebp), %eaxmovl %eax, (%esp)call strcpymovl -12(%ebp), %edx ; EDX=canary from stackxorl %gs:20, %edx ; has it changed?je .L3 ;call __stack_chk_fail ; if it has, we’ll abort

.L3:leaveret

Page 18: Secure Programming Lecture 6: Memory Corruption IV ... · É a safe compiler to automatically generate checking code that checks bounds or types dynamically, during execution. É

the stack protection spots an overflow with 1026characters:

$ gcc -m32 overflow.c -o overflow.out$ ./overflow.out xxxx$ ./overflow.out ‘perl -e ’print "x"x1025’‘*** stack smashing detected ***: ./overflow.out terminatedAborted (core dumped)

Page 19: Secure Programming Lecture 6: Memory Corruption IV ... · É a safe compiler to automatically generate checking code that checks bounds or types dynamically, during execution. É

Canary arms race

The arms race in general: attackers respond to newprotection mechanisms by looking for vulnerabilities inthose mechanisms. . .

For example:

É Attack code/probing discovers a constant canaryÉ e.g., canary is 0x0af237ab6, so write that near

return address

É Canary defence uses pseudorandom sequenceÉ attacker learns sequence or discovers seed

É Canary defences uses cryptographic PRNGÉ attacker finds where value is storedÉ finds another exploit to copy it

Page 20: Secure Programming Lecture 6: Memory Corruption IV ... · É a safe compiler to automatically generate checking code that checks bounds or types dynamically, during execution. É

Effectiveness

É Doesn’t protect against local variable overwritingÉ related protection mechanisms reorder local

variables

É Other attacks work by overwriting parametersÉ aim to change where subsequent writes occurÉ overwrite return address, but don’t return

É Hardened heap implementations have also beendevelopedÉ glibc and Windows since XP SP2 have heap canaries

É Self-managed memory mechanisms not addressedÉ e.g., HLL runtimes, application specific heaps

É Return-oriented programming (ROP)É state-of-the-art: use existing executable codeÉ evades canaries, also defeats NX (see below)

Page 21: Secure Programming Lecture 6: Memory Corruption IV ... · É a safe compiler to automatically generate checking code that checks bounds or types dynamically, during execution. É

Outline

Announcement

Recap

Containment and curtailment

Stack tamper detection

Memory mode protection

Diversification

Secure programming

Summary

Page 22: Secure Programming Lecture 6: Memory Corruption IV ... · É a safe compiler to automatically generate checking code that checks bounds or types dynamically, during execution. É

Operating system separation (review)

Isolation different processes have different resources(address spaces, file systems, . . . )

Sharing resources are shared between processes,partial isolation. Sharing may be:

É all or nothingÉ mediated with access controlsÉ mediated with usage controls (capabilities)

Concern: granularity of protection.

OSes have provided separation mechanisms since theearly days of multi-user systems. For memory, directsupport was added to the CPU and memory systemhardware.

Page 23: Secure Programming Lecture 6: Memory Corruption IV ... · É a safe compiler to automatically generate checking code that checks bounds or types dynamically, during execution. É

Hardware memory protection mechanisms

Original mechanisms introduced to provide separation(mainly for safety) between different programs onmulti-user systems:

É Fences: separate memory accesses between OSand user code (one boundary, one way protection).

É Base and bounds registers: enforce separationbetween several programs allowing access controlon memory ranges.

É Tagged architecture: more fine-grained, tags oneach memory location set access rights to storedword (R, RW, X). Supervisor mode instructionsrequired to set tag. Not currently supported inmodern architectures.

Page 24: Secure Programming Lecture 6: Memory Corruption IV ... · É a safe compiler to automatically generate checking code that checks bounds or types dynamically, during execution. É

OS memory segmentation

Segmentation splits a program into many variablesized pieces, each with a name.

É mainÉ dataÉ moduleÉ libraryÉ . . .

É Programs access memory using names and offsets.É Segmentation table maintained by OS, use

segment registers for indexing.

Page 25: Secure Programming Lecture 6: Memory Corruption IV ... · É a safe compiler to automatically generate checking code that checks bounds or types dynamically, during execution. É

OS memory segmentation

Pros:

É memory locations abstract from physical memoryÉ OS can move things aroundÉ segments can be shared between programsÉ different segments may have different access

rightsÉ user programs cannot access locations outwith

their segments

Cons:

É seg names mapped to the numbers for efficiencyÉ segfaults: must dynamically check boundsÉ fragmentation of memory

Page 26: Secure Programming Lecture 6: Memory Corruption IV ... · É a safe compiler to automatically generate checking code that checks bounds or types dynamically, during execution. É

OS paging

Paging splits a program into fixed-sized pieces. Theseget mapped onto memory which is split intoequal sized page frames.

Pros:

É fixed sizes easier to manage, avoid fragmentationÉ transparent to programming model

Cons:

É vs segmentation, lose logical control over regionsÉ access control granularity increasedÉ potential for wasted space

Page 27: Secure Programming Lecture 6: Memory Corruption IV ... · É a safe compiler to automatically generate checking code that checks bounds or types dynamically, during execution. É

Combined paging and segmentation

É Access via segment table + page translationÉ Combines advantages of each.É Designed for efficient memory allocation/relocationÉ Memory protection useful secondary benefit

Modern solution since Multics. Relies on only twoprotection levels supported in the hardware.

Exercise. Why might more protection levels be better?What is the reason only two levels are currentlysupported?

However, complex/portable OSes prefer to use softwareand work over a flat memory model. The x86 and Linuxwork over a flat model.

Page 28: Secure Programming Lecture 6: Memory Corruption IV ... · É a safe compiler to automatically generate checking code that checks bounds or types dynamically, during execution. É

Non-executable memory pages

CPU have often included R, RW, X protection formemory pages.

É x86 series CPUs added page-level XD/NX in 2001-4

By enforcing non-executable regions, if the programkeeps code and data separate, shellcode can beprevented from running when it’s injected into dataregions on the heap or stack.

É Compared with C, more tricky for certainlanguages/compilers/interpreters, which maymanipulate executable code during runtime.

Page 29: Secure Programming Lecture 6: Memory Corruption IV ... · É a safe compiler to automatically generate checking code that checks bounds or types dynamically, during execution. É

Outline

Announcement

Recap

Containment and curtailment

Stack tamper detection

Memory mode protection

Diversification

Secure programming

Summary

Page 30: Secure Programming Lecture 6: Memory Corruption IV ... · É a safe compiler to automatically generate checking code that checks bounds or types dynamically, during execution. É

Address Space Layout Randomization (ASLR)

Concept: use diversification to make many versions ofsame program; thwarts general attacks that makeassumptions about fixed structure.

ASLR: make it harder to find data or code locations, byrandomising layout during load time. Breakshard-coded static locations.

Implemented in Linux by the PaX Team.

Effectiveness: good, but doesn’t remove mainvulnerability and vulnerabilities in ASLR implementationbecome target of attack. Early implementationsrandomised by small amounts (e.g. 256 addresses), soattacker could use brute force to find the vulnerablelocations. Such attacks may attract attention (sincefailures cause crashes).

Page 31: Secure Programming Lecture 6: Memory Corruption IV ... · É a safe compiler to automatically generate checking code that checks bounds or types dynamically, during execution. É

Outline

Announcement

Recap

Containment and curtailment

Stack tamper detection

Memory mode protection

Diversification

Secure programming

Summary

Page 32: Secure Programming Lecture 6: Memory Corruption IV ... · É a safe compiler to automatically generate checking code that checks bounds or types dynamically, during execution. É

Defensive programming: bounds checking

Defensive programming to avoid overflow requiresbounds checking.

É Check data lengths before writingÉ Check array subscripts are within limitsÉ Check boundary conditions to avoid OBOÉ Constrain size of inputsÉ Beware of dangerous API calls to risky code

Page 33: Secure Programming Lecture 6: Memory Corruption IV ... · É a safe compiler to automatically generate checking code that checks bounds or types dynamically, during execution. É

Responsibility for bounds checking

Like many security checks, this is a sharedresponsibility. It requires checking at each point, bythe:

É programmerÉ programming language, compilerÉ OSÉ hardware

Exercise. For each role, give an example of what theydo to check bounds.

Page 34: Secure Programming Lecture 6: Memory Corruption IV ... · É a safe compiler to automatically generate checking code that checks bounds or types dynamically, during execution. É

Bounds checks by programmer

int a[20], i;for (i=0, i<20; i++) {

a[i] = 0;...

}

É How can this go wrong?

Page 35: Secure Programming Lecture 6: Memory Corruption IV ... · É a safe compiler to automatically generate checking code that checks bounds or types dynamically, during execution. É

Bounds checks by programmer

int a[20], i;for (i=0, i<20; i++) {

if (i<0) signal error;if (i >= 20) signal error;a[i] = 0;...

}

É Checking every time seems inefficientÉ Are both checks required?É Tempting to skip. . .

Page 36: Secure Programming Lecture 6: Memory Corruption IV ... · É a safe compiler to automatically generate checking code that checks bounds or types dynamically, during execution. É

Bounds checks by programmer

int a[20], i, max;...

for (i=0, i<max; i++) {if (i<0) signal error;if (i >= 20) signal error;a[i] = 0;...

}

É If bound is computed, both checks essentialÉ Code reviews, programmer reasoning are brittle

Page 37: Secure Programming Lecture 6: Memory Corruption IV ... · É a safe compiler to automatically generate checking code that checks bounds or types dynamically, during execution. É

Safety from programming languages

Programming languages may provide memory safetyand type safety, automatically for all programs:

Memory safety disallow reading/writing with arbitrarymemory addressing.Prevents overflow attacks from corruptingmemory.

Type safety prevent storing arbitrary data into datavalues.Makes it harder for attacker to inject data thatwill be executed as binary code.

Page 38: Secure Programming Lecture 6: Memory Corruption IV ... · É a safe compiler to automatically generate checking code that checks bounds or types dynamically, during execution. É

Safety from compilers and tools

To try to ensure safety with an unsafe language, wemay use:

É a safe compiler to automatically generatechecking code that checks bounds or typesdynamically, during execution.

É a verifying compiler that checks statically atcompile time that the code it produces is safe.

É security testing tools that generate inputs toprograms to try to find security bugs.

É program analysis tools that ensure that inputsource code is free from certain vulnerabilities.

We’ll look at these technologies in more detail later inthe course.

Page 39: Secure Programming Lecture 6: Memory Corruption IV ... · É a safe compiler to automatically generate checking code that checks bounds or types dynamically, during execution. É

Safety from OS, libraries

É See lists of unsafe functions and explanations:É Microsoft’s recommendationsÉ CERT Secure C Coding

É Use a code security scanning toolÉ Have lists of dangerous API calls built inÉ Simple to find these in code, need deeper analysis

to identify certain vulnerabilitiesÉ Examples: RATS, cppcheck, SPLint, Clang.

É Switch to using safe(r) library functionsÉ The Safe C Library introduced in VS 2005.É Bounds checking functions part of the latest C11

standard (appendix K, also ISO/IEC TR 24731-1)É But has been contentious, not clear how

widely/quickly will be adopted.

Page 40: Secure Programming Lecture 6: Memory Corruption IV ... · É a safe compiler to automatically generate checking code that checks bounds or types dynamically, during execution. É

Outline

Announcement

Recap

Containment and curtailment

Stack tamper detection

Memory mode protection

Diversification

Secure programming

Summary

Page 41: Secure Programming Lecture 6: Memory Corruption IV ... · É a safe compiler to automatically generate checking code that checks bounds or types dynamically, during execution. É

Review questionsOverflow protection mechanisms

É Describe how StackGuard’s “canaries” work to stopbuffer overflows. What kind of attacks are they noteffective against?

É Describe how hardware-assisted memoryprotection can prevent the worst kinds of overflowattacks. In what cases may it be difficult to use?

É Explain the strategy of program diversification andhow it is achieved in ASLR.

Avoiding overflow vulnerabilities

É Explain where bounds checking should beperformed, especially to ensure “defence-in-depth”.

É List some checks which a programmer or staticanalysis tool should do to prevent overflowvulnerabilities in released code.

Page 42: Secure Programming Lecture 6: Memory Corruption IV ... · É a safe compiler to automatically generate checking code that checks bounds or types dynamically, during execution. É

Coming next

Lab session tomorrow!

Next week: looking at injections.

Page 43: Secure Programming Lecture 6: Memory Corruption IV ... · É a safe compiler to automatically generate checking code that checks bounds or types dynamically, during execution. É

References and credits

TBD