Lecture 4: Mitigating Memory Safety Vulnerabilities
- Slides
- Optional slides
- Playlist (length: 45:36)
Ensuring Memory Safety
Optional: Reasoning About Memory Safety
One way to ensure memory safety is to carefully reason about memory accesses in your code, by defining pre-conditions and post-conditions for every function you write and using invariants to prove that these conditions are satisfied. Although it is a good skill to have, this process is rarely used in practice, so it is out of scope for the summer.
If you are interested, the Spring 2020 video is linked below. It will not be tested on any exams or projects.
(End of optional content. Everything below this is in scope.)
Use a Memory-Safe Language
True or false: Using a memory-safe language prevents 100% of buffer overflow attacks.
Defending Non-Memory-Safe Code
Stack Canaries
An attacker runs a vulnerable program with some input that leaks the stack canary, and writes down the value of the leaked stack canary. Then the attacker runs the program again, using the leaked canary value to overwrite the stack canary. True or false: this strategy defeats the stack canary defense.
Guessing the Canary
How many bits of entropy would a canary on a 64-bit system have if one of the bytes is always 0x00?
Pointer Authentication
Non-Executable Pages
True or false: An attacker cannot do anything malicious if non-executable pages are enabled. (Hint: Think about the analogy from the last lecture.)
Return Into libc
Return-Oriented Programming
Why does enabling non-executable pages not prevent return-oriented programming?
Address Space Layout Randomization (ASLR)
True or false: If ASLR is enabled but DEP is not enabled, an attacker can write malicious code to the stack and overwrite the return address to execute that code.
Defenses in Practice
Fuzz Testing
Memory Safety Conclusion
After finishing this lecture, you should have everything you need to start Project 1. Debugging this project can be time-consuming, so please start early!