fun(0) -> 3.14
fun(1) -> 3.14
fun(2) -> 3.1399998664856
fun(3) -> 2.00000061035156
fun(4) -> 3.14
fun(6) -> Segmentation fault
This kind of problem is generally called a “buffer overflow”. It happens when exceeding the memory size allocated for an array. it is the #1 technical cause of security vulnerabilities Most common form of the buffer overflows come from:
- Unchecked lengths on string inputs
- Particularly for bounded character arrays on the stack
There is no way to specify limit on number of characters to read. strcpy, strcat, scanf, fscanf, sscanf all have the same problem.
If you run the code above, you will likely get…
Overflowed buffer and corrupted return pointer.
Even if the buffer overflow did not make the program to stop, it can be a serious problem.
After the execution of the function, the %rsp “Returns” to unrelated code.
Lots of things can happen, without modifying critical state and the program will eventually execute
retq back to
- How does attackers take advantage of this bug?
- overwrite with a carefully chosen return address
- executes malicious code (injected by attacker or elsewhere in the running process)
- What can attackers do once they are executing code?
- To gain easier access, e.g. execute a shell
- Take advantage of the permissions granted to the hacked process
- if the process is running as “root”….
- read user database, send spam etc.
Input string contains byte representation of executable code.
Overwrite return address A with address of buffer B.
When Q executes ret, will jump to exploit code.
Buffer overflow bugs can allow remote machines to execute arbitrary code on victim machines.
Common in real progams
Examples across the decades
- “Internet worm” (1988)
- Attacks on Xbox
- Jaibreaks on iPhone
Recent measures make these attacks much more difficult
- Better coding practices
- e.g. use library routines that limit string lengths, fgets instead of gets, strncpy instead of strcpy
- Use a memory-safe language instead of C
- bug finding tools?
A buffer overflow attack typically needs two components:
- Control-flow hijacking
- overwrite a code pointer (e.g. return address) that’s later invoked
- Need some interesting code in the process’ memory
- e.g. put code in the buffer
- Process already contains a lot of code in predictable location
How to mitigate attacks? make #1 or #2 hard
Idea: Catch over-written return address before invocation!
Place special value (“canary”) on stack just beyond buffer
Check for corruption before exiting function
- Now the default
Overwrite a code pointer before canary
Overwrite a data pointer before canary
- NX: Non-executable code segments
- Traditional x86 has no “executable” permission bit, X86-64 added explicit “execute” permission
- Stack marked as non-executable
- Does not defend against:
- Modify return address to point to code in stdlib (which has functions to execute any programs e.g. shell)
- Insight: attacks often use hard-coded address make it difficult for attackers to figure out the address to use
- Address Space Layout Randomization
- Stack randomization
- Makes it difficult to determine where the return addresses are located
- Randomize the heap, location of dynamically loaded libraries etc.
- Stack randomization