Stack Canaries, Bounds Checking, NX, DEP, ROP, ASLR(week 3) Flashcards
canaries
help program to detect if it has been attacked before the attacker takes control
idea of canary
what if the compiler could add a piece of data between buffer and control data
that way if there is an overflow, the compiler will first check to make sure that the canary is not overwritten
what if an attacker knows the canary?
a few defenses:
- canary could be copy-unfriendly “terminator” characters
- -> “\0\CR\LF-1”
- -> strcpy will stop copying at \0 and won’t copy the rest of the canary - canary randomly generated on each run
- -> doesn’t work if adversary can read its value somehow (like format string vulnerabilities) - random canary XORed with control data
- -> store: “return address XOR saved ebp XOR random canary”
- -> a little harder for attacker but still bypassable
are attacks possible without harming the canary?
yes. we could just overwrite local variables and completely avoid the canary
Explain Option 1 for bounds checking: electric fences
- only useful for the heap
- allocate memory page
- then, allocate a memory page above it (at a higher address) that serves as the electric fence
- we call mprotect on this page and it makes the page has no access privileges
- if we try to access the electric fences then the program will crash
good performance: no cost, all done by hardware (unless BO)
downside: doesn’t work with the stack, only works at the granularity of pages, can’t do push and pop, when stack shrinks data isn’t deleted
INEFFICIENT IN TERMS OF SPACE, minimum page size is usually around 4 KB
they are found in a lot of debugging software like valgrind
describe option 2 for bounds checking: fat pointers
existing pointers: 32 bit address
fat pointer: [32 bit start address][32 bit end address][32 bit ptr address]
drawbacks:
• fat pointers are big. they make everything big.
• legacy code doesn’t understand fat pointers
• updates are non-atomic because fat pointers use 3 words
–>makes multithreaded code harder to write
what’s a low-fat pointer
use part of 64 bit address to encode something about the length of the pointer (invented at penn)
explain non-executable bit (NX)
make the stack non-executable
memory pages have 3 permission bits
R: Read
W: Write
X: Execute
Idea: set the NX bit on the memory pages that make up the stack
make memory W XOR X
Either memory is writable (stack) or executable (like the code pages), but not both
who sets the NX bit?
• compiler annotates memory section in the ELP binary
- -ELF contains headers of section in memory
- -Can set section header flags (sh_flags) to:
- —SHF_WRITE: makes section’s memory writable
- —SHF_EXECINSTR: allows section’s memory to contain executable instr.
• loader reads these annotations and sets the NX bit (kernel)
–if a region of memory doesn’t have the SHF_EXECINSTR flag, the loader sets the NX bit on the memory pages
Who checks the NX bit?
the MMU!
lives in CPU. checks page permissions. the MMU takes memory address and figures out if the command is consistent with the permissions of the page.
drawbacks NX bit/DEP
- prevents benign code rewriting at runtime (useful for JTI compiling)
- there are ways to get around this
• attacker cannot inject code but can still overflow and change return address and point it to existing code (libraries and program’s own code)
Return Oriented Programming
helps attackers bypass data execution prevention
DEP prevents us from running injected code but we can use code that is already there
options for bypassing DEP
1: get lucky, see if exact sequences of opcodes exists in program’s code
- return to libc: we can use libc see if linked in application,
- find out their address
- setup the stack before returning to them
ROP:
- recycle existing instructions
- use opcodes from different functions (“gadgets”) and string them together to get the sequence we want
- ROP
how to spot gadgets for ROP?
- look for ret instruction and then work backwards (0xc3)
- useful gadget pop, push, or modify common registers
- we have automated tools that can do this now
Address Space Randomization Layout
attacks rely on attacker knowing the exact layout of memory address of injected shellcode, libraries, or gadgets
- randomizes the start address of the stack, heap, program code, libs, and data on each run of program
- if program crashes and restarts, it should have different address space
- it attacker has a copy of binary, address space on their machine is different than address space on target’s machine