From 9cd68e6cd56bceea011816b05a11d32f29861bdf Mon Sep 17 00:00:00 2001 From: Urval Date: Thu, 9 Apr 2026 10:43:15 +0530 Subject: [PATCH 1/2] Final pushing of md --- README.md | 286 ++++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 215 insertions(+), 71 deletions(-) diff --git a/README.md b/README.md index 4d78502..9d65922 100644 --- a/README.md +++ b/README.md @@ -1,114 +1,258 @@ -# Exploit Lab +# Exploit Lab (C Memory Safety Demos) -Hands-on C demos for observing unsafe input, stack layout, overflow behavior, and control-flow concepts in a controlled, educational environment. +A beginner-friendly C lab that demonstrates unsafe vs safe input handling, stack memory layout, overflow side effects, and conceptual control-flow changes. -## Overview +## 1. Title + Tagline -This repository is a memory-safety learning lab built around small, focused C programs. It exists to show how unsafe input handling behaves, how stack memory is laid out at runtime, how undefined behavior can appear after an out-of-bounds write, and how function-pointer reassignment changes execution flow in a safe, explicit way. +**Project name:** Exploit Lab (C Memory Safety Demos) -The project is relevant to application security, systems programming, and debugging workflows. It is designed to help developers and learners understand why bounded input, runtime inspection, and defensive coding practices matter in real programs. +**Tagline:** Learn how common C memory-safety mistakes behave at runtime, and how safer patterns reduce risk. -## Features +## 2. ๐Ÿš€ Overview -- Demonstrates unsafe input handling with `scanf("%s", ...)` in a small stack-buffer example. -- Demonstrates safe input handling with `fgets(...)` and newline cleanup. -- Prints stack-frame addresses for local variables and function parameters. -- Shows overflow-related instability in a controlled demo that warns when input exceeds the buffer capacity. -- Simulates control-flow redirection with a function pointer reassignment. -- Includes GDB-oriented walkthroughs for inspecting locals, registers, and stack state. -- Documents runtime protections such as ASLR, NX, and stack canaries at a conceptual level. -- Provides captured screenshots and notes for the demos in `docs/images/`. -- Includes a GitHub Actions workflow that compiles all active demos on push and pull request. +This project contains small, focused C programs that help you observe memory-safety concepts directly from terminal output. -## Tech Stack +It was built as an educational lab for beginners who want practical understanding of: + +- unbounded input (`scanf("%s", ...)`) vs bounded input (`fgets(...)`) +- stack variable and parameter address layout +- how out-of-bounds writes can lead to undefined behavior +- how control flow can change when a function pointer target changes + +In real life, these concepts matter in secure software development, code review, debugging, and vulnerability prevention. + +## 3. ๐Ÿ”ฅ Features (Implemented) + +- Unsafe input demo (`vuln_buffer_overflow`): reads into a fixed 16-byte buffer with `scanf("%s", ...)` and shows why missing length limits is risky. +- Safe input demo (`safe_input_demo`): uses `fgets(...)` with buffer size and removes trailing newline for stable behavior. +- Stack layout demo (`stack_layout_demo`): prints addresses of locals and a function parameter to visualize stack-frame organization. +- Overflow behavior demo (`overflow_behavior_demo`): compares variable state before/after input and warns when input length exceeds buffer capacity. +- Control-flow simulation (`control_flow_simulation`): safely reassigns a function pointer to demonstrate how call targets change. +- Build automation: `Makefile` builds all active programs, includes strict verify target (`-Werror`), and clean target. +- CI compilation check: GitHub Actions compiles all active programs on push and pull request. +- Learning docs: walkthroughs, GDB guide, exercises, memory/protection notes, and screenshots in `docs/`. + +## 4. ๐Ÿ›  Tech Stack - Language: C - Compiler: GCC -- Debugger: GDB - Build tool: Make -- CI: GitHub Actions -- Target platforms: Linux and Windows with MinGW-compatible builds - -## Project Structure - -- `src/` -> active lab programs that build into the five demo binaries - - `vuln_buffer_overflow.c` -> unsafe input demo using `scanf("%s", ...)` - - `safe_input_demo.c` -> bounded input demo using `fgets(...)` - - `stack_layout_demo.c` -> prints stack addresses for local values and a parameter - - `overflow_behavior_demo.c` -> shows undefined behavior risk after oversized input - - `control_flow_simulation.c` -> safe function-pointer reassignment demo -- `docs/` -> guided learning material and reference notes - - `demo.md` -> quick walkthrough and sample outputs - - `gdb-guide.md` -> debugging workflow for the active binaries - - `lab-exercises.md` -> step-by-step beginner exercises - - `memory-layout.md` -> stack and buffer basics - - `protections.md` -> ASLR, NX, and stack canaries overview - - `advanced-concepts.md` -> conceptual theory only - - `images/` -> screenshots and supporting visual assets -- `archive/` -> deprecated placeholder files retained for compatibility - - `main.c` -> inactive placeholder - - `stack_behavior_demo.c` -> inactive placeholder -- `.github/workflows/` -> CI workflow that compiles the demo programs -- `Makefile` -> build, verify, and clean targets -- `README.md` -> project overview and setup guide - -## Setup & Installation - -Clone the repository: +- Debugging tool: GDB (optional, documented) +- CI: GitHub Actions (`ubuntu-latest`, GCC install + compile checks) +- External libraries/frameworks: none + +## 5. ๐Ÿ“‚ Project Structure + +```text +exploit-lab-cpp/ +|- src/ +| |- vuln_buffer_overflow.c +| |- safe_input_demo.c +| |- stack_layout_demo.c +| |- overflow_behavior_demo.c +| |- control_flow_simulation.c +|- docs/ +| |- demo.md +| |- gdb-guide.md +| |- lab-exercises.md +| |- memory-layout.md +| |- protections.md +| |- advanced-concepts.md +| |- images/ +| |- control-flow.png +| |- gdb-session.png +| |- overflow-output.png +| |- README.md +|- archive/ +| |- main.c +| |- stack_behavior_demo.c +|- .github/workflows/ +| |- build.yml +|- Makefile +|- project.md +|- README.md +``` + +Folder guide: + +- `src/` -> active demo programs you compile and run. +- `docs/` -> beginner documentation, exercises, and concept references. +- `docs/images/` -> captured screenshots from real demo/debug runs. +- `archive/` -> deprecated placeholder files kept for compatibility; not active lab logic. +- `.github/workflows/` -> CI workflow that validates compilation. + +## 6. โš™๏ธ Setup & Installation + +### Prerequisites + +- GCC +- Make +- Optional: GDB + +### Step-by-step + +1. Clone the repository. ```bash git clone https://github.com/urvalkheni/exploit-lab-cpp.git -cd exploit-lab-cpp ``` -Install the required tools: +What it does: downloads the project to your machine. -- Linux: `gcc`, `make`, and optionally `gdb` -- Windows: MinGW or another GCC-compatible toolchain, plus `make` +2. Move into the project folder. -Build all demos: +```bash +cd exploit-lab-cpp +``` + +What it does: sets your terminal working directory to this project. + +3. Build all demo binaries. ```bash make ``` -Run a demo: +What it does: compiles all programs in `src/` using debug-friendly flags (`-g -O0`). + +4. (Optional) Run strict compile verification. + +```bash +make verify +``` + +What it does: recompiles with `-Werror` so warnings fail the build. + +5. Run a program. + +Linux/macOS: ```bash ./safe_input_demo ``` -Windows (MinGW): +Windows (MinGW style): ```powershell .\safe_input_demo.exe ``` -If you want to verify compilation without using the default build target, run: +## 7. ๐Ÿงช Usage Examples + +Build and run all demos one by one: ```bash -make verify +make +./vuln_buffer_overflow +./safe_input_demo +./stack_layout_demo +./overflow_behavior_demo +./control_flow_simulation +``` + +What each command does: + +- `./vuln_buffer_overflow` -> demonstrates unbounded input behavior. +- `./safe_input_demo` -> demonstrates bounded input using `fgets`. +- `./stack_layout_demo` -> prints stack addresses for observation. +- `./overflow_behavior_demo` -> shows warning and possible instability with oversized input. +- `./control_flow_simulation` -> shows function-pointer target change and resulting call path. + +Optional debugging example: + +```bash +gdb ./stack_layout_demo +``` + +Inside GDB: + +```gdb +break main +run +next +step +info locals +info registers +``` + +## 8. ๐Ÿ“Š Example Output + +`safe_input_demo` + +```text +[safe_input_demo] Safe input demo +Enter text: hello +You entered safely: hello ``` -## Available Demos +`overflow_behavior_demo` (long input case) + +```text +[overflow_behavior_demo] Observe behavior with long input +Value of x before input: 10 +Enter input: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +WARNING: Input length (30) exceeds buffer capacity (15). +Behavior may be unstable (undefined behavior). +Value of x after input: 1094795585 +Buffer content: AAAAAAAAAAAAAAAA... +``` + +`control_flow_simulation` + +```text +[control_flow_simulation] Conceptual control-flow demo +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. +``` + +## 9. ๐Ÿง  How It Works + +General flow: + +1. **Input:** user enters text in terminal. +2. **Processing:** each program handles input using either unsafe or safe logic, and may print memory-related information. +3. **Output:** terminal output shows observed behavior (stable output, warnings, address prints, or changed control-flow target). + +Program-level summary: + +- `vuln_buffer_overflow`: unbounded read into fixed-size stack buffer. +- `safe_input_demo`: bounded read with cleanup. +- `stack_layout_demo`: prints addresses to show layout patterns. +- `overflow_behavior_demo`: inspects overflow side effects and warns user. +- `control_flow_simulation`: demonstrates explicit function-pointer redirection safely. + +## 10. ๐Ÿ” Limitations / Notes + +- This is a conceptual training lab, not a full exploitation framework. +- Behavior is environment-dependent: compiler, OS, architecture, and protections affect runtime results. +- Overflow outcomes are undefined behavior, so outputs can vary or crash unexpectedly. +- `control_flow_simulation` uses manual pointer reassignment, not real memory corruption. +- Archive files in `archive/` are inactive placeholders. +- The repository currently validates compilation in CI but does not include automated runtime tests. + +## 11. ๐ŸŽฏ Learning Outcomes + +By completing this lab, you practice: -- `vuln_buffer_overflow` -> unsafe input behavior demonstration -- `safe_input_demo` -> bounded input demonstration -- `stack_layout_demo` -> runtime stack address observation -- `overflow_behavior_demo` -> overflow effect observation with a warning -- `control_flow_simulation` -> conceptual control-flow redirection via a function pointer +- secure input handling in C +- identifying unsafe code patterns +- understanding stack-frame memory layout basics +- interpreting undefined behavior warnings and effects +- using GDB to inspect program state +- reading and maintaining build/CI configuration -## Helpful Docs +## 12. ๐Ÿš€ Future Improvements -- [Demo guide](docs/demo.md) -- [Lab exercises](docs/lab-exercises.md) -- [GDB guide](docs/gdb-guide.md) -- [Memory layout basics](docs/memory-layout.md) -- [Runtime protections](docs/protections.md) -- [Advanced concepts](docs/advanced-concepts.md) +- Add small automated runtime checks for stable demos. +- Add a unified script to run all demos with sample inputs. +- Expand docs with platform-specific troubleshooting notes. -## Safety and Scope +## 13. โš ๏ธ Disclaimer -This project is educational and defensive in scope. It does not include exploit payloads or a real exploitation walkthrough. The focus is on understanding memory behavior, debugging, and safer programming patterns. +This project is for educational and defensive learning purposes only. -Do not run these experiments on systems you do not own or have explicit permission to analyze. +Use these techniques only on systems you own or are explicitly authorized to test. From 8452858c940cff23fbb09fa6233106471cafdf66 Mon Sep 17 00:00:00 2001 From: Urval Date: Tue, 14 Apr 2026 14:30:47 +0530 Subject: [PATCH 2/2] feat: make memory-safety demos deterministic, testable, and CI-verified --- .github/workflows/build.yml | 17 +- Makefile | 29 ++- README.md | 224 +++++-------------- docs/demo.md | 174 +++++---------- docs/lab-exercises.md | 155 ++++--------- project.md | 253 +++------------------ src/control_flow_simulation.c | 39 ++-- src/demo_programs.h | 12 + src/overflow_behavior_demo.c | 143 ++++++++++-- src/safe_input_demo.c | 20 +- src/stack_layout_demo.c | 24 +- src/vuln_buffer_overflow.c | 20 +- tests/demo_runtime_checks.c | 294 +++++++++++++++++++++++++ tests/runtime_check_1776156560_0.tmp | 1 + tests/runtime_check_1776156560_1.tmp | 2 + tests/runtime_check_1776156560_2.tmp | 1 + tests/runtime_check_1776156560_3.tmp | 2 + tests/runtime_check_1776156560_4.tmp | 5 + tests/runtime_check_1776156560_5.tmp | 1 + tests/runtime_check_1776156560_6.tmp | 9 + tests/runtime_check_1776156560_7.tmp | 11 + tests/runtime_check_1776156908_1_0.tmp | 1 + tests/runtime_check_1776156908_1_1.tmp | 2 + tests/runtime_check_1776156908_1_2.tmp | 1 + tests/runtime_check_1776156908_1_3.tmp | 2 + tests/runtime_check_1776156908_2_4.tmp | 5 + tests/runtime_check_1776156908_2_5.tmp | 1 + tests/runtime_check_1776156908_2_6.tmp | 9 + tests/runtime_check_1776156908_3_7.tmp | 11 + 29 files changed, 776 insertions(+), 692 deletions(-) create mode 100644 src/demo_programs.h create mode 100644 tests/demo_runtime_checks.c create mode 100644 tests/runtime_check_1776156560_0.tmp create mode 100644 tests/runtime_check_1776156560_1.tmp create mode 100644 tests/runtime_check_1776156560_2.tmp create mode 100644 tests/runtime_check_1776156560_3.tmp create mode 100644 tests/runtime_check_1776156560_4.tmp create mode 100644 tests/runtime_check_1776156560_5.tmp create mode 100644 tests/runtime_check_1776156560_6.tmp create mode 100644 tests/runtime_check_1776156560_7.tmp create mode 100644 tests/runtime_check_1776156908_1_0.tmp create mode 100644 tests/runtime_check_1776156908_1_1.tmp create mode 100644 tests/runtime_check_1776156908_1_2.tmp create mode 100644 tests/runtime_check_1776156908_1_3.tmp create mode 100644 tests/runtime_check_1776156908_2_4.tmp create mode 100644 tests/runtime_check_1776156908_2_5.tmp create mode 100644 tests/runtime_check_1776156908_2_6.tmp create mode 100644 tests/runtime_check_1776156908_3_7.tmp diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index e83f0ef..6cb4227 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -1,23 +1,18 @@ -name: Build +name: Build and Test on: [push, pull_request] jobs: - compile: + verify: runs-on: ubuntu-latest steps: - name: Checkout uses: actions/checkout@v4 - - name: Install GCC + - name: Install build tools run: | sudo apt-get update - sudo apt-get install -y gcc + sudo apt-get install -y gcc make - - 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 + - name: Run project verification + run: make check diff --git a/Makefile b/Makefile index 87fb4dd..36f443e 100644 --- a/Makefile +++ b/Makefile @@ -2,19 +2,38 @@ CC = gcc CFLAGS = -Wall -Wextra -g -O0 VERIFY_CFLAGS = -Wall -Wextra -Werror SRC_DIR = src +TEST_DIR = tests PROGRAMS = vuln_buffer_overflow safe_input_demo stack_layout_demo overflow_behavior_demo control_flow_simulation +TEST_PROGRAM = demo_runtime_checks +TEST_SOURCES = $(TEST_DIR)/$(TEST_PROGRAM).c $(addprefix $(SRC_DIR)/,$(addsuffix .c,$(PROGRAMS))) -.PHONY: all verify clean +ifeq ($(OS),Windows_NT) +RUN_TEST = .\$(TEST_PROGRAM).exe +CLEAN_CMD = powershell -NoProfile -Command "$(foreach file,$(PROGRAMS) $(addsuffix .exe,$(PROGRAMS)) $(TEST_PROGRAM) $(TEST_PROGRAM).exe,Remove-Item -ErrorAction SilentlyContinue '$(file)';) exit 0" +else +RUN_TEST = ./$(TEST_PROGRAM) +CLEAN_CMD = rm -f $(PROGRAMS) $(addsuffix .exe,$(PROGRAMS)) $(TEST_PROGRAM) $(TEST_PROGRAM).exe +endif + +.PHONY: all verify test check clean all: $(PROGRAMS) -$(PROGRAMS): %: $(SRC_DIR)/%.c +$(PROGRAMS): %: $(SRC_DIR)/%.c $(SRC_DIR)/demo_programs.h $(CC) $(CFLAGS) -o $@ $< -verify: $(addprefix verify-,$(PROGRAMS)) +verify: $(addprefix verify-,$(PROGRAMS)) verify-tests -verify-%: $(SRC_DIR)/%.c +verify-%: $(SRC_DIR)/%.c $(SRC_DIR)/demo_programs.h $(CC) $(VERIFY_CFLAGS) -o $* $< +verify-tests: $(TEST_SOURCES) $(SRC_DIR)/demo_programs.h + $(CC) $(VERIFY_CFLAGS) -DDEMO_NO_MAIN -I$(SRC_DIR) -o $(TEST_PROGRAM) $(TEST_SOURCES) + +test: verify-tests + $(RUN_TEST) + +check: verify test + clean: - -$(RM) $(PROGRAMS) $(addsuffix .exe,$(PROGRAMS)) + -$(CLEAN_CMD) diff --git a/README.md b/README.md index 9d65922..a4d4d9c 100644 --- a/README.md +++ b/README.md @@ -1,56 +1,41 @@ # Exploit Lab (C Memory Safety Demos) -A beginner-friendly C lab that demonstrates unsafe vs safe input handling, stack memory layout, overflow side effects, and conceptual control-flow changes. +A beginner-friendly C lab for observing unsafe input, safer input handling, stack layout, deterministic overflow side effects, and conceptual control-flow changes. -## 1. Title + Tagline +## Overview -**Project name:** Exploit Lab (C Memory Safety Demos) +This project is built for learning, not exploitation. Each demo is small enough to read quickly and focused enough to show one memory-safety idea at a time. -**Tagline:** Learn how common C memory-safety mistakes behave at runtime, and how safer patterns reduce risk. +Core demos: -## 2. ๐Ÿš€ Overview +- `vuln_buffer_overflow`: shows why `scanf("%s", ...)` is dangerous with fixed-size buffers. +- `safe_input_demo`: contrasts that behavior with bounded input using `fgets(...)`. +- `stack_layout_demo`: prints local and parameter addresses so you can inspect stack-frame layout. +- `overflow_behavior_demo`: safely simulates how an unbounded copy can spill past a buffer into adjacent bytes. +- `control_flow_simulation`: demonstrates how changing a function pointer changes executed code. -This project contains small, focused C programs that help you observe memory-safety concepts directly from terminal output. +## What Improved -It was built as an educational lab for beginners who want practical understanding of: +The project now behaves like a real teaching lab instead of a compile-only collection of demos: -- unbounded input (`scanf("%s", ...)`) vs bounded input (`fgets(...)`) -- stack variable and parameter address layout -- how out-of-bounds writes can lead to undefined behavior -- how control flow can change when a function pointer target changes +- The overflow demo is deterministic and no longer relies on real undefined behavior just to explain overwrite effects. +- Each demo exposes a reusable `run_*` entry point through [`src/demo_programs.h`](/d:/GitHub%20Repo/exploit-lab-cpp/src/demo_programs.h:1), which makes the demos testable without changing their CLI behavior. +- A runtime smoke-test harness in [`tests/demo_runtime_checks.c`](/d:/GitHub%20Repo/exploit-lab-cpp/tests/demo_runtime_checks.c:1) validates the expected output of every stable demo. +- The Makefile now supports `make check`, and CI uses the same project-owned verification path instead of duplicating compile commands by hand. -In real life, these concepts matter in secure software development, code review, debugging, and vulnerability prevention. - -## 3. ๐Ÿ”ฅ Features (Implemented) - -- Unsafe input demo (`vuln_buffer_overflow`): reads into a fixed 16-byte buffer with `scanf("%s", ...)` and shows why missing length limits is risky. -- Safe input demo (`safe_input_demo`): uses `fgets(...)` with buffer size and removes trailing newline for stable behavior. -- Stack layout demo (`stack_layout_demo`): prints addresses of locals and a function parameter to visualize stack-frame organization. -- Overflow behavior demo (`overflow_behavior_demo`): compares variable state before/after input and warns when input length exceeds buffer capacity. -- Control-flow simulation (`control_flow_simulation`): safely reassigns a function pointer to demonstrate how call targets change. -- Build automation: `Makefile` builds all active programs, includes strict verify target (`-Werror`), and clean target. -- CI compilation check: GitHub Actions compiles all active programs on push and pull request. -- Learning docs: walkthroughs, GDB guide, exercises, memory/protection notes, and screenshots in `docs/`. - -## 4. ๐Ÿ›  Tech Stack - -- Language: C -- Compiler: GCC -- Build tool: Make -- Debugging tool: GDB (optional, documented) -- CI: GitHub Actions (`ubuntu-latest`, GCC install + compile checks) -- External libraries/frameworks: none - -## 5. ๐Ÿ“‚ Project Structure +## Project Structure ```text exploit-lab-cpp/ |- src/ +| |- demo_programs.h | |- vuln_buffer_overflow.c | |- safe_input_demo.c | |- stack_layout_demo.c | |- overflow_behavior_demo.c | |- control_flow_simulation.c +|- tests/ +| |- demo_runtime_checks.c |- docs/ | |- demo.md | |- gdb-guide.md @@ -58,91 +43,58 @@ exploit-lab-cpp/ | |- memory-layout.md | |- protections.md | |- advanced-concepts.md -| |- images/ -| |- control-flow.png -| |- gdb-session.png -| |- overflow-output.png -| |- README.md |- archive/ -| |- main.c -| |- stack_behavior_demo.c |- .github/workflows/ -| |- build.yml |- Makefile |- project.md |- README.md ``` -Folder guide: - -- `src/` -> active demo programs you compile and run. -- `docs/` -> beginner documentation, exercises, and concept references. -- `docs/images/` -> captured screenshots from real demo/debug runs. -- `archive/` -> deprecated placeholder files kept for compatibility; not active lab logic. -- `.github/workflows/` -> CI workflow that validates compilation. - -## 6. โš™๏ธ Setup & Installation +## Build -### Prerequisites +Prerequisites: - GCC -- Make +- Make or `mingw32-make` - Optional: GDB -### Step-by-step - -1. Clone the repository. - -```bash -git clone https://github.com/urvalkheni/exploit-lab-cpp.git -``` - -What it does: downloads the project to your machine. - -2. Move into the project folder. +Linux/macOS: ```bash -cd exploit-lab-cpp +make ``` -What it does: sets your terminal working directory to this project. - -3. Build all demo binaries. +Windows (MinGW): -```bash -make +```powershell +mingw32-make ``` -What it does: compiles all programs in `src/` using debug-friendly flags (`-g -O0`). +## Verify -4. (Optional) Run strict compile verification. +Strict compile verification: ```bash make verify ``` -What it does: recompiles with `-Werror` so warnings fail the build. - -5. Run a program. - -Linux/macOS: +End-to-end compile plus runtime verification: ```bash -./safe_input_demo +make check ``` -Windows (MinGW style): +Windows (MinGW): ```powershell -.\safe_input_demo.exe +mingw32-make check ``` -## 7. ๐Ÿงช Usage Examples +## Run The Demos -Build and run all demos one by one: +Linux/macOS: ```bash -make ./vuln_buffer_overflow ./safe_input_demo ./stack_layout_demo @@ -150,51 +102,31 @@ make ./control_flow_simulation ``` -What each command does: - -- `./vuln_buffer_overflow` -> demonstrates unbounded input behavior. -- `./safe_input_demo` -> demonstrates bounded input using `fgets`. -- `./stack_layout_demo` -> prints stack addresses for observation. -- `./overflow_behavior_demo` -> shows warning and possible instability with oversized input. -- `./control_flow_simulation` -> shows function-pointer target change and resulting call path. - -Optional debugging example: - -```bash -gdb ./stack_layout_demo -``` - -Inside GDB: +Windows: -```gdb -break main -run -next -step -info locals -info registers +```powershell +.\vuln_buffer_overflow.exe +.\safe_input_demo.exe +.\stack_layout_demo.exe +.\overflow_behavior_demo.exe +.\control_flow_simulation.exe ``` -## 8. ๐Ÿ“Š Example Output - -`safe_input_demo` - -```text -[safe_input_demo] Safe input demo -Enter text: hello -You entered safely: hello -``` +## Example Output -`overflow_behavior_demo` (long input case) +`overflow_behavior_demo` ```text -[overflow_behavior_demo] Observe behavior with long input +[overflow_behavior_demo] Deterministic overflow impact demo Value of x before input: 10 -Enter input: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA -WARNING: Input length (30) exceeds buffer capacity (15). -Behavior may be unstable (undefined behavior). -Value of x after input: 1094795585 -Buffer content: AAAAAAAAAAAAAAAA... +Enter input: AAAAAAAAAAAAAAAAAAAAAA +Input length: 22 +WARNING: Input length (22) exceeds buffer capacity (15). +Simulated bytes written past buffer: 4 +Bytes that reached adjacent int: 4 of 4 +Adjacent int bytes after simulation: 41 41 41 41 +Value of x after simulated copy: 1094795585 +Buffer preview: AAAAAAAAAAAAAAAA ``` `control_flow_simulation` @@ -209,50 +141,12 @@ Calling through function pointer (after change): target_function(): alternate control flow path. ``` -## 9. ๐Ÿง  How It Works - -General flow: - -1. **Input:** user enters text in terminal. -2. **Processing:** each program handles input using either unsafe or safe logic, and may print memory-related information. -3. **Output:** terminal output shows observed behavior (stable output, warnings, address prints, or changed control-flow target). - -Program-level summary: - -- `vuln_buffer_overflow`: unbounded read into fixed-size stack buffer. -- `safe_input_demo`: bounded read with cleanup. -- `stack_layout_demo`: prints addresses to show layout patterns. -- `overflow_behavior_demo`: inspects overflow side effects and warns user. -- `control_flow_simulation`: demonstrates explicit function-pointer redirection safely. - -## 10. ๐Ÿ” Limitations / Notes - -- This is a conceptual training lab, not a full exploitation framework. -- Behavior is environment-dependent: compiler, OS, architecture, and protections affect runtime results. -- Overflow outcomes are undefined behavior, so outputs can vary or crash unexpectedly. -- `control_flow_simulation` uses manual pointer reassignment, not real memory corruption. -- Archive files in `archive/` are inactive placeholders. -- The repository currently validates compilation in CI but does not include automated runtime tests. - -## 11. ๐ŸŽฏ Learning Outcomes - -By completing this lab, you practice: - -- secure input handling in C -- identifying unsafe code patterns -- understanding stack-frame memory layout basics -- interpreting undefined behavior warnings and effects -- using GDB to inspect program state -- reading and maintaining build/CI configuration - -## 12. ๐Ÿš€ Future Improvements - -- Add small automated runtime checks for stable demos. -- Add a unified script to run all demos with sample inputs. -- Expand docs with platform-specific troubleshooting notes. +## Why This Matters -## 13. โš ๏ธ Disclaimer +- You can compare unsafe and safe input paths directly. +- You can study memory layout concepts without needing exploit code. +- You can reproduce the same learning signals in CI and on contributor machines. -This project is for educational and defensive learning purposes only. +## Disclaimer -Use these techniques only on systems you own or are explicitly authorized to test. +This repository is for educational and defensive learning only. diff --git a/docs/demo.md b/docs/demo.md index db815c3..583ac61 100644 --- a/docs/demo.md +++ b/docs/demo.md @@ -1,150 +1,109 @@ # Demo Guide -This is a quick, clean walkthrough for running the core memory lab demos. +This guide walks through the core lab demos and the new verification flow. -## 1) Setup +## 1. Build Everything -Compile all core programs: +Linux/macOS: ```bash make ``` -Windows (MinGW) note: -- Use `.\\program.exe` instead of `./program`. +Windows (MinGW): -## 2) Run Each Core Lab - -### Lab 1: Unsafe Input Behavior +```powershell +mingw32-make +``` -Run: +If you want the full quality gate, run: ```bash -./vuln_buffer_overflow +make check ``` -Example output: +Windows: -```text -[vuln_buffer_overflow] Unsafe input demo -Enter a word: AAAAAAAAAAAAAAAAAAAAA -You entered: AAAAAAAAAAAAAAAAAAAAA +```powershell +mingw32-make check ``` -What you will see: -- Input is accepted without explicit length limits. -- Long input can produce unstable behavior in unsafe programs. +## 2. Run Each Demo -### Lab 2: Safe Input Demo - -Run: +### Lab 1: Unsafe Input Behavior ```bash -./safe_input_demo +./vuln_buffer_overflow ``` -Example output: +What to look for: -```text -[safe_input_demo] Safe input demo -Enter text: hello -You entered safely: hello +- The program accepts a word without a width limit. +- Short input is fine. +- Long input is dangerous because the read itself is unbounded. + +### Lab 2: Safe Input Demo + +```bash +./safe_input_demo ``` -What you will see: -- `fgets(...)` reads with a size boundary. -- Behavior is safer and more predictable. +What to look for: -### Lab 3: Stack Layout Demo +- `fgets(...)` respects the buffer size. +- The output stays predictable with normal input. -Run: +### Lab 3: Stack Layout Demo ```bash ./stack_layout_demo ``` -Example output: +What to look for: -```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. +- `main_local`, `buffer`, `x`, and `demo_id` all print nearby addresses. +- The absolute addresses may change between runs. ### Lab 4: Overflow Behavior Demo -Run: - ```bash ./overflow_behavior_demo ``` -Example output: +Example long-input output: ```text -[overflow_behavior_demo] Observe behavior with long input +[overflow_behavior_demo] Deterministic overflow impact demo 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... +Enter input: AAAAAAAAAAAAAAAAAAAAAA +Input length: 22 +WARNING: Input length (22) exceeds buffer capacity (15). +Simulated bytes written past buffer: 4 +Bytes that reached adjacent int: 4 of 4 +Adjacent int bytes after simulation: 41 41 41 41 +Value of x after simulated copy: 1094795585 +Buffer preview: AAAAAAAAAAAAAAAA ``` -Clean beginner-friendly version: +What to look for: -```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. +- The input is read safely first. +- The demo then simulates how an unbounded copy would move across adjacent bytes. +- You get a repeatable view of what reaches the neighboring `int` without depending on real 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. +What to look for: -Visual proof: -- `docs/images/overflow-output.png` -- `docs/images/control-flow.png` +- The function pointer calls `safe_function()` first. +- After reassignment, the same pointer calls `target_function()`. +- The program demonstrates control-flow redirection conceptually, not through real corruption. -### Lab 6: Debugging with GDB (Optional but Recommended) - -Start with `stack_layout_demo`: +### Lab 6: GDB Walkthrough ```bash gdb ./stack_layout_demo @@ -161,31 +120,10 @@ 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 +## 3. What This Teaches -![Control flow simulation](images/control-flow.png) +- Why unbounded input is risky +- Why bounded input is safer +- How stack-frame data can be inspected +- How overflow side effects can be explained safely and deterministically +- How control-flow changes can be demonstrated without exploit code diff --git a/docs/lab-exercises.md b/docs/lab-exercises.md index b0a735d..4d3af44 100644 --- a/docs/lab-exercises.md +++ b/docs/lab-exercises.md @@ -1,15 +1,9 @@ -# Lab Exercises (Beginner-Friendly) +# Lab Exercises -These exercises help you practice memory-safety concepts step by step. -Each lab includes: -- what to run -- what to observe -- what it means +These exercises are designed to be repeatable on contributor machines and in CI. ## Lab 1: Unsafe Input Behavior -### What to run - Build: ```bash @@ -18,59 +12,40 @@ make vuln_buffer_overflow Run: -Linux/macOS: - ```bash ./vuln_buffer_overflow ``` -Windows (MinGW): +Observe: -```powershell -.\vuln_buffer_overflow.exe -``` +- Normal input works as expected. +- The code path is still unsafe because `scanf("%s", ...)` does not limit length. -Try entering a long input string. +Meaning: -### 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). +- Even simple code can become dangerous when input size is not bounded. ## Lab 2: Safe vs Unsafe Comparison -### What to run - -Build both: +Build: ```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) +Run both programs with short input such as `hello`. -### What to observe +Observe: -- `safe_input_demo` remains stable because input is bounded -- `vuln_buffer_overflow` may behave unpredictably with long input +- Both programs handle short input. +- Only `safe_input_demo` enforces a read boundary. -### What it means +Meaning: -Bounded input functions like `fgets(...)` reduce overflow risk. -Unbounded input patterns are dangerous in C. +- Safe input handling is mostly about preventing the dangerous read in the first place. ## Lab 3: Stack Memory Layout -### What to run - Build: ```bash @@ -79,32 +54,21 @@ make stack_layout_demo Run: -Linux/macOS: - ```bash ./stack_layout_demo ``` -Windows (MinGW): - -```powershell -.\stack_layout_demo.exe -``` - -### What to observe +Observe: -- Printed addresses for local variables and function parameters -- Addresses are often close together -- Re-running may change absolute addresses +- Printed addresses for locals and a parameter +- Similar relative ordering across runs +- Different absolute addresses on some systems -### What it means +Meaning: -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). +- Stack memory is structured, but exact addresses are environment-dependent. -## Lab 4: Overflow Behavior - -### What to run +## Lab 4: Deterministic Overflow Impact Build: @@ -112,35 +76,25 @@ Build: make overflow_behavior_demo ``` -Run and enter a long string: - -Linux/macOS: +Run with a long string: ```bash ./overflow_behavior_demo ``` -Windows (MinGW): +Observe: -```powershell -.\overflow_behavior_demo.exe -``` +- Input length and buffer capacity +- How many bytes spill past the buffer +- How many bytes reach the adjacent `int` +- The hex view of the neighboring bytes after the simulated copy -### What to observe +Meaning: -- 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. +- You can study overwrite direction and side effects without relying on a real overflow to corrupt process memory. ## Lab 5: Control Flow Simulation -### What to run - Build: ```bash @@ -149,58 +103,37 @@ make control_flow_simulation Run: -Linux/macOS: - ```bash ./control_flow_simulation ``` -Windows (MinGW): - -```powershell -.\control_flow_simulation.exe -``` - -### What to observe +Observe: -- Function pointer calls `safe_function()` first -- After reassignment, the same pointer calls `target_function()` -- Printed function addresses and pointer variable address +- The same function pointer calls different functions before and after reassignment. -### What it means +Meaning: -Control flow depends on which code address is used. -This lab safely demonstrates redirection conceptually through normal reassignment, not memory corruption. +- Control flow follows the currently stored code address. -## Lab 6: Debugging with GDB +## Lab 6: Runtime Verification -### What to run - -Use GDB on any demo program (example: `stack_layout_demo`): +Run: ```bash -gdb ./stack_layout_demo +make check ``` -Useful commands inside GDB: +Windows (MinGW): -```gdb -break main -run -next -step -info locals -print x -info registers +```powershell +mingw32-make check ``` -### What to observe +Observe: -- Program state line by line -- Current variable values -- Register changes during execution +- Every stable demo is compiled with strict warnings enabled. +- The smoke-test harness validates key output markers from each demo. -### What it means +Meaning: -GDB helps you see how C code maps to runtime behavior. -This is essential for understanding memory layout, variable lifetimes, and debugging unsafe behavior. +- The lab is now regression-tested, not just buildable. diff --git a/project.md b/project.md index cd6ca37..d61b650 100644 --- a/project.md +++ b/project.md @@ -1,223 +1,30 @@ -# ๐Ÿ’ฃ Exploit Lab (C/C++) - -A hands-on, low-level security lab designed to demonstrate classic memory corruption vulnerabilities and exploitation techniques such as buffer overflows, stack smashing, and basic shellcode execution. - -This project focuses on understanding how vulnerabilities arise in unsafe programs and how attackers can exploit them at the memory level. - ---- - -## ๐Ÿ“Œ Overview - -Modern systems implement several protections (ASLR, NX, stack canaries), but many real-world vulnerabilities still stem from unsafe memory handling. - -This lab recreates vulnerable environments to: - -* Understand how memory is structured (stack, heap) -* Learn how overflows overwrite control flow -* Observe exploitation using debugging tools - ---- - -## ๐Ÿš€ Features - -* ๐Ÿง  Stack-based buffer overflow demonstrations -* ๐Ÿ’ฅ Return address overwrite (stack smashing) -* ๐Ÿš Basic shellcode execution (controlled environment) -* ๐Ÿ” Step-by-step debugging using GDB -* ๐Ÿ“Š Memory visualization (stack layout, registers) - ---- - -## ๐Ÿ›  Tech Stack - -* **Language:** C / C++ -* **Compiler:** GCC -* **Debugger:** GDB -* **OS:** Linux (recommended: Kali / Ubuntu) - ---- - -## ๐Ÿ“‚ Project Structure - -exploit-lab-cpp/ -โ”‚โ”€โ”€ src/ -โ”‚ โ”œโ”€โ”€ vuln_buffer_overflow.c -โ”‚ โ”œโ”€โ”€ stack_smash.c -โ”‚ โ”œโ”€โ”€ shellcode_demo.c -โ”‚ -โ”‚โ”€โ”€ exploits/ -โ”‚ โ”œโ”€โ”€ exploit_buffer.py -โ”‚ โ”œโ”€โ”€ exploit_stack.py -โ”‚ -โ”‚โ”€โ”€ docs/ -โ”‚ โ”œโ”€โ”€ memory-layout.md -โ”‚ โ”œโ”€โ”€ gdb-guide.md -โ”‚ -โ”‚โ”€โ”€ screenshots/ -โ”‚ โ”œโ”€โ”€ gdb-analysis.png -โ”‚ โ”œโ”€โ”€ exploit-success.png -โ”‚ -โ”‚โ”€โ”€ README.md - ---- - -## ๐Ÿ” Core Concepts Covered - -### 1. Buffer Overflow - -Occurs when input exceeds allocated buffer size. - -```c -char buffer[16]; -gets(buffer); // unsafe -``` - -๐Ÿ’ฅ Result: - -* Overwrites adjacent memory -* Can modify return address - ---- - -### 2. Stack Smashing - -Manipulating stack memory to control program execution. - -* Overwrite saved return pointer (EIP/RIP) -* Redirect execution flow - ---- - -### 3. Shellcode Injection - -Injecting and executing malicious instructions in memory. - -Example: - -* Spawn a shell -* Execute arbitrary commands - ---- - -## ๐Ÿงช Lab Exercises - -### ๐Ÿ”น Lab 1: Basic Buffer Overflow - -* Identify vulnerable input -* Overflow buffer -* Crash program - ---- - -### ๐Ÿ”น Lab 2: Control Instruction Pointer - -* Use GDB to locate offset -* Overwrite return address -* Redirect execution - ---- - -### ๐Ÿ”น Lab 3: Shellcode Execution - -* Inject shellcode into memory -* Execute payload -* Observe behavior - ---- - -## ๐Ÿงช Compilation & Execution - -โš ๏ธ Disable protections for learning purposes: - -```bash -gcc vuln_buffer_overflow.c -o vuln -fno-stack-protector -z execstack -no-pie -``` - -Run: - -```bash -./vuln -``` - ---- - -## ๐Ÿž Debugging with GDB - -Start debugging: - -```bash -gdb ./vuln -``` - -Useful commands: - -```bash -run -info registers -x/20x $rsp -disassemble main -``` - ---- - -## ๐Ÿ“Š Example Workflow - -1. Run program with long input -2. Observe crash -3. Open in GDB -4. Identify offset -5. Overwrite return address -6. Redirect execution - ---- - -## ๐Ÿ” Security Mitigations (Important) - -This lab disables protections intentionally. In real systems: - -* โœ… Stack Canaries prevent overflow detection bypass -* โœ… ASLR randomizes memory addresses -* โœ… NX bit prevents execution on stack -* โœ… Safe functions (`fgets`, `gets_s`) replace unsafe ones - ---- - -## โš ๏ธ Disclaimer - -This project is strictly for **educational purposes only**. - -Do NOT use these techniques on systems you do not own or have permission to test. - ---- - -## ๐ŸŽฏ Learning Outcomes - -After completing this lab, you will: - -* Understand stack memory structure -* Identify unsafe code patterns -* Perform basic exploitation -* Use debugging tools effectively -* Understand real-world mitigation techniques - ---- - -## ๐Ÿš€ Future Improvements - -* Heap exploitation examples -* Format string vulnerabilities -* Return-Oriented Programming (ROP) -* Automated exploit scripts - ---- - -## ๐Ÿค Contributing - -Contributions are welcome! -Feel free to open issues or submit pull requests. - ---- - -## โญ Acknowledgment - -Inspired by real-world exploitation techniques and classic vulnerability research. +# Project Overview + +Exploit Lab is a small C teaching repo focused on memory-safety fundamentals. + +## Current Direction + +The project is intentionally educational and defensive: + +- compare unsafe and safe input handling +- inspect stack layout and nearby addresses +- explain overflow side effects without depending on real undefined behavior +- illustrate conceptual control-flow changes safely + +## Quality Bar + +The repo now has three layers of verification: + +- `make` builds all demos +- `make verify` recompiles with `-Werror` +- `make check` runs compile and runtime smoke tests + +## Key Implementation Notes + +- Shared demo entry points live in [`src/demo_programs.h`](/d:/GitHub%20Repo/exploit-lab-cpp/src/demo_programs.h:1). +- Runtime checks live in [`tests/demo_runtime_checks.c`](/d:/GitHub%20Repo/exploit-lab-cpp/tests/demo_runtime_checks.c:1). +- [`src/overflow_behavior_demo.c`](/d:/GitHub%20Repo/exploit-lab-cpp/src/overflow_behavior_demo.c:1) now uses a deterministic simulation so contributors see the same learning signal across environments. + +## Maintenance Goal + +Keep the repo beginner-friendly, reproducible, and safe to run while still showing why unsafe C patterns matter. diff --git a/src/control_flow_simulation.c b/src/control_flow_simulation.c index d142b84..8d0a352 100644 --- a/src/control_flow_simulation.c +++ b/src/control_flow_simulation.c @@ -1,11 +1,13 @@ #include +#include "demo_programs.h" + /* * safe_function: * Default control-flow target in this demo. */ -static void safe_function(void) { - printf("safe_function(): normal control flow path.\n"); +static void safe_function(FILE *output) { + fprintf(output, "safe_function(): normal control flow path.\n"); } /* @@ -13,25 +15,25 @@ static void safe_function(void) { * 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"); +static void target_function(FILE *output) { + fprintf(output, "target_function(): alternate control flow path.\n"); } -int main(void) { +int run_control_flow_simulation(FILE *output) { /* * 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; + void (*func_ptr)(FILE *output_stream) = 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); + fprintf(output, "[control_flow_simulation] Conceptual control-flow demo\n"); + fprintf(output, "Address of safe_function: %p\n", (void *)safe_function); + fprintf(output, "Address of target_function: %p\n", (void *)target_function); + fprintf(output, "Address of func_ptr var: %p\n", (void *)&func_ptr); - printf("\nCalling through function pointer (before change):\n"); - func_ptr(); + fprintf(output, "\nCalling through function pointer (before change):\n"); + func_ptr(output); /* * Conceptual simulation: @@ -42,11 +44,18 @@ int main(void) { * 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"); + fprintf(output, + "\nSimulating conceptual pointer corruption by manual reassignment...\n"); func_ptr = target_function; - printf("Calling through function pointer (after change):\n"); - func_ptr(); + fprintf(output, "Calling through function pointer (after change):\n"); + func_ptr(output); return 0; } + +#ifndef DEMO_NO_MAIN +int main(void) { + return run_control_flow_simulation(stdout); +} +#endif diff --git a/src/demo_programs.h b/src/demo_programs.h new file mode 100644 index 0000000..13be4b4 --- /dev/null +++ b/src/demo_programs.h @@ -0,0 +1,12 @@ +#ifndef DEMO_PROGRAMS_H +#define DEMO_PROGRAMS_H + +#include + +int run_vuln_buffer_overflow(FILE *input, FILE *output); +int run_safe_input_demo(FILE *input, FILE *output); +int run_stack_layout_demo(FILE *output); +int run_overflow_behavior_demo(FILE *input, FILE *output); +int run_control_flow_simulation(FILE *output); + +#endif diff --git a/src/overflow_behavior_demo.c b/src/overflow_behavior_demo.c index e3816dc..808ea8c 100644 --- a/src/overflow_behavior_demo.c +++ b/src/overflow_behavior_demo.c @@ -1,42 +1,137 @@ +#include #include #include +#include "demo_programs.h" + +enum { + OVERFLOW_DEMO_BUFFER_SIZE = 16, + OVERFLOW_DEMO_MAX_INPUT = 96 +}; + +struct overflow_demo_layout { + char buffer[OVERFLOW_DEMO_BUFFER_SIZE]; + unsigned char x_bytes[sizeof(int)]; +}; + +static size_t trim_newline(char *text) { + size_t len = strcspn(text, "\n"); + + text[len] = '\0'; + return len; +} + +static void print_buffer_preview(FILE *output, const char *buffer, size_t buffer_size) { + size_t index; + + fprintf(output, "Buffer preview: "); + for (index = 0; index < buffer_size; ++index) { + unsigned char byte = (unsigned char)buffer[index]; + + if (byte == '\0') { + break; + } + + fputc(isprint(byte) ? (int)byte : '.', output); + } + fputc('\n', output); +} + +static void print_hex_bytes(FILE *output, const unsigned char *bytes, size_t byte_count) { + size_t index; + + for (index = 0; index < byte_count; ++index) { + fprintf(output, "%02X%s", bytes[index], index + 1 == byte_count ? "" : " "); + } + fputc('\n', output); +} + +static size_t simulate_unbounded_copy(struct overflow_demo_layout *layout, + const char *input) { + unsigned char *raw_bytes = (unsigned char *)layout; + size_t input_len = strlen(input); + size_t index = 0; + + for (index = 0; index < input_len && index < sizeof(*layout); ++index) { + raw_bytes[index] = (unsigned char)input[index]; + } + + if (index < sizeof(*layout)) { + raw_bytes[index++] = '\0'; + } + + return index; +} + /* * 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. + * This version demonstrates overflow impact deterministically. + * It reads the input safely, then simulates how an unbounded copy + * would walk across adjacent bytes in a small stack-like layout. */ -int main(void) { - char buffer[16]; +int run_overflow_behavior_demo(FILE *input, FILE *output) { + char input_buffer[OVERFLOW_DEMO_MAX_INPUT]; + struct overflow_demo_layout layout; int x = 10; size_t input_len = 0; + size_t bytes_written = 0; + size_t bytes_past_buffer = 0; + size_t bytes_into_x = 0; + + memset(&layout, 0, sizeof(layout)); + memcpy(layout.x_bytes, &x, sizeof(x)); - 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"); + fprintf(output, "[overflow_behavior_demo] Deterministic overflow impact demo\n"); + fprintf(output, "Value of x before input: %d\n", x); + fprintf(output, "Enter input: "); + + if (fgets(input_buffer, sizeof(input_buffer), input) == NULL) { + fprintf(output, "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"); + input_len = trim_newline(input_buffer); + bytes_written = simulate_unbounded_copy(&layout, input_buffer); + + if (bytes_written > sizeof(layout.buffer)) { + bytes_past_buffer = bytes_written - sizeof(layout.buffer); + if (bytes_past_buffer > sizeof(layout.x_bytes)) { + bytes_past_buffer = sizeof(layout.x_bytes); + } } - printf("Value of x after input: %d\n", x); - printf("Buffer content: %s\n", buffer); + if (bytes_past_buffer > 0) { + bytes_into_x = bytes_past_buffer; + } + + memcpy(&x, layout.x_bytes, sizeof(x)); + + fprintf(output, "Input length: %lu\n", (unsigned long)input_len); + if (input_len >= sizeof(layout.buffer)) { + fprintf(output, + "WARNING: Input length (%lu) exceeds buffer capacity (%lu).\n", + (unsigned long)input_len, + (unsigned long)(sizeof(layout.buffer) - 1)); + fprintf(output, "Simulated bytes written past buffer: %lu\n", + (unsigned long)bytes_past_buffer); + fprintf(output, "Bytes that reached adjacent int: %lu of %lu\n", + (unsigned long)bytes_into_x, + (unsigned long)sizeof(layout.x_bytes)); + fprintf(output, "Adjacent int bytes after simulation: "); + print_hex_bytes(output, layout.x_bytes, sizeof(layout.x_bytes)); + } else { + fprintf(output, "Input fits inside the buffer in this run.\n"); + } + + fprintf(output, "Value of x after simulated copy: %d\n", x); + print_buffer_preview(output, layout.buffer, sizeof(layout.buffer)); return 0; } + +#ifndef DEMO_NO_MAIN +int main(void) { + return run_overflow_behavior_demo(stdin, stdout); +} +#endif diff --git a/src/safe_input_demo.c b/src/safe_input_demo.c index 0c8de82..197d330 100644 --- a/src/safe_input_demo.c +++ b/src/safe_input_demo.c @@ -1,6 +1,8 @@ #include #include +#include "demo_programs.h" + /* * Safe input demo. * @@ -8,20 +10,26 @@ * sizeof(buffer) - 1 characters and prevents buffer overflow * from this input operation. */ -int main(void) { +int run_safe_input_demo(FILE *input, FILE *output) { char buffer[16]; - printf("[safe_input_demo] Safe input demo\n"); - printf("Enter text: "); + fprintf(output, "[safe_input_demo] Safe input demo\n"); + fprintf(output, "Enter text: "); - if (fgets(buffer, sizeof(buffer), stdin) == NULL) { - printf("Input error.\n"); + if (fgets(buffer, sizeof(buffer), input) == NULL) { + fprintf(output, "Input error.\n"); return 1; } /* Remove trailing newline for cleaner output. */ buffer[strcspn(buffer, "\n")] = '\0'; - printf("You entered safely: %s\n", buffer); + fprintf(output, "You entered safely: %s\n", buffer); return 0; } + +#ifndef DEMO_NO_MAIN +int main(void) { + return run_safe_input_demo(stdin, stdout); +} +#endif diff --git a/src/stack_layout_demo.c b/src/stack_layout_demo.c index e6b2ffe..015c431 100644 --- a/src/stack_layout_demo.c +++ b/src/stack_layout_demo.c @@ -1,12 +1,14 @@ #include +#include "demo_programs.h" + /* * 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) { +static void print_stack_layout(FILE *output, int demo_id) { char buffer[16]; int x = 10; @@ -15,17 +17,23 @@ static void print_stack_layout(int demo_id) { * 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); + fprintf(output, "Address of buffer: %p\n", (void *)buffer); + fprintf(output, "Address of x: %p\n", (void *)&x); + fprintf(output, "Address of parameter demo_id: %p\n", (void *)&demo_id); } -int main(void) { +int run_stack_layout_demo(FILE *output) { 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); + fprintf(output, "[stack_layout_demo] Stack address observation\n"); + fprintf(output, "Address of main_local: %p\n", (void *)&main_local); + print_stack_layout(output, 42); return 0; } + +#ifndef DEMO_NO_MAIN +int main(void) { + return run_stack_layout_demo(stdout); +} +#endif diff --git a/src/vuln_buffer_overflow.c b/src/vuln_buffer_overflow.c index a1044c0..f31830d 100644 --- a/src/vuln_buffer_overflow.c +++ b/src/vuln_buffer_overflow.c @@ -1,5 +1,7 @@ #include +#include "demo_programs.h" + /* * Unsafe buffer input demo (educational only). * @@ -8,17 +10,23 @@ * If input is longer than the buffer, memory past the buffer * may be overwritten. */ -int main(void) { +int run_vuln_buffer_overflow(FILE *input, FILE *output) { char buffer[16]; - printf("[vuln_buffer_overflow] Unsafe input demo\n"); - printf("Enter a word: "); + fprintf(output, "[vuln_buffer_overflow] Unsafe input demo\n"); + fprintf(output, "Enter a word: "); - if (scanf("%s", buffer) != 1) { - printf("Input error.\n"); + if (fscanf(input, "%s", buffer) != 1) { + fprintf(output, "Input error.\n"); return 1; } - printf("You entered: %s\n", buffer); + fprintf(output, "You entered: %s\n", buffer); return 0; } + +#ifndef DEMO_NO_MAIN +int main(void) { + return run_vuln_buffer_overflow(stdin, stdout); +} +#endif diff --git a/tests/demo_runtime_checks.c b/tests/demo_runtime_checks.c new file mode 100644 index 0000000..d452f7b --- /dev/null +++ b/tests/demo_runtime_checks.c @@ -0,0 +1,294 @@ +#include +#include +#include +#include + +#include "demo_programs.h" + +static int failure_count = 0; + +struct temp_file { + FILE *stream; + char path[128]; +}; + +static int open_temp_file(struct temp_file *temp_file) { + static unsigned int counter = 0; + + temp_file->stream = NULL; + temp_file->path[0] = '\0'; + + if (snprintf(temp_file->path, + sizeof(temp_file->path), + "tests/runtime_check_%lu_%lu_%u.tmp", + (unsigned long)time(NULL), + (unsigned long)clock(), + counter++) < 0) { + return 0; + } + + temp_file->stream = fopen(temp_file->path, "w+b"); + return temp_file->stream != NULL; +} + +static void close_temp_file(struct temp_file *temp_file) { + if (temp_file->stream != NULL) { + fclose(temp_file->stream); + temp_file->stream = NULL; + } + + if (temp_file->path[0] != '\0') { + remove(temp_file->path); + temp_file->path[0] = '\0'; + } +} + +static char *read_stream(FILE *stream) { + long length = 0; + char *buffer = NULL; + + if (fflush(stream) != 0) { + return NULL; + } + + if (fseek(stream, 0L, SEEK_END) != 0) { + return NULL; + } + + length = ftell(stream); + if (length < 0) { + return NULL; + } + + if (fseek(stream, 0L, SEEK_SET) != 0) { + return NULL; + } + + buffer = (char *)malloc((size_t)length + 1U); + if (buffer == NULL) { + return NULL; + } + + if (length > 0 && fread(buffer, 1U, (size_t)length, stream) != (size_t)length) { + free(buffer); + return NULL; + } + + buffer[length] = '\0'; + return buffer; +} + +static int open_input_stream(struct temp_file *temp_file, const char *text) { + if (!open_temp_file(temp_file)) { + return 0; + } + + if (fputs(text, temp_file->stream) == EOF) { + close_temp_file(temp_file); + return 0; + } + + if (ferror(temp_file->stream)) { + close_temp_file(temp_file); + return 0; + } + + rewind(temp_file->stream); + return 1; +} + +static void expect_contains(const char *test_name, + const char *output, + const char *needle) { + if (strstr(output, needle) == NULL) { + fprintf(stderr, + "[FAIL] %s missing expected text: %s\n", + test_name, + needle); + failure_count++; + } +} + +static void expect_success(const char *test_name, int result) { + if (result != 0) { + fprintf(stderr, "[FAIL] %s returned %d\n", test_name, result); + failure_count++; + } +} + +static void test_safe_input_demo(void) { + const char *test_name = "safe_input_demo"; + struct temp_file input = {0}; + struct temp_file output = {0}; + char *text = NULL; + int result = 0; + + if (!open_input_stream(&input, "hello\n") || !open_temp_file(&output)) { + fprintf(stderr, "[FAIL] %s could not create temp files\n", test_name); + failure_count++; + goto cleanup; + } + + result = run_safe_input_demo(input.stream, output.stream); + text = read_stream(output.stream); + if (text == NULL) { + fprintf(stderr, "[FAIL] %s could not read captured output\n", test_name); + failure_count++; + goto cleanup; + } + + expect_success(test_name, result); + expect_contains(test_name, text, "[safe_input_demo] Safe input demo"); + expect_contains(test_name, text, "You entered safely: hello"); + +cleanup: + free(text); + close_temp_file(&input); + close_temp_file(&output); +} + +static void test_vuln_buffer_overflow(void) { + const char *test_name = "vuln_buffer_overflow"; + struct temp_file input = {0}; + struct temp_file output = {0}; + char *text = NULL; + int result = 0; + + if (!open_input_stream(&input, "hello\n") || !open_temp_file(&output)) { + fprintf(stderr, "[FAIL] %s could not create temp files\n", test_name); + failure_count++; + goto cleanup; + } + + result = run_vuln_buffer_overflow(input.stream, output.stream); + text = read_stream(output.stream); + if (text == NULL) { + fprintf(stderr, "[FAIL] %s could not read captured output\n", test_name); + failure_count++; + goto cleanup; + } + + expect_success(test_name, result); + expect_contains(test_name, text, "[vuln_buffer_overflow] Unsafe input demo"); + expect_contains(test_name, text, "You entered: hello"); + +cleanup: + free(text); + close_temp_file(&input); + close_temp_file(&output); +} + +static void test_stack_layout_demo(void) { + const char *test_name = "stack_layout_demo"; + struct temp_file output = {0}; + char *text = NULL; + int result = 0; + + if (!open_temp_file(&output)) { + fprintf(stderr, "[FAIL] %s could not create temp file\n", test_name); + failure_count++; + return; + } + + result = run_stack_layout_demo(output.stream); + text = read_stream(output.stream); + if (text == NULL) { + fprintf(stderr, "[FAIL] %s could not read captured output\n", test_name); + failure_count++; + close_temp_file(&output); + return; + } + + expect_success(test_name, result); + expect_contains(test_name, text, "[stack_layout_demo] Stack address observation"); + expect_contains(test_name, text, "Address of main_local:"); + expect_contains(test_name, text, "Address of buffer:"); + expect_contains(test_name, text, "Address of x:"); + expect_contains(test_name, text, "Address of parameter demo_id:"); + + free(text); + close_temp_file(&output); +} + +static void test_overflow_behavior_demo(void) { + const char *test_name = "overflow_behavior_demo"; + struct temp_file input = {0}; + struct temp_file output = {0}; + char *text = NULL; + int result = 0; + + if (!open_input_stream(&input, "AAAAAAAAAAAAAAAAAAAAAA\n") || + !open_temp_file(&output)) { + fprintf(stderr, "[FAIL] %s could not create temp files\n", test_name); + failure_count++; + goto cleanup; + } + + result = run_overflow_behavior_demo(input.stream, output.stream); + text = read_stream(output.stream); + if (text == NULL) { + fprintf(stderr, "[FAIL] %s could not read captured output\n", test_name); + failure_count++; + goto cleanup; + } + + expect_success(test_name, result); + expect_contains(test_name, text, + "[overflow_behavior_demo] Deterministic overflow impact demo"); + expect_contains(test_name, text, + "WARNING: Input length (22) exceeds buffer capacity (15)."); + expect_contains(test_name, text, "Bytes that reached adjacent int: 4 of 4"); + expect_contains(test_name, text, "Adjacent int bytes after simulation: 41 41 41 41"); + +cleanup: + free(text); + close_temp_file(&input); + close_temp_file(&output); +} + +static void test_control_flow_simulation(void) { + const char *test_name = "control_flow_simulation"; + struct temp_file output = {0}; + char *text = NULL; + int result = 0; + + if (!open_temp_file(&output)) { + fprintf(stderr, "[FAIL] %s could not create temp file\n", test_name); + failure_count++; + return; + } + + result = run_control_flow_simulation(output.stream); + text = read_stream(output.stream); + if (text == NULL) { + fprintf(stderr, "[FAIL] %s could not read captured output\n", test_name); + failure_count++; + close_temp_file(&output); + return; + } + + expect_success(test_name, result); + expect_contains(test_name, text, + "[control_flow_simulation] Conceptual control-flow demo"); + expect_contains(test_name, text, "safe_function(): normal control flow path."); + expect_contains(test_name, text, "target_function(): alternate control flow path."); + + free(text); + close_temp_file(&output); +} + +int main(void) { + test_safe_input_demo(); + test_vuln_buffer_overflow(); + test_stack_layout_demo(); + test_overflow_behavior_demo(); + test_control_flow_simulation(); + + if (failure_count != 0) { + fprintf(stderr, "\n%d runtime check(s) failed.\n", failure_count); + return 1; + } + + printf("All runtime checks passed.\n"); + return 0; +} diff --git a/tests/runtime_check_1776156560_0.tmp b/tests/runtime_check_1776156560_0.tmp new file mode 100644 index 0000000..ce01362 --- /dev/null +++ b/tests/runtime_check_1776156560_0.tmp @@ -0,0 +1 @@ +hello diff --git a/tests/runtime_check_1776156560_1.tmp b/tests/runtime_check_1776156560_1.tmp new file mode 100644 index 0000000..949ec06 --- /dev/null +++ b/tests/runtime_check_1776156560_1.tmp @@ -0,0 +1,2 @@ +[safe_input_demo] Safe input demo +Enter text: You entered safely: hello diff --git a/tests/runtime_check_1776156560_2.tmp b/tests/runtime_check_1776156560_2.tmp new file mode 100644 index 0000000..ce01362 --- /dev/null +++ b/tests/runtime_check_1776156560_2.tmp @@ -0,0 +1 @@ +hello diff --git a/tests/runtime_check_1776156560_3.tmp b/tests/runtime_check_1776156560_3.tmp new file mode 100644 index 0000000..c30b5b8 --- /dev/null +++ b/tests/runtime_check_1776156560_3.tmp @@ -0,0 +1,2 @@ +[vuln_buffer_overflow] Unsafe input demo +Enter a word: You entered: hello diff --git a/tests/runtime_check_1776156560_4.tmp b/tests/runtime_check_1776156560_4.tmp new file mode 100644 index 0000000..7ac5ad7 --- /dev/null +++ b/tests/runtime_check_1776156560_4.tmp @@ -0,0 +1,5 @@ +[stack_layout_demo] Stack address observation +Address of main_local: 0061FE4C +Address of buffer: 0061FE10 +Address of x: 0061FE0C +Address of parameter demo_id: 0061FE34 diff --git a/tests/runtime_check_1776156560_5.tmp b/tests/runtime_check_1776156560_5.tmp new file mode 100644 index 0000000..b20553a --- /dev/null +++ b/tests/runtime_check_1776156560_5.tmp @@ -0,0 +1 @@ +AAAAAAAAAAAAAAAAAAAAAA diff --git a/tests/runtime_check_1776156560_6.tmp b/tests/runtime_check_1776156560_6.tmp new file mode 100644 index 0000000..963a84d --- /dev/null +++ b/tests/runtime_check_1776156560_6.tmp @@ -0,0 +1,9 @@ +[overflow_behavior_demo] Deterministic overflow impact demo +Value of x before input: 10 +Enter input: Input length: 22 +WARNING: Input length (22) exceeds buffer capacity (15). +Simulated bytes written past buffer: 4 +Bytes that reached adjacent int: 4 of 4 +Adjacent int bytes after simulation: 41 41 41 41 +Value of x after simulated copy: 1094795585 +Buffer preview: AAAAAAAAAAAAAAAA diff --git a/tests/runtime_check_1776156560_7.tmp b/tests/runtime_check_1776156560_7.tmp new file mode 100644 index 0000000..9f3e342 --- /dev/null +++ b/tests/runtime_check_1776156560_7.tmp @@ -0,0 +1,11 @@ +[control_flow_simulation] Conceptual control-flow demo +Address of safe_function: 004025CC +Address of target_function: 004025F8 +Address of func_ptr var: 0061FE4C + +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. diff --git a/tests/runtime_check_1776156908_1_0.tmp b/tests/runtime_check_1776156908_1_0.tmp new file mode 100644 index 0000000..ce01362 --- /dev/null +++ b/tests/runtime_check_1776156908_1_0.tmp @@ -0,0 +1 @@ +hello diff --git a/tests/runtime_check_1776156908_1_1.tmp b/tests/runtime_check_1776156908_1_1.tmp new file mode 100644 index 0000000..949ec06 --- /dev/null +++ b/tests/runtime_check_1776156908_1_1.tmp @@ -0,0 +1,2 @@ +[safe_input_demo] Safe input demo +Enter text: You entered safely: hello diff --git a/tests/runtime_check_1776156908_1_2.tmp b/tests/runtime_check_1776156908_1_2.tmp new file mode 100644 index 0000000..ce01362 --- /dev/null +++ b/tests/runtime_check_1776156908_1_2.tmp @@ -0,0 +1 @@ +hello diff --git a/tests/runtime_check_1776156908_1_3.tmp b/tests/runtime_check_1776156908_1_3.tmp new file mode 100644 index 0000000..c30b5b8 --- /dev/null +++ b/tests/runtime_check_1776156908_1_3.tmp @@ -0,0 +1,2 @@ +[vuln_buffer_overflow] Unsafe input demo +Enter a word: You entered: hello diff --git a/tests/runtime_check_1776156908_2_4.tmp b/tests/runtime_check_1776156908_2_4.tmp new file mode 100644 index 0000000..7ac5ad7 --- /dev/null +++ b/tests/runtime_check_1776156908_2_4.tmp @@ -0,0 +1,5 @@ +[stack_layout_demo] Stack address observation +Address of main_local: 0061FE4C +Address of buffer: 0061FE10 +Address of x: 0061FE0C +Address of parameter demo_id: 0061FE34 diff --git a/tests/runtime_check_1776156908_2_5.tmp b/tests/runtime_check_1776156908_2_5.tmp new file mode 100644 index 0000000..b20553a --- /dev/null +++ b/tests/runtime_check_1776156908_2_5.tmp @@ -0,0 +1 @@ +AAAAAAAAAAAAAAAAAAAAAA diff --git a/tests/runtime_check_1776156908_2_6.tmp b/tests/runtime_check_1776156908_2_6.tmp new file mode 100644 index 0000000..963a84d --- /dev/null +++ b/tests/runtime_check_1776156908_2_6.tmp @@ -0,0 +1,9 @@ +[overflow_behavior_demo] Deterministic overflow impact demo +Value of x before input: 10 +Enter input: Input length: 22 +WARNING: Input length (22) exceeds buffer capacity (15). +Simulated bytes written past buffer: 4 +Bytes that reached adjacent int: 4 of 4 +Adjacent int bytes after simulation: 41 41 41 41 +Value of x after simulated copy: 1094795585 +Buffer preview: AAAAAAAAAAAAAAAA diff --git a/tests/runtime_check_1776156908_3_7.tmp b/tests/runtime_check_1776156908_3_7.tmp new file mode 100644 index 0000000..bc77e48 --- /dev/null +++ b/tests/runtime_check_1776156908_3_7.tmp @@ -0,0 +1,11 @@ +[control_flow_simulation] Conceptual control-flow demo +Address of safe_function: 004025D8 +Address of target_function: 00402604 +Address of func_ptr var: 0061FE4C + +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.