Lab 1: Buffer Overflow Exploits

🎯 Objective

In this lab, you'll explore classic stack-based buffer overflow vulnerabilities and learn how to craft exploits by directly manipulating binary input. The goal is not just to understand how overflows work, but to gain hands-on experience reading assembly, analyzing binaries, and reasoning about control flow at a low level.

This lab focuses on: - Understanding stack layout and calling conventions - Analyzing vulnerable binaries - Crafting exploit payloads - Techniques like code injection and return-to-libc


🗃️ Setup

Target Platform

  • OS: Linux (Ubuntu recommended)
  • Architecture: 32-bit x86 (even if your host system is 64-bit)
  • Tools:
    • gcc with -m32 option
    • gdb (GNU Debugger)
    • Ghidra (for decompilation and disassembly)
    • Optional: hexedit or a hex editor of your choice

Compilation Flags

To make the attack possible, disable certain security features:

gcc -m32 -fno-stack-protector -z execstack -no-pie -o example example.c

Disable ASLR

ASLR (Address Space Layout Randomization) must be disabled:

# Temporarily disable (requires sudo)
echo 0 | sudo tee /proc/sys/kernel/randomize_va_space

# Or: Launch a shell with ASLR disabled
setarch `uname -m` -R /bin/bash

🧵 Vulnerable Code Walkthrough

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

int IsPasswordOkay(void)
{
  char Password[12];
  gets(Password);

  if (!strcmp(Password, "goodpass"))
    return 1;

  return 0;
}

int main(void)
{
  int PwStatus;

  puts("Enter password:");
  PwStatus = IsPasswordOkay();
  if (PwStatus == 0) {
    puts("Access denied");
    return -1;
  }
  puts("Access granted");
  return 0;
}

The vulnerability lies in the use of gets(), which does no bounds checking. Input longer than 12 bytes overwrites adjacent memory.


🧠 How Stack-Based Buffer Overflows Work

[ Higher Address ]
+-----------------+
| Return Address  | <- what we want to overwrite
+-----------------+
| Saved %ebp      |
+-----------------+
| Buffer (??B)    | <- Need to determine the actual size of the buffer
+-----------------+
[ Lower Address ]

🧪 Attack 1: Authentication Bypass

Goal: Trick the program into printing “Access granted” without knowing the correct password.

  1. Analyze the binary in Ghidra
  2. Find offset to return address
  3. Identify the address of the instruction that prints “Access granted”
  4. Construct payload: [12 or more bytes junk][4 bytes junk][4 bytes of desired address]

🧪 Attack 2: Shellcode Injection (Code Injection)

Goal: Inject shellcode into the program and redirect control flow to it.

  1. Create an input:
  2. NOP sled (0x90)
  3. Shellcode
  4. Padding
  5. Overwrite return address with address into sled
  6. Use GDB to find stack address
  7. Handle small stack shifts using NOP sled

🧪 Attack 3: Return-to-libc

Goal: Hijack control flow to system("ps") without injecting code.

  1. Find system() address using GDB
  2. Place "ps" or "/bin/sh" string in memory
  3. Stack layout:
[ system() address ]
[ return address (dummy) ]
[ pointer to string ]

Note: This only works cleanly on 32-bit. On 64-bit, arguments go in registers.


⚠️ Tips

  • Intel is little-endian: 0xdeadbeef\xef\xbe\xad\xde
  • Use gdb and x/24x $esp to examine stack
  • Disable ASLR every time
  • Use hexedit to inspect and edit your attack inputs

📄 Submission Instructions

Submit a report (no code needed) including: - Explanation of each attack - Your payloads - GDB screenshots or output - Observations and challenges


💬 Final Thoughts

This lab is about developing intuition and hands-on skill with binary exploits. Reach out on Slack or in office hours for help.