diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 0000000..e83f0ef --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,23 @@ +name: Build + +on: [push, pull_request] + +jobs: + compile: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Install GCC + run: | + sudo apt-get update + sudo apt-get install -y gcc + + - name: Compile all lab programs + run: | + gcc -Wall -Wextra -Werror src/vuln_buffer_overflow.c -o vuln_buffer_overflow + gcc -Wall -Wextra -Werror src/safe_input_demo.c -o safe_input_demo + gcc -Wall -Wextra -Werror src/stack_layout_demo.c -o stack_layout_demo + gcc -Wall -Wextra -Werror src/overflow_behavior_demo.c -o overflow_behavior_demo + gcc -Wall -Wextra -Werror src/control_flow_simulation.c -o control_flow_simulation diff --git a/.gitignore b/.gitignore index e8e8365..cbbf398 100644 --- a/.gitignore +++ b/.gitignore @@ -2,4 +2,17 @@ vuln_lab vuln_lab.exe vuln_lab_test vuln_lab_test.exe +stack_behavior_demo +stack_behavior_demo.exe +vuln_buffer_overflow +vuln_buffer_overflow.exe +safe_input_demo +safe_input_demo.exe +stack_layout_demo +stack_layout_demo.exe +overflow_behavior_demo +overflow_behavior_demo.exe +control_flow_simulation +control_flow_simulation.exe +*.exe *.o diff --git a/Makefile b/Makefile index ed28068..87fb4dd 100644 --- a/Makefile +++ b/Makefile @@ -1,17 +1,20 @@ CC = gcc CFLAGS = -Wall -Wextra -g -O0 -TARGET = vuln_lab -SRC = src/main.c +VERIFY_CFLAGS = -Wall -Wextra -Werror +SRC_DIR = src +PROGRAMS = vuln_buffer_overflow safe_input_demo stack_layout_demo overflow_behavior_demo control_flow_simulation -.PHONY: all run clean +.PHONY: all verify clean -all: $(TARGET) +all: $(PROGRAMS) -$(TARGET): $(SRC) - $(CC) $(CFLAGS) -o $(TARGET) $(SRC) +$(PROGRAMS): %: $(SRC_DIR)/%.c + $(CC) $(CFLAGS) -o $@ $< -run: $(TARGET) - ./$(TARGET) +verify: $(addprefix verify-,$(PROGRAMS)) + +verify-%: $(SRC_DIR)/%.c + $(CC) $(VERIFY_CFLAGS) -o $* $< clean: - -$(RM) $(TARGET) $(TARGET).exe + -$(RM) $(PROGRAMS) $(addsuffix .exe,$(PROGRAMS)) diff --git a/README.md b/README.md index c222e15..45f70b2 100644 --- a/README.md +++ b/README.md @@ -1,236 +1,171 @@ -# Exploit Lab (C/C++) - Memory Vulnerability Learning Lab +# Exploit Lab (C/C++) - Safe Memory Vulnerability Learning Lab -This project demonstrates how memory vulnerabilities can appear in C programs and how they affect behavior at the stack level. +> A structured, multi-phase lab for understanding memory vulnerabilities from first principles using safe, controlled demonstrations. -It is a hands-on educational lab focused on understanding and observing memory behavior, not exploitation. +A modular, beginner-friendly lab for understanding memory vulnerability concepts in C through conceptual demonstration and controlled simulation. -## Overview +This project is educational only. It does not include exploit payloads or exploitation instructions. -Memory vulnerabilities are common in low-level languages such as C and C++. -They often happen when a program writes outside intended memory boundaries or does not validate input size. +## What This Lab Covers -This lab helps you learn: -- How unsafe input handling can cause problems -- How stack memory is laid out for local variables -- How to inspect behavior with GDB -- How safer input handling reduces risk +- Unsafe vs safe input handling +- Stack memory layout observation +- Overflow behavior observation (controlled) +- Conceptual control-flow redirection using function pointers +- Practical debugging with GDB +- Runtime protection concepts (ASLR, NX, stack canaries) -## What Are Memory Vulnerabilities? +## Core Programs (5) -A memory vulnerability happens when code incorrectly reads or writes memory. - -Example of unsafe input: - -```c -char buffer[16]; -scanf("%s", buffer); /* No size limit */ -``` - -If the input is longer than the buffer, nearby memory can be overwritten. -Possible outcomes include: -- Unexpected variable value changes -- Program instability -- Crashes -- Undefined behavior - -## What This Program Demonstrates - -### 1. Safe vs Unsafe Input Handling -- `unsafe_input(...)` uses unbounded `%s` input to show risk -- `safe_input(...)` uses `fgets(...)` with buffer limits - -### 2. Memory Layout Observation - -The program prints addresses of: -- `buffer` -- local variable `x` -- function parameter (`demo_id`) - -This helps visualize how stack variables are typically stored close together. - -### 3. Stack Behavior - -You can observe: -- Relative ordering of local variables in stack memory -- Address changes across runs (commonly due to ASLR) -- Similar local layout patterns between runs - -### 4. Controlled Overflow Observation - -In unsafe mode, very long input may: -- Trigger warning messages -- Change nearby variable values unexpectedly -- Crash the program - -This is used to observe undefined behavior in a controlled, educational context. - -### 5. Debugging With GDB - -Use GDB to: -- Set breakpoints -- Step through execution -- Print local variables -- Inspect register state - -See [docs/gdb-guide.md](docs/gdb-guide.md) for the full walkthrough. +1. `vuln_buffer_overflow` - unsafe input pattern demonstration +2. `safe_input_demo` - bounded input with `fgets(...)` +3. `stack_layout_demo` - stack address observation +4. `overflow_behavior_demo` - controlled overflow behavior observation +5. `control_flow_simulation` - conceptual control-flow redirection ## Project Structure ```text exploit-lab-cpp/ |-- src/ -| `-- main.c +| |-- vuln_buffer_overflow.c +| |-- safe_input_demo.c +| |-- stack_layout_demo.c +| |-- overflow_behavior_demo.c +| `-- control_flow_simulation.c +|-- archive/ +| |-- main.c +| `-- stack_behavior_demo.c |-- docs/ | |-- gdb-guide.md -| `-- memory-layout.md +| |-- memory-layout.md +| |-- protections.md +| |-- advanced-concepts.md +| |-- lab-exercises.md +| |-- demo.md +| `-- images/ |-- Makefile `-- README.md ``` -## Requirements - -- GCC -- GDB (recommended for debugging) -- `make` (optional; you can compile directly with `gcc`) - -## Build and Run +## Build -### Build With Make +Compile all core programs: ```bash make ``` -### Build Manually (if `make` is not available) +## Manual Compilation (No Make) + +If `make` is not available, compile each program directly: ```bash -gcc -Wall -Wextra -g -O0 -o vuln_lab src/main.c +gcc src/vuln_buffer_overflow.c -o vuln_buffer_overflow +gcc src/safe_input_demo.c -o safe_input_demo +gcc src/stack_layout_demo.c -o stack_layout_demo +gcc src/overflow_behavior_demo.c -o overflow_behavior_demo +gcc src/control_flow_simulation.c -o control_flow_simulation ``` -### Run +## Verification (Quick Check) -Linux/macOS: +Run this to verify setup in seconds: ```bash -./vuln_lab +make +./vuln_buffer_overflow ``` Windows (MinGW): ```powershell -.\vuln_lab.exe +make +.\vuln_buffer_overflow.exe ``` -Choose a mode: -- `1` = Unsafe demo -- `2` = Safe demo - -## How to Test Safely +## Quick Sanity Check -Run in a local, controlled environment and use simple test inputs. +1. Safe demo: + - Run `./safe_input_demo` + - Expected: input works normally with no warnings. +2. Overflow demo: + - Run `./overflow_behavior_demo` with long input. + - Expected: warning appears and behavior may change. +3. Control flow demo: + - Run `./control_flow_simulation`. + - Expected: output changes before/after pointer reassignment. -### Normal input +## Run Commands -Example: +Linux/macOS: -```text -hello +```bash +./vuln_buffer_overflow +./safe_input_demo +./stack_layout_demo +./overflow_behavior_demo +./control_flow_simulation ``` -Expected: -- No warning -- Stable behavior - -### Long input - -Example: +Windows (MinGW): -```text -AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +```powershell +.\vuln_buffer_overflow.exe +.\safe_input_demo.exe +.\stack_layout_demo.exe +.\overflow_behavior_demo.exe +.\control_flow_simulation.exe ``` -Expected in unsafe demo: -- Warning about input length (in many runs) -- Possible variable corruption -- Possible crash +## Learning Path -Expected in safe demo: -- Input is bounded by `fgets(...)` -- No out-of-bounds write from input read +1. Start with `vuln_buffer_overflow` (unsafe behavior). +2. Compare with `safe_input_demo` (bounded input). +3. Run `stack_layout_demo` and observe address relationships. +4. Run `overflow_behavior_demo` with long input and observe effects. +5. Run `control_flow_simulation` to understand conceptual redirection. +6. Use GDB to inspect variables, stack state, and registers. -## Example Output (Unsafe Demo) +## Lab Exercises -```text -Address of buffer: 0x7ffd1234... -Address of x: 0x7ffd1240... -Address of parameter demo_id: 0x7ffd1250... -Value of x before input: 10 -... -WARNING: Input length (...) exceeds buffer capacity (15). -Nearby stack values may be corrupted (undefined behavior). -Value of x after input: ... -``` - -## GDB Quick Start - -```bash -gdb ./vuln_lab -``` +Step-by-step exercises: +- [docs/lab-exercises.md](docs/lab-exercises.md) -Useful commands: +## Demo Guide -```gdb -break main -run -step -next -print buffer -info locals -info registers -``` +Commands + sample outputs: +- [docs/demo.md](docs/demo.md) -More details: [docs/gdb-guide.md](docs/gdb-guide.md) +## Protection Mechanisms -## Core Concepts You Learn +Beginner explanation of ASLR, NX bit, and stack canaries: +- [docs/protections.md](docs/protections.md) -- Stack memory basics -- Safe vs unsafe input handling -- Why buffer size checks matter -- Undefined behavior and why it is dangerous -- Basic debugging workflow in GDB +## Advanced Concepts (Theory Only) -## How to Prevent Memory Vulnerabilities +Conceptual overview of stack smashing, shellcode, and ROP: +- [docs/advanced-concepts.md](docs/advanced-concepts.md) -- Prefer bounded input APIs like `fgets` -- Validate input lengths before processing -- Avoid unbounded input patterns like `scanf("%s", ...)` -- Compile with warnings enabled (`-Wall -Wextra`) -- Keep security protections enabled in real applications +## Debugging Guide -## Disclaimer +Current GDB workflow for modular binaries: +- [docs/gdb-guide.md](docs/gdb-guide.md) -This project is for education only. -Do not use these concepts on systems you do not own or have explicit permission to test. +## Demo Assets -## Learning Outcomes +Screenshots and visual captures: +- `docs/images/` +- `docs/images/gdb-session.png` +- `docs/images/overflow-output.png` +- `docs/images/control-flow.png` -After completing this lab, you should be able to: -- Identify unsafe input handling patterns -- Explain basic stack layout for local variables -- Observe and reason about undefined behavior -- Use GDB to inspect program state -- Write safer C input-handling code +## Safety and Scope -## Future Improvements +- Educational use only. +- Focused on understanding behavior and prevention. +- No exploit payloads, no exploitation walkthroughs. -- Add heap memory safety examples -- Add format-string safety module -- Add small guided debugging exercises -- Add diagrams for function stack frames - -## Contributing +## Disclaimer -Contributions are welcome: -- Improve docs and explanations -- Add beginner-friendly exercises -- Improve platform-specific run notes +Do not test on systems you do not own or have explicit permission to analyze. diff --git a/archive/main.c b/archive/main.c new file mode 100644 index 0000000..6d5fbf1 --- /dev/null +++ b/archive/main.c @@ -0,0 +1,13 @@ +/* + * Deprecated placeholder. + * + * This file is intentionally kept empty for compatibility with environments + * that currently lock file deletion/rename operations. + * + * Active lab programs are the modular demos in: + * - src/vuln_buffer_overflow.c + * - src/safe_input_demo.c + * - src/stack_layout_demo.c + * - src/overflow_behavior_demo.c + * - src/control_flow_simulation.c + */ diff --git a/archive/stack_behavior_demo.c b/archive/stack_behavior_demo.c new file mode 100644 index 0000000..d5e386d --- /dev/null +++ b/archive/stack_behavior_demo.c @@ -0,0 +1,11 @@ +/* + * Deprecated placeholder. + * + * This file is intentionally inactive. The project now uses five focused + * core programs: + * - vuln_buffer_overflow + * - safe_input_demo + * - stack_layout_demo + * - overflow_behavior_demo + * - control_flow_simulation + */ diff --git a/docs/advanced-concepts.md b/docs/advanced-concepts.md new file mode 100644 index 0000000..30eb5de --- /dev/null +++ b/docs/advanced-concepts.md @@ -0,0 +1,31 @@ +# Advanced Concepts (Theory Only) + +This file explains higher-level security concepts in simple terms. +It is conceptual only and does not include exploit code. + +## 1) Stack Smashing (Conceptual) + +- Stack smashing means writing past a local stack buffer into nearby stack data. +- Nearby data can include local variables, saved frame information, and return-control data. +- If return-control data is corrupted, execution may jump to an unintended location. +- Even small out-of-bounds writes can create unstable or unpredictable behavior. +- Modern systems add protections (canaries, ASLR, NX), but unsafe writes are still bugs. +- The key learning point is prevention: use bounded input and validate sizes. + +## 2) Shellcode (Conceptual) + +- Shellcode is a historical term for byte sequences intended to run as machine instructions. +- In older vulnerable setups, attackers tried to place these bytes in writable memory. +- Modern systems typically mark stack/heap as non-executable (NX), blocking this path. +- This concept matters for understanding why executable vs non-executable memory matters. +- In secure development, the priority is preventing memory corruption in the first place. +- This lab does not build, inject, or execute shellcode. + +## 3) Return-Oriented Programming (ROP) (Conceptual) + +- ROP is a technique that reuses short existing instruction sequences already in a program. +- Instead of injecting new code, it chains existing code snippets conceptually. +- ROP became relevant as protections like NX made direct code injection harder. +- Address randomization (ASLR) makes reliable chaining more difficult in practice. +- Understanding ROP is useful for threat awareness, not for implementation here. +- This lab keeps ROP as theory only and focuses on safe fundamentals. diff --git a/docs/demo.md b/docs/demo.md new file mode 100644 index 0000000..db815c3 --- /dev/null +++ b/docs/demo.md @@ -0,0 +1,191 @@ +# Demo Guide + +This is a quick, clean walkthrough for running the core memory lab demos. + +## 1) Setup + +Compile all core programs: + +```bash +make +``` + +Windows (MinGW) note: +- Use `.\\program.exe` instead of `./program`. + +## 2) Run Each Core Lab + +### Lab 1: Unsafe Input Behavior + +Run: + +```bash +./vuln_buffer_overflow +``` + +Example output: + +```text +[vuln_buffer_overflow] Unsafe input demo +Enter a word: AAAAAAAAAAAAAAAAAAAAA +You entered: AAAAAAAAAAAAAAAAAAAAA +``` + +What you will see: +- Input is accepted without explicit length limits. +- Long input can produce unstable behavior in unsafe programs. + +### Lab 2: Safe Input Demo + +Run: + +```bash +./safe_input_demo +``` + +Example output: + +```text +[safe_input_demo] Safe input demo +Enter text: hello +You entered safely: hello +``` + +What you will see: +- `fgets(...)` reads with a size boundary. +- Behavior is safer and more predictable. + +### Lab 3: Stack Layout Demo + +Run: + +```bash +./stack_layout_demo +``` + +Example output: + +```text +[stack_layout_demo] Stack address observation +Address of main_local: 0x7ff... +Address of buffer: 0x7ff... +Address of x: 0x7ff... +Address of parameter demo_id: 0x7ff... +``` + +What you will see: +- Local addresses are often close together. +- Absolute addresses may change between runs. + +### Lab 4: Overflow Behavior Demo + +Run: + +```bash +./overflow_behavior_demo +``` + +Example output: + +```text +[overflow_behavior_demo] Observe behavior with long input +Value of x before input: 10 +Enter input: WARNING: Input length (30) exceeds buffer capacity (15). +Behavior may be unstable (undefined behavior). +Value of x after input: 1094795585 +Buffer content: AAAAAAAAAAAAAAAA... +``` + +Clean beginner-friendly version: + +```text +User types: AAAAAAAAAAAAAAAA +Output: +Value of x before input: 10 +WARNING: Input exceeds buffer size +Value of x after input: 1094795585 +``` + +What you will see: +- Warning for oversized input. +- Possible unstable values because overflow is undefined behavior. + +### Lab 5: Control Flow Simulation + +Run: + +```bash +./control_flow_simulation +``` + +Example output: + +```text +[control_flow_simulation] Conceptual control-flow demo +Address of safe_function: 00401460 +Address of target_function: 00401475 +Address of func_ptr var: 0061FF1C + +Calling through function pointer (before change): +safe_function(): normal control flow path. + +Simulating conceptual pointer corruption by manual reassignment... +Calling through function pointer (after change): +target_function(): alternate control flow path. +``` + +What you will see: +- Changing function pointer target changes executed function. +- This is a controlled simulation, not real memory corruption. + +Visual proof: +- `docs/images/overflow-output.png` +- `docs/images/control-flow.png` + +### Lab 6: Debugging with GDB (Optional but Recommended) + +Start with `stack_layout_demo`: + +```bash +gdb ./stack_layout_demo +``` + +Useful commands: + +```gdb +break main +run +next +step +info locals +info registers +``` + +What you will see: +- Line-by-line execution state. +- Variable and register values during runtime. + +Visual proof: +- `docs/images/gdb-session.png` + +## 3) What This Teaches + +- Why unbounded input is risky. +- How bounded input reduces risk. +- How stack variables are arranged in memory. +- Why undefined behavior is dangerous. +- How control flow concepts can be taught safely. + +## 4) Screenshot Evidence + +### GDB Session + +![GDB session](images/gdb-session.png) + +### Overflow Output + +![Overflow output](images/overflow-output.png) + +### Control Flow Simulation + +![Control flow simulation](images/control-flow.png) diff --git a/docs/gdb-guide.md b/docs/gdb-guide.md index 12576a3..749ce45 100644 --- a/docs/gdb-guide.md +++ b/docs/gdb-guide.md @@ -1,96 +1,126 @@ -# GDB Beginner Guide (Memory Learning Lab) +# GDB Guide (Current Multi-File Lab) -This guide helps you inspect program state while learning safe vs unsafe memory handling. +This guide uses the current modular binaries: +- `stack_layout_demo` +- `overflow_behavior_demo` -## 1. Compile With Debug Symbols +## 1. Build With Debug Symbols -Debug symbols let GDB map machine code back to your C source code and variable names. +Use the project Makefile: ```bash -gcc -g -Wall -Wextra -O0 -o vuln_lab src/main.c +make ``` -If you use the project Makefile, it already includes `-g` and `-O0`. - -## 2. Start GDB +Or compile specific targets manually: ```bash -gdb ./vuln_lab +gcc -Wall -Wextra -g -O0 -o stack_layout_demo src/stack_layout_demo.c +gcc -Wall -Wextra -g -O0 -o overflow_behavior_demo src/overflow_behavior_demo.c ``` -## 3. Core GDB Commands +Why `-g` and `-O0` matter: +- `-g` gives GDB variable and line information. +- `-O0` avoids heavy optimization so variables are easier to inspect. -Set a breakpoint at program entry: +## 2. GDB on stack_layout_demo -```gdb -break main +Start debugger: + +```bash +gdb ./stack_layout_demo ``` -Run the program: +Useful flow: ```gdb +break main run +next +step +info locals +print main_local ``` -Execute the next line (without stepping into function calls): +What to inspect: +- `main_local` in `main()` +- addresses printed by `print_stack_layout(...)` + +Example address checks: ```gdb -next +break print_stack_layout +run +print &demo_id +print &x +print &buffer +info registers ``` -Step into the next function call: +What this teaches: +- local variables and parameters are placed in the function stack frame +- addresses are often close together +- exact addresses can vary between runs -```gdb -step +## 3. GDB on overflow_behavior_demo + +Start debugger: + +```bash +gdb ./overflow_behavior_demo ``` -Print a variable value: +Set breakpoints around unsafe input: ```gdb -print choice -print buffer +break main +run +next +next ``` -Show all local variables in the current function: +Step until you reach the `scanf("%s", buffer)` line, then inspect: ```gdb +print x +print &x +print &buffer info locals ``` -Show CPU register values: +Continue after input and inspect again: ```gdb -info registers +next +next +print x +print input_len +info locals ``` -## 4. Memory Concepts (Beginner-Friendly) - -### What Is The Stack? - -The stack is a memory region used for function calls. -When a function starts, it gets a stack frame that stores local data (like `char buffer[16]`) and bookkeeping data for returning to the caller. - -### How Local Variables Are Stored - -Local variables are usually stored inside the current stack frame. -That is why printing a local buffer address (for example, with `printf("%p", (void *)buffer)`) helps you see where that variable lives in memory during execution. +What this teaches: +- `x` and `buffer` are neighboring local values in stack memory +- oversized input can lead to undefined behavior +- observed outcomes can vary by run and environment -### Why Buffer Size Matters +## 4. Core GDB Commands (Quick Reference) -A buffer has a fixed capacity. -If input writes more bytes than the buffer can hold, memory outside the buffer can be overwritten. This is called a buffer overflow and can cause crashes or undefined behavior. - -Safe input APIs such as `fgets(buffer, sizeof(buffer), stdin)` limit how many bytes are written, helping prevent overflow. +```gdb +break main +run +next +step +print x +print buffer +print &buffer +info locals +info registers +continue +quit +``` -## 5. Suggested Practice +## 5. Beginner Practice Path -1. Run program normally: - - `./vuln_lab` -2. Start debugger: - - `gdb ./vuln_lab` -3. Try these commands: - - `break main` - - `run` - - `step` - - `print buffer` - - `info registers` +1. Run `stack_layout_demo` in GDB and inspect variable addresses. +2. Run `overflow_behavior_demo` in GDB and inspect `x`, `buffer`, and `input_len`. +3. Compare runs to see what stays similar (relative layout) and what changes (absolute addresses). diff --git a/docs/images/README.md b/docs/images/README.md new file mode 100644 index 0000000..59431f8 --- /dev/null +++ b/docs/images/README.md @@ -0,0 +1,15 @@ +# Demo Screenshots + +Real captured outputs are available: + +- `gdb-session.png` - GDB breakpoint, locals, and register snapshot +- `overflow-output.png` - overflow behavior run with long input +- `control-flow.png` - control flow simulation before/after pointer change + +Supporting raw transcripts: + +- `gdb-session.txt` +- `overflow-output.txt` +- `control-flow-output.txt` + +Note: older placeholder files may remain due file-lock restrictions in this environment; use the PNG files above as the canonical visuals. diff --git a/docs/images/control-flow.png b/docs/images/control-flow.png new file mode 100644 index 0000000..7188008 Binary files /dev/null and b/docs/images/control-flow.png differ diff --git a/docs/images/gdb-session.png b/docs/images/gdb-session.png new file mode 100644 index 0000000..03d68aa Binary files /dev/null and b/docs/images/gdb-session.png differ diff --git a/docs/images/overflow-output.png b/docs/images/overflow-output.png new file mode 100644 index 0000000..5c04223 Binary files /dev/null and b/docs/images/overflow-output.png differ diff --git a/docs/lab-exercises.md b/docs/lab-exercises.md new file mode 100644 index 0000000..b0a735d --- /dev/null +++ b/docs/lab-exercises.md @@ -0,0 +1,206 @@ +# Lab Exercises (Beginner-Friendly) + +These exercises help you practice memory-safety concepts step by step. +Each lab includes: +- what to run +- what to observe +- what it means + +## Lab 1: Unsafe Input Behavior + +### What to run + +Build: + +```bash +make vuln_buffer_overflow +``` + +Run: + +Linux/macOS: + +```bash +./vuln_buffer_overflow +``` + +Windows (MinGW): + +```powershell +.\vuln_buffer_overflow.exe +``` + +Try entering a long input string. + +### What to observe + +- Program behavior with normal input vs long input +- Whether output becomes unstable or unexpected + +### What it means + +`scanf("%s", ...)` does not limit input length. +If input is longer than the buffer, memory outside the buffer may be overwritten (undefined behavior). + +## Lab 2: Safe vs Unsafe Comparison + +### What to run + +Build both: + +```bash +make safe_input_demo vuln_buffer_overflow +``` + +Run each program and enter similar inputs: + +- short input (for example: `hello`) +- long input (for example: many `A` characters) + +### What to observe + +- `safe_input_demo` remains stable because input is bounded +- `vuln_buffer_overflow` may behave unpredictably with long input + +### What it means + +Bounded input functions like `fgets(...)` reduce overflow risk. +Unbounded input patterns are dangerous in C. + +## Lab 3: Stack Memory Layout + +### What to run + +Build: + +```bash +make stack_layout_demo +``` + +Run: + +Linux/macOS: + +```bash +./stack_layout_demo +``` + +Windows (MinGW): + +```powershell +.\stack_layout_demo.exe +``` + +### What to observe + +- Printed addresses for local variables and function parameters +- Addresses are often close together +- Re-running may change absolute addresses + +### What it means + +Local variables are typically placed in the current stack frame. +Relative ordering is often similar, while exact addresses can change between runs (for example, due to ASLR). + +## Lab 4: Overflow Behavior + +### What to run + +Build: + +```bash +make overflow_behavior_demo +``` + +Run and enter a long string: + +Linux/macOS: + +```bash +./overflow_behavior_demo +``` + +Windows (MinGW): + +```powershell +.\overflow_behavior_demo.exe +``` + +### What to observe + +- Value of variable `x` before and after input +- Warning message for oversized input +- Possible instability depending on run/environment + +### What it means + +When input exceeds buffer size, nearby memory may be affected. +This is undefined behavior, so outcomes are not guaranteed. + +## Lab 5: Control Flow Simulation + +### What to run + +Build: + +```bash +make control_flow_simulation +``` + +Run: + +Linux/macOS: + +```bash +./control_flow_simulation +``` + +Windows (MinGW): + +```powershell +.\control_flow_simulation.exe +``` + +### What to observe + +- Function pointer calls `safe_function()` first +- After reassignment, the same pointer calls `target_function()` +- Printed function addresses and pointer variable address + +### What it means + +Control flow depends on which code address is used. +This lab safely demonstrates redirection conceptually through normal reassignment, not memory corruption. + +## Lab 6: Debugging with GDB + +### What to run + +Use GDB on any demo program (example: `stack_layout_demo`): + +```bash +gdb ./stack_layout_demo +``` + +Useful commands inside GDB: + +```gdb +break main +run +next +step +info locals +print x +info registers +``` + +### What to observe + +- Program state line by line +- Current variable values +- Register changes during execution + +### What it means + +GDB helps you see how C code maps to runtime behavior. +This is essential for understanding memory layout, variable lifetimes, and debugging unsafe behavior. diff --git a/docs/protections.md b/docs/protections.md new file mode 100644 index 0000000..8f3b375 --- /dev/null +++ b/docs/protections.md @@ -0,0 +1,59 @@ +# Runtime Protections (Beginner Guide) + +Modern systems include security protections to make memory bugs harder to abuse. +These protections reduce risk, but they do not replace safe coding. + +## 1. ASLR (Address Space Layout Randomization) + +What it does: +- ASLR places important memory regions (stack, heap, libraries) at different addresses each run. + +Why addresses change between runs: +- The operating system intentionally randomizes where things are loaded. +- So an address you see in one run is often different in the next run. + +How it helps: +- Attackers cannot easily rely on fixed memory addresses. +- This makes many memory-abuse attempts less reliable. + +## 2. NX Bit (Non-Executable Memory) + +What it does: +- NX marks some memory areas as data-only, not executable code. + +What it prevents: +- It blocks running injected bytes as machine code from places like the stack. + +Why stack code execution is blocked: +- The stack is usually marked non-executable on modern systems. +- Even if unsafe data is written there, the CPU refuses to execute it as code. + +## 3. Stack Canaries + +What they are: +- A small secret value placed on the stack near sensitive control data. + +How they detect buffer overflow: +- If a buffer overflow overwrites past a local buffer, it often changes the canary too. +- Before returning from a function, the program checks whether the canary changed. +- If changed, the program stops because stack corruption is detected. + +## How These Protections Help Prevent Memory Exploitation + +- ASLR makes target addresses unpredictable. +- NX blocks executing data from non-executable memory regions. +- Stack canaries detect many stack overwrites before normal return flow continues. + +Together, they add layered defense and make memory exploitation much harder. + +## Why This Lab Still Works Conceptually + +This lab focuses on understanding memory behavior and safe vs unsafe coding patterns. +Even when real systems have protections, the core concepts are still important: + +- Buffers still have fixed sizes. +- Out-of-bounds writes are still bugs. +- Undefined behavior is still dangerous. + +In other words, protections reduce impact, but they do not make unsafe code safe. +That is why this lab may conceptually ignore or simplify protections while teaching fundamentals. diff --git a/src/control_flow_simulation.c b/src/control_flow_simulation.c new file mode 100644 index 0000000..d142b84 --- /dev/null +++ b/src/control_flow_simulation.c @@ -0,0 +1,52 @@ +#include + +/* + * safe_function: + * Default control-flow target in this demo. + */ +static void safe_function(void) { + printf("safe_function(): normal control flow path.\n"); +} + +/* + * target_function: + * Alternate function used to show how changing a function pointer + * changes which code executes. + */ +static void target_function(void) { + printf("target_function(): alternate control flow path.\n"); +} + +int main(void) { + /* + * A function pointer stores an address of executable code. + * Calling through this pointer transfers control to the function + * currently stored in it. + */ + void (*func_ptr)(void) = safe_function; + + printf("[control_flow_simulation] Conceptual control-flow demo\n"); + printf("Address of safe_function: %p\n", (void *)safe_function); + printf("Address of target_function: %p\n", (void *)target_function); + printf("Address of func_ptr var: %p\n", (void *)&func_ptr); + + printf("\nCalling through function pointer (before change):\n"); + func_ptr(); + + /* + * Conceptual simulation: + * We manually reassign the function pointer to a different function. + * This is a safe, explicit reassignment (not memory corruption). + * + * In real stack-smashing scenarios, overwritten return addresses can + * redirect execution unexpectedly. This demo only illustrates the idea + * of control-flow redirection without exploit code. + */ + printf("\nSimulating conceptual pointer corruption by manual reassignment...\n"); + func_ptr = target_function; + + printf("Calling through function pointer (after change):\n"); + func_ptr(); + + return 0; +} diff --git a/src/main.c b/src/main.c deleted file mode 100644 index 470501d..0000000 --- a/src/main.c +++ /dev/null @@ -1,120 +0,0 @@ -#include -#include - -/* - * Memory Vulnerability Learning Lab - * - * This file demonstrates unsafe and safe ways to read user input. - * The unsafe version is kept for education only. - */ - -void unsafe_input(int demo_id) { - char buffer[16]; - int x = 10; - size_t input_len = 0; - - printf("\n[UNSAFE DEMO] Enter your name: "); - printf("Address of buffer: %p\n", (void *)buffer); - printf("Address of x: %p\n", (void *)&x); - printf("Address of parameter demo_id: %p\n", (void *)&demo_id); - printf("Value of x before input: %d\n", x); - - /* - * These addresses are locations of variables inside this function's - * stack frame (current function call memory). - * - * Typical behavior on many systems: - * - The stack grows downward (from higher to lower addresses). - * - Local variables and parameters are often stored near each other. - * - * Exact order can vary by compiler, architecture, and optimization level. - */ - - /* - * DANGEROUS: - * "%s" with scanf() does not limit input length. - * If the user types more than 15 characters (+ '\0'), - * it can write past buffer boundaries (buffer overflow). - * - * Important learning point: - * this read happens before any length check below, so the overflow - * (if it occurs) may already have corrupted nearby stack data. - */ - if (scanf("%s", buffer) != 1) { - printf("Input error.\n"); - return; - } - - input_len = strlen(buffer); - if (input_len >= sizeof(buffer)) { - printf("WARNING: Input length (%lu) exceeds buffer capacity (%lu).\n", - (unsigned long)input_len, - (unsigned long)(sizeof(buffer) - 1)); - printf("Nearby stack values may be corrupted (undefined behavior).\n"); - } - - printf("Value of x after input: %d\n", x); - printf("You entered (unsafe path): %s\n", buffer); -} - -void safe_input(int demo_id) { - char buffer[16]; - int x = 10; - - printf("\n[SAFE DEMO] Enter your name: "); - printf("Address of buffer: %p\n", (void *)buffer); - printf("Address of x: %p\n", (void *)&x); - printf("Address of parameter demo_id: %p\n", (void *)&demo_id); - - /* - * Same stack concept as the unsafe demo: - * buffer, x, and demo_id belong to this function call context. - * Their addresses help visualize how stack memory is laid out. - */ - - /* - * SAFER: - * fgets() receives the buffer size, so it reads at most - * sizeof(buffer) - 1 characters and always terminates with '\0'. - * This prevents writing beyond the buffer. - */ - if (fgets(buffer, sizeof(buffer), stdin) == NULL) { - printf("Input error.\n"); - return; - } - - /* Remove trailing newline (if present) for cleaner output. */ - buffer[strcspn(buffer, "\n")] = '\0'; - - printf("You entered (safe path): %s\n", buffer); -} - -int main(void) { - char choice_line[8]; - int choice = 0; - - printf("Memory Handling Lab\n"); - printf("1 = Unsafe input demo\n"); - printf("2 = Safe input demo\n"); - printf("Choose an option: "); - - if (fgets(choice_line, sizeof(choice_line), stdin) == NULL) { - printf("Failed to read choice.\n"); - return 1; - } - - if (sscanf(choice_line, "%d", &choice) != 1) { - printf("Invalid choice.\n"); - return 1; - } - - if (choice == 1) { - unsafe_input(choice); - } else if (choice == 2) { - safe_input(choice); - } else { - printf("Invalid option. Use 1 or 2.\n"); - } - - return 0; -} diff --git a/src/overflow_behavior_demo.c b/src/overflow_behavior_demo.c new file mode 100644 index 0000000..e3816dc --- /dev/null +++ b/src/overflow_behavior_demo.c @@ -0,0 +1,42 @@ +#include +#include + +/* + * Overflow behavior observation demo (educational only). + * + * This intentionally keeps an unsafe read to demonstrate that + * out-of-bounds writes can lead to undefined behavior. + * No exploit logic is included. + */ +int main(void) { + char buffer[16]; + int x = 10; + size_t input_len = 0; + + printf("[overflow_behavior_demo] Observe behavior with long input\n"); + printf("Value of x before input: %d\n", x); + printf("Enter input: "); + + /* + * Unsafe: no width limit is provided. + * If input exceeds buffer capacity, overflow may happen before + * the length check below can run. + */ + if (scanf("%s", buffer) != 1) { + printf("Input error.\n"); + return 1; + } + + input_len = strlen(buffer); + if (input_len >= sizeof(buffer)) { + printf("WARNING: Input length (%lu) exceeds buffer capacity (%lu).\n", + (unsigned long)input_len, + (unsigned long)(sizeof(buffer) - 1)); + printf("Behavior may be unstable (undefined behavior).\n"); + } + + printf("Value of x after input: %d\n", x); + printf("Buffer content: %s\n", buffer); + + return 0; +} diff --git a/src/safe_input_demo.c b/src/safe_input_demo.c new file mode 100644 index 0000000..0c8de82 --- /dev/null +++ b/src/safe_input_demo.c @@ -0,0 +1,27 @@ +#include +#include + +/* + * Safe input demo. + * + * fgets() receives the buffer size, so it reads at most + * sizeof(buffer) - 1 characters and prevents buffer overflow + * from this input operation. + */ +int main(void) { + char buffer[16]; + + printf("[safe_input_demo] Safe input demo\n"); + printf("Enter text: "); + + if (fgets(buffer, sizeof(buffer), stdin) == NULL) { + printf("Input error.\n"); + return 1; + } + + /* Remove trailing newline for cleaner output. */ + buffer[strcspn(buffer, "\n")] = '\0'; + + printf("You entered safely: %s\n", buffer); + return 0; +} diff --git a/src/stack_layout_demo.c b/src/stack_layout_demo.c new file mode 100644 index 0000000..e6b2ffe --- /dev/null +++ b/src/stack_layout_demo.c @@ -0,0 +1,31 @@ +#include + +/* + * Stack layout demo. + * + * Prints addresses of local variables and a function parameter + * to help visualize how function-call memory is arranged. + */ +static void print_stack_layout(int demo_id) { + char buffer[16]; + int x = 10; + + /* + * These addresses are typically in the current stack frame. + * On many systems, the stack often grows downward + * (from higher addresses toward lower addresses). + */ + printf("Address of buffer: %p\n", (void *)buffer); + printf("Address of x: %p\n", (void *)&x); + printf("Address of parameter demo_id: %p\n", (void *)&demo_id); +} + +int main(void) { + int main_local = 1; + + printf("[stack_layout_demo] Stack address observation\n"); + printf("Address of main_local: %p\n", (void *)&main_local); + print_stack_layout(42); + + return 0; +} diff --git a/src/vuln_buffer_overflow.c b/src/vuln_buffer_overflow.c new file mode 100644 index 0000000..a1044c0 --- /dev/null +++ b/src/vuln_buffer_overflow.c @@ -0,0 +1,24 @@ +#include + +/* + * Unsafe buffer input demo (educational only). + * + * WARNING: + * scanf("%s", ...) does not enforce a maximum length. + * If input is longer than the buffer, memory past the buffer + * may be overwritten. + */ +int main(void) { + char buffer[16]; + + printf("[vuln_buffer_overflow] Unsafe input demo\n"); + printf("Enter a word: "); + + if (scanf("%s", buffer) != 1) { + printf("Input error.\n"); + return 1; + } + + printf("You entered: %s\n", buffer); + return 0; +}