- last time: - framing control versus clickjacking - MIME type inference dangers - same-origin policy - cross-origin resource sharing + historical places it is not used - implication for information leaks - exam format - most similar to S2017 final - probably relatively few open-ended questoins (just b/c of grading time) - Rust on the exam - we expect you to know about the "ownership" and "borrowing" ideas - we don't care about syntax - we expect you to unerstand the idea of refcounting - relocation tables - setup: some file with misisng references to other file - example: executable with references to a library it loads - example: object file with references to other object files - linker needs to fill in these references (when the program is loaded for dynamic linking when the program is created otherwise) - relocatoin table lists what the linker needs to fill in: each entry contains - where is the "hole" to fill in - what format does that hole have example: is it a global offset table entry which needs to a pointer? example: is it the offset in a jmp instruction which needs to be a number of bytes between this jump and the place to jump to? - what "symbol" the hole should refer to example: `foo` for the function `foo` - the linker will match the relocatoin table with a symbol table to figure out how to fill in the holes - symbol table entries have: - symbol name - locatoin in some file - Q10 S2017 virus code insertion suppose a virus searched for the machine code for ret nopl (%eax,%eax,1) <-- 8-byte no-op instruction and it replaces this machine code with a jump to virus code jump is composed of [opcode for JMP] + (offset of virus code - offset of this code) what could go wrong here? ? could fail a stack canary check? NO --- b/c the stack canary check must have been before the RET in the original code, and we must have popped the stack canary off the stack for the RET to work ? these bytes could have been in another instruction YES -- mov $0x...C3, ... ^^--- looks like a ret -- string constant in program ? inserted jump in non-executable region This could happen, but would only cause a crash if the non-executable region was data or similar that needed be correct Would have to be anothr example of confusing these bytes with something else ? wrong offset which jmp in different segments This could happen if we have normal segment: LOAD off 0x1000 vaddr 0x400000 ... LOAD off 0x9000 vaddr 0x500000 then code at offset 0x9100 in the file won't be 0x8000 bytes away from 0x1100 when the program runs, and this would make the jump no twork - polymorphic malware two strategies malware used to have different machine code each time typical polymorphic strategy was to have a "decrypter" generator template that had several versions and "randomly" encrypted part typical "metamoprhic" strategy which had a machine code-to-machine code translator, which would have some table of how to change instructions and would be applied to itself for detectoin: - polymorphic strategy -- simplest idea is to write a pattern to match all possible decrypters - metamorphic strategy -- can still write a detector, but mihgt need something more hand-spun than just a regex OR: - behavior-based detectoin - heuristically look for "encrypted" data with entropy analysis - pointer subterfuge - some way of changing a pointer's value, then having the program use the pointer example: char buffer[128]; char *ptr; if we overflow buffer, then we change where ptr pointers, then if the program does something like strcpy(ptr, input) we can write to whereever we want in mmeory - challenge: not immediately obvious how to turn this into code execution (b/c we don't use 'ptr' to execute anything) - solution: we look for something writeable that is used to execute code - if we could overwrite a normal function, tha twould work, but typically that would just segfault b/c that memory is read-only - if we know where a return address that will be used is, we can make it point somewhere else [to our code to run] * runs our code when that function call returns - if we know where a VTable pointer is (or wreitable VTable entry is), we can make it point somewhere else [to a "fake VTable" pointing to our code ot run] * runs our code when we make a (polymorphic) method cal on that object BEFORE OVERWRITING Rectangle: [VTbl pointer]------>[area()]------>"normal Rectangle area()" [width] [print()]----->"normal Rectangle print()" [height] [...] AFTER OVERWRITING VTABLE POINTER: Rectangle: /---------------------->["our area()"]-------->"our code" [VTbl pointer]-/ [area()] ["our print()"]------->"our code" [width] [print()] [...] [height] [...] - if we know where a writeable GOT is (writeable = no relocatoin read-only in use) we can make it point somewhere else * runs our code when we call the library function whose "stub" uses that GOT entry to find where the library is loaded this time in memory - alternately: - we could just mess up the program's data - set the "grade" variable to 'A'. - fat pointers / baggy bounds / ASan comparison - all ways of adding bounds-checking - design goals, two ideas: - preventing security flaws - baggy bounds [in between: - fat pointers] - finding memory bugs - AddressSanitizer - strategy used: - track where objects are and figure out when we go out of bounds of them [fat pointers, baggy bounds] - track what memory is valid and figure out when invalid memory is accessed, and add "empty spaces" to make out-of-bounds usually hit invalid memory [AddressSanitizer] - implementatoin idea: - fat pointers for every pointer track that object it points to "object it points" -- &foo.bar[4] -- original object is foo.bar &foo.bar[4].x --- originaly object is foo.bar[4].x after pointe arithmetic and before dereferencing make sure the pointer still points to the same object means: can access other things in an array using indein/pointer arithmetic can't skip from one object in the array to anothre - baggy bounds don't track any extra information with pointers but have a way to lookup what object a pointer points to - means that &foo, &foo.bar[4], &foo.bar[4].x --- we'll know it points to 'foo', but can't be more specific whenever we do pointer arithmetic, make sure we don't jump from one (top-level) object to another to make this lookup fast: round object sizes to a power of two, so our lookup table can be relatively compact means: can skip from one object in an array to another but can't skip between top-level objects won't reliably detect off-by-one issues (b/c they may be in "rounded" object size) - AddressSaniztier don't track any extra information iwth pointers but have a way to lookup whether a byte of memory is valid insret invalid bytes between (top-level) objects in heap/stack - not in the middle of objects b/c this would non-AddressSanitizer code that expects those objects not have gaps wheneve we dereference a pointer, make sure it's only using valid bytes of memory means: can skip between objects as long sa we don't "land" in between will reliably detect off-by-one issues - smart pointer types in Rust - "normal" references enforce: compile-determined single modifier OR multiple readers freeing an object requires "modifier" access - can only stay valid as long as: * borrowed from somewhere that keeps the memory valid (if reference) * is the "main" copy (not a reference) - Cells treated like read-only but allows modifications by reacpling the value all at once - can modify while other readers, readers will see old value or new value - can't take references to "inside" - "smart pointer" --- runtime tracking to ensure safety - Rc --- reference counting - allow multiple readers - keep object alive until there are no readers - does this by counting # of readers - does not allow writers - RefCell --- dynamic "interior mutablity" - allows modifiers and readers - makes sure that if there's a modifier, there are no readers - does this by counting # of readers + modifiers - appears as read-only thing, so you can put it in an Rc - other most notable ones: threading - quiz week15 - Q4C has wrong key - Q1B: library function system() runs it sargument as a shell command - seems like a good candidate that will have an ENDBR64 in it already - Q2B: clang has a bitmask of allowed functions determined by seeing what could've been assigned to the function pointer by any code it saw