Stack buffer overflow happens when data being written exceeds the boundaries of the buffer. An attacker can craft a payload to overwrite local variables or even redirect code execution by overwriting the saved return address on the stack.
To see how we can exploit it:
In the old days we can simply overwrite the saved instruction pointer with a known function address or write some shellcode on the stack and jump there via a jmp esp
gadget, but this wouldn’t work against modern binaries, which typically have mitigations enabled (e.g., ASLR, NX stack, stack canaries, RELRO). This doesn’t mean that we can’t exploit a buffer overflow when mitigations are turned on, as there are often ways around them:
- ROPEmporium x86_64 demonstrates how ROP is used to bypass a non-executable stack (NX for Linux, DEP for Windows). By abusing existing instructions in the program and jumping from places to places, we don’t have to write and execute anything on the stack.
- ASLR can typically be bypassed by looking for infoleaks, i.e., making the binary leak a function address. Since the offsets between functions are still the same in a PIE (i.e., ASLR-enabled) executable, we can easily calculated another function’s address through some simple calculation. how-to-bypass-aslr-on-linux-x86_64 also demonstrates how to bypass ASLR without infoleaks.
- I don’t have any notes on stack canary bypasses, but typically you either have to leak the stack somehow (e.g., format string exploit) or brute-force it via a crash oracle—when a server forks a process to handle our request, we can partially overwrite the canary to brute-force it one byte at a time; if the process didn’t crash then we got it right, and we can move on to the next byte.