Memory Flashcards
Endian-ness
x86 family is a little-endian architecture: multi-byte values are stored least-significant byte first
0x11223344 –> \0x44\0x33\0x22\0x11
Memory Layout
[ HIGH ]
Kernel Space
Stack (grows down): procedure-local data and control
Memory Mapping (grows down): shared libraries, mapped files
Heap (grows up): dynamic data, limit controlled by brk/sbrk
BSS: uninitialized static vars, filled with zero
Data: initialized static vars
Text: program code
[ LOW 0x0 ]
Stack Frames
- collection of all data corresponding to one subroutine call
- local variables, passed arguments, saved return address, saved registers
Calling Conventions
- standards for defining subroutine call setup, needed so that tool chains can operate together (where are args passed? responsibilities of caller/ee? how to return? etc…)
- caller: code that invokes a subroutine
- callee: invoked subroutine
Stack Frame Layout
% ebp + 12 | Argument 2
% ebp + 8 | Argument 1
Return Address
% ebp –> Saved %ebp
Local Data
% esp –> Stack top
Key stack-based buffer overflow vulnerability
Overwriting the return address!
- fxn returns using a corrupted stack frame
- attacker controls the return address
- code jumps to a location of the attacker’s choosing
Low vs high-level languages
- low-level languages are not memory safe
- high level languages (like Java or Python) are not vulnerable to memory corruption attacks b/c memory management is not left to the programmer
Shellcode
- idea: inject a malicious payload somewhere in memory and jump to it
- inject shellcode into the overflown buffer or in an environment variable
NOP Sled
- special “landing area” in front of the shellcode
- instead of needing to jump to the exact start of your shellcode, you can use a nop sled to make a bigger domain of “correct” addresses you can jump to
- should not effect the execution (program logic or state)
Stack Overflow Defenses
- write better code: proper bounds checking, use memory-safe prog langs, use safer functions (strcpy –> strncpy)
- stack canaries: if the canary value on the stack is dead (messed up), then bail out of the program
- non-executable stack: OS-level protection, stack memory marked as non-executable
PLT & GOT
- dynamically linked executables reference external fxns (location not known at link time)
- Procedure Linkage Table & Global Offset Table together implement runtime function resolution
Return-oriented programming
- borrow small code chunks, called gadgets
- chain them together to create your malicious process
- can be Turing complete
- useful to bypass many modern memory defenses
- defenses: check for abnormal ret execution frequency, remove gadgets from binary when compiling, control-flow integrity (enforce good jump source and targets), ASLR
call & ret
- call foo: push the return address on stack, jump to foo
- ret: pop the saved return address, jump to it
- gadgets (reusable code chunks) end with ret
ASLR
Address space layout randomization
- traditional attacks require attackers to know/guess certain addresses
- idea: randomize code & data addresses –> difficult to guess
- OS level defense (no recompilation needed)
printf
- printf family of fxns format string data
- format string can contain static data and variable placeholders
- if attacker can control format string, can overwrite any location in memory using %n directive
- %n reads an address from the stack, and then writes the number of bytes printed so far to that address
- classic attack: put the target address in the format string itself, then walk back on the stack to find it (ex: AAA %x %x %x –> AAA d 0 blahblah blahblah 0 414141)