Blog | G5 Cyber Security

Buffer Overflow: Canary Protection

TL;DR

Terminator canaries (stack canaries) are a security measure to detect buffer overflows on the stack. They work by placing a known value (the canary) just before the return address on the stack. If a buffer overflow overwrites the canary, it indicates a potential attack. When the function returns, the program checks if the canary has been modified. If it has, the program terminates to prevent malicious code execution.

How Buffer Overflow with Canaries Works

Stack canaries don’t prevent buffer overflows; they detect them. Here’s how:

  1. Canary Placement: When a function is called, the compiler inserts a random value (the canary) onto the stack immediately before the saved return address.
  2. Overflow Attempt: If a buffer overflow occurs within that function, it may overwrite the canary value.
  3. Return Check: Before returning from the function, the program checks if the canary value has changed.
  4. Detection & Termination: If the canary is different from its original value, the program knows a buffer overflow likely happened and terminates (often with an error message like ‘Stack smashing detected’).

Steps to Understand and Test Canary Protection

  1. Compilation with Canaries: Most compilers enable stack canaries by default. However, you might need to explicitly enable them using compiler flags. For GCC, use the -fstack-protector flag.
    gcc -fstack-protector vulnerable_program.c -o vulnerable_program
  2. Vulnerable Code Example: Consider this simple C code:
    #include <stdio.h>
    #include <string.h>
    
    int main() {
      char buffer[64];
      printf("Enter input: ");
      gets(buffer); // Vulnerable function!
      printf("You entered: %sn", buffer);
      return 0;
    }
    

    This code uses gets(), which doesn’t perform bounds checking.

  3. Attempting an Overflow (Without Canaries): If you compile this without canaries and provide input larger than 64 bytes, you can overwrite the return address and potentially hijack execution.
  4. Attempting an Overflow (With Canaries): When compiled with -fstack-protector, attempting the same overflow will likely result in a ‘Stack smashing detected’ error before your malicious code runs. The program terminates because the canary was overwritten.
  5. Disabling Canaries (For Testing – Use Caution!): You can disable stack canaries for testing purposes using the -fno-stack-protector flag. However, this makes your program vulnerable and should only be done in a controlled environment.
    gcc -fno-stack-protector vulnerable_program.c -o vulnerable_program
  6. Examining the Stack (GDB): Use GDB to examine the stack layout and see how the canary is placed.
    • Start GDB: gdb ./vulnerable_program
    • Set a breakpoint before the return: break main
    • Run the program: run
    • Examine the stack: x/20wx $rsp (This shows 20 words starting from the stack pointer)

    You should see a random value (the canary) just before the return address.

Bypassing Canaries

Canary protection isn’t foolproof. Attackers can sometimes bypass it using techniques like:

Mitigation Strategies

Exit mobile version