Blog | G5 Cyber Security

Fixing Buffer Overflows & Checking Registers

TL;DR

Buffer overflows happen when a program tries to write more data into a memory area than it’s allowed. This can crash the program or, worse, let attackers take control. We’ll cover how to prevent them and how to check register contents for debugging.

Understanding Buffer Overflows

Imagine you have a box that can hold 10 apples. A buffer overflow is like trying to stuff 15 apples into that box – some will spill out (overflow) and potentially mess things up. In programming, these ‘boxes’ are memory buffers.

Preventing Buffer Overflows

  1. Use Safe Functions: Avoid functions like strcpy, gets, and sprintf which don’t check buffer sizes. Use their safer alternatives:
    • Instead of strcpy(dest, src) use strncpy(dest, src, sizeof(dest)-1); dest[sizeof(dest)-1] = ' ';
    • Instead of gets(buffer) use fgets(buffer, sizeof(buffer), stdin).
    • Instead of sprintf(buffer, "format string", value) use snprintf(buffer, sizeof(buffer), "format string", value).
  2. Check Input Length: Always validate the length of user input before copying it into a buffer.
    if (strlen(input) >= buffer_size) {
      // Handle error - input too long!
    }
  3. Bounds Checking: Ensure you’re not writing beyond the allocated memory space. This is often done automatically by safer functions, but manual checks are sometimes necessary.
  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 the program can terminate.
    • Most compilers (like GCC) have options to enable stack canaries (e.g., -fstack-protector).
  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.
    • Enabled by default on most modern operating systems.

Checking Register Contents (Debugging)

Registers hold important data during program execution. Checking their values can help you understand what’s happening, especially when debugging buffer overflows.

Using GDB (GNU Debugger)

  1. Start GDB: Launch the debugger with your executable.
    gdb ./your_program
  2. Set a Breakpoint: Stop execution at a specific point in your code.
    break main
  3. Run the Program: Start the program.
    run
  4. Inspect Registers: Use the info registers command to view all register values.
    info registers
  5. Inspect Specific Registers: View individual register values (e.g., $rsp for stack pointer, $rip for instruction pointer).
    print $rsp
    print $rip
  6. Examine the Stack: Use x/20wx $rsp to examine 20 words (4 bytes each) starting from the stack pointer.
    x/20wx $rsp

Example Scenario

If you suspect a buffer overflow is corrupting the return address on the stack, check $rip after the vulnerable function call. If it’s changed unexpectedly, that’s a strong indicator of an overflow.

Exit mobile version