HOW TO PREVENT BUFFER OVERFLOW ATTACKS? STACK CANARIES Goal: catch overwrite before |------------------| | strarg | |------------------| | return address | |------------------| | old esp | |------------------| | canary value | |------------------| | buf[99] | | | | ... buf ... | | | | buf[1] | | buf[0] | |vvvvvvvvvvvvvvvvvv| <- %esp WHEN DO STACK CANARIES FAIL? When attacker: ELECTRIC FENCES Every heap allocation between pages [ Guard Page ] [ Heap Alloc.] [ Guard Page ] Guard pages are protected by hardware Write (or read) from guard pages causes an OS trap BOUNDS CHECKING Goal: What does it mean in C? WHAT HAS TO BE DONE Interject code whenever program does: - pointer arithmetic p + 1 - pointer dereference PRACTICAL CONSIDERATIONS How expensive are defenses? Would people pay for an OS that is: FAT POINTERS Instead of just an address, each pointer stores: BOUNDS CHECKING TECHNIQUES Splay trees: - record sizes for each object - grow larger as objects allocated Shadow table: - memory divided into constant-sized slots - pointers converted to indexes into shadow table - can locate metadata in BAGGY BOUNDS CHECKING Goals: - detect and stop out of bounds accesses - ensure derived pointers point to same object - don't allow reading/writing other allocations Constraints - use same size pointers - permit pointers one past either end Ideas: - round up each allocation to nearest power of 2 (bytes, say) e.g., 9 -> 16, 28 -> 32, ... - enforce bounds of the allocation - store binary log of allocation in bounds table, bt - allocate memory with granularity of a slot (fixed size, say 16 bytes) Let size be the allocation size (in bytes) e = log_2(size) so 1 << e = 2^e = size So, in bounds table, bt, store e value recover the size by look up in bt RECOVERING LENGTH AND BASE FROM POINTER Find the allocated size from pointer p: len(p) = 1 << bt[p >> log_2(slot_size)] Example: allocate 32 bytes char *p = malloc(32); for slot_size = 16 log_2(slot_size) = 4 len(p) = 1 << bt[p>>4] would put 5 (i.e., log_2(32)) in bt entries for 16 byte slots: bt[p>>4] = 5 bt[(p>>4)+1] = 5 Find starting address from pointer p: base(p) = p & ~(len(p)-1) Example: int a[100]; int *pa = &a[0]; allocate sizeof(int)*100 rounded up to power of 2 bytes = 512 bytes so need 512/16 == 32 slots each bt entry stores log_2(512) = 9 suppose address of pa == 0x400 so use 32 bt entries: pa >> 4 = 0x40 (== 64) bt[pa>>4] = 9 bt[(pa>>4)+1] = 9 ... bt[(pa>>4)+31] = 9 suppose: int *pb = &a[75]; == 0x400 + 4*0x4B == 0x400 + 0x12C == 0x52C (== 1324) len(pb) = 1 << bt[pb>>4] = 1 << bt[0x52C>>4] = 1 << bt[0x52] = 1 << 9 = 0x200 (== 512) base(pb) = pb & ~(len(pb)-1) = 0x52C & ~(1FF) = 0x400 BAGGY BOUNDS CHECKING (32 bit Arch.) inBounds(p) = base(p) <= p and p < base(p)+len(p) Result of pointer arithmetic: for computation of p2 = p + n; add the code: p2 = result(p2); where result(p2) = if inBounds(p2) then p2 else if base(p2)-7 <= p2 and p2 < base(p2)+len(p2)+8 then (1 << 31) | p2 else error("illegal pointer") WORKING WITH UNINSTRUMENTED CODE Code in libraries that was not compiled with baggy bounds checks bt entries set to maximum possible (31) BAGGY BOUNDS WITH 64 BIT POINTERS Idea: Store more information in the pointers Valid pointer: [ zeros | log2(size) | address ] 21 bits 5 bits 38 bits Invalid pointer: [ offset | log2(size) | zeros | address ] 13 bits 5 bits 8 bits 38 bits EVALUATING BAGGY BOUNDS SYSTEM Disadvantages: Advantages: NON-EXECUTABLE MEMORY 3 bits for permission on a page: read (R), write (W), execute (X) Execute means that Policy: W xor X so can't both write and execute in a page RANDOMIZED ADDRESS SPACE Idea: - make it harder for attacker to Often called ASLR = Address Space Layout Randomization DEFEATING ASLR Approaches: - extract the randomness - heap attack: . spread shell code all over the heap . jump to a random address - nop slide . put lots of nops in heap . put shell code at end . jump to random address WHAT IS USED IN PRACTICE? Both gcc and Visual Studio: - use stack canaries by default Linux and Windows both have W xor X memory and ASLR WHAT IS NOT USED IN PRACTICE? Baggy bounds