Get a Pentest and security assessment of your IT network.

Cyber Security

Fix Buffer Overflow Vulnerabilities

TL;DR

Buffer overflows happen when a program tries to write more data into a memory area than it’s allowed, potentially crashing the program or letting attackers take control. This guide shows how to prevent them without relying on environment variables.

Understanding Buffer Overflows

A buffer overflow occurs when you attempt to store more data in a fixed-size block of memory (the ‘buffer’) than it can hold. This overwrites adjacent memory, leading to unpredictable behaviour. Common causes include unchecked input and string manipulation.

Preventing Buffer Overflows

  1. Use Safe Functions: Avoid functions like strcpy, strcat, and sprintf which don’t perform bounds checking. Instead, use their safer counterparts:
    • strncpy: Copies a specified number of characters.
      char dest[10];
      strncpy(dest, source, sizeof(dest) - 1);
      dest[sizeof(dest) - 1] = ''; // Always null-terminate!
    • strncat: Appends a specified number of characters.
      char dest[20];
      strncat(dest, source, sizeof(dest) - strlen(dest) - 1);
      dest[sizeof(dest) - 1] = ''; // Always null-terminate!
    • snprintf: Formats a string with a maximum length.
      char dest[30];
      snprintf(dest, sizeof(dest), "Formatted string: %s", source);
      dest[sizeof(dest) - 1] = ''; // Always null-terminate!
  2. Input Validation: Check the length of user input before copying it into a buffer. Ensure it doesn’t exceed the buffer’s capacity.
    int input_length = strlen(user_input);
    if (input_length >= BUFFER_SIZE) {
      // Handle error - input too long
    } else {
      strcpy(buffer, user_input); // Now safe because of length check
    }
  3. Bounds Checking: Explicitly verify that you’re not writing beyond the buffer boundaries.
    for (int i = 0; i < input_length && i < BUFFER_SIZE - 1; ++i) {
      buffer[i] = user_input[i];
    }
    buffer[BUFFER_SIZE - 1] = ''; // Null-terminate
  4. Stack Canaries: Compilers can insert 'canary' values onto the stack before function return addresses. If a buffer overflow overwrites the canary, it indicates an attack and terminates the program.
    • Enable this feature in your compiler (e.g., -fstack-protector with GCC).
  5. Address Space Layout Randomization (ASLR): ASLR randomizes the memory addresses of key program components, making it harder for attackers to predict where to inject malicious code.
    • Enable this feature in your operating system. Most modern OSes have this enabled by default.
  6. Data Execution Prevention (DEP): DEP marks certain memory regions as non-executable, preventing attackers from executing injected code.
    • Enable this feature in your operating system.

Example Scenario & Fix

Let's say you have the following vulnerable code:

void copy_input(char *user_input) {
 char buffer[16];
 strcpy(buffer, user_input); // Vulnerable! No bounds checking.
 printf("Copied input: %sn", buffer);
}

To fix this:

void copy_input(char *user_input) {
 char buffer[16];
 strncpy(buffer, user_input, sizeof(buffer) - 1);
buffer[sizeof(buffer) - 1] = ''; // Ensure null termination.
 printf("Copied input: %sn", buffer);
}

Testing for Buffer Overflows

Use tools like:

  • Valgrind: A memory debugging tool that can detect buffer overflows and other memory errors.
  • AddressSanitizer (ASan): Another powerful memory error detector, often faster than Valgrind.
Related posts
Cyber Security

Zip Codes & PII: Are They Personal Data?

Cyber Security

Zero-Day Vulnerabilities: User Defence Guide

Cyber Security

Zero Knowledge Voting with Trusted Server

Cyber Security

ZeroNet: 51% Attack Risks & Mitigation