Get a Pentest and security assessment of your IT network.

Cyber Security

Buffer Overflow: Executing Hidden Code

TL;DR

A buffer overflow attack lets you overwrite parts of a program’s memory to change how it works. This guide shows how an attacker can use this to make the program run code that wasn’t meant to be executed, specifically an uncalled function within the program itself.

Understanding the Attack

Buffer overflows happen when a program writes data beyond the allocated space for a buffer. This overwrites adjacent memory locations, potentially changing important values like return addresses or function pointers. In this scenario, we’ll focus on overwriting the return address to point to an uncalled function within the same executable.

Prerequisites

  • A vulnerable program (compiled C code example provided below).
  • Basic understanding of assembly language and stack frames.
  • Debugging tools like GDB or a similar debugger.

Vulnerable Program Example (C)

#include <stdio.h>
#include <string.h>

void secret_function() {
    printf("Secret function executed!n");
}

int main(int argc, char *argv[]) {
    char buffer[64];
    if (argc > 1) {
        strcpy(buffer, argv[1]);
    }
    printf("Buffer contents: %sn", buffer);
    return 0;
}

This program has a classic buffer overflow vulnerability in the strcpy function. It copies user input into a fixed-size buffer without checking its length.

Steps to Exploit

  1. Identify the Offset: Determine how many bytes you need to write before overwriting the return address on the stack.
    • Run the program in a debugger (e.g., GDB).
    • Set a breakpoint after the strcpy call.
    • Examine the stack using commands like info frame or x/20xw $rsp to find the return address.
    • Calculate the distance between the beginning of the buffer and the return address. This is your offset. In this example, it will likely be around 72 bytes (64 for the buffer + some padding).
  2. Find the Address of the Uncalled Function: Locate the memory address of the function you want to execute.
    • Use a debugger or disassembler (e.g., objdump -d executable_name) to find the starting address of secret_function().
    • Note this address; it will be needed in the next step.
  3. Craft the Payload: Create a string that overwrites the return address with the address of the uncalled function.
    • The payload will consist of:
      • Padding to fill the buffer up to the return address. This is usually ‘A’ characters.
      • The address of secret_function(), in little-endian format (because most systems are little-endian).
    • Example payload (assuming offset is 72 and function address is 0x401166):
      "A" * 72 + "x66x11x40x00"
  4. Execute the Attack: Run the program with the crafted payload as input.
    • In this example:
      ./vulnerable_program $(python3 -c 'print("A" * 72 + "x66x11x40x00")')
    • The program should now execute the secret_function().

Important Considerations

  • Address Space Layout Randomization (ASLR): ASLR randomizes memory addresses, making it harder to predict the address of functions. Bypassing ASLR often requires information leaks or other techniques.
  • Stack Canaries: Stack canaries are values placed on the stack to detect buffer overflows. Overwriting a canary will cause the program to terminate.
  • Non-Executable Stack (NX bit): The NX bit prevents code execution from the stack, making it harder to inject and run shellcode directly.
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