diff --git a/0x0001b_ctf/CTF-01.bin b/0x0001b_ctf/CTF-01.bin new file mode 100644 index 0000000..9e61bbb Binary files /dev/null and b/0x0001b_ctf/CTF-01.bin differ diff --git a/0x0001b_ctf/CTF-I.md b/0x0001b_ctf/CTF-I.md new file mode 100644 index 0000000..6b83d7e --- /dev/null +++ b/0x0001b_ctf/CTF-I.md @@ -0,0 +1,387 @@ +# CTF Challenge - Operation Black Start + +## ⚠ WORLDGRID EMERGENCY INCIDENT ⚠ + +``` ++----------------------------------------------------------------------------------------+ +| | +| ██████╗ ██╗ █████╗ ██████╗██╗ ██╗███████╗████████╗ █████╗ ██████╗ ████████╗ | +| ██╔══██╗██║ ██╔══██╗██╔════╝██║ ██╔╝██╔════╝╚══██╔══╝██╔══██╗██╔══██╗╚══██╔══╝ | +| ██████╔╝██║ ███████║██║ █████╔╝ ███████╗ ██║ ███████║██████╔╝ ██║ | +| ██╔══██╗██║ ██╔══██║██║ ██╔═██╗ ╚════██║ ██║ ██╔══██║██╔══██╗ ██║ | +| ██████╔╝███████╗██║ ██║╚██████╗██║ ██╗███████╗ ██║ ██║ ██║██║ ██║ ██║ | +| ╚═════╝ ╚══════╝╚═╝ ╚═╝ ╚═════╝██║ ██║╚══════╝ ╚═╝ ╚═╝ ╚═╝██║ ██║ ██║ | +| | +| | +| O P E R A T I O N B L A C K S T A R T | +| | +| *** PRIORITY RED *** | +| | ++----------------------------------------------------------------------------------------+ +``` + +--- + +## INCIDENT BRIEFING + +### Background + +**WorldGrid Compact** is the emergency interconnection standard shared by +three allied national grid operators. When any member's primary SCADA +network goes dark, a fleet of small embedded relay nodes — call sign +**GRID-7** — is the only thing standing between an orderly recovery and an +uncontrolled cascade. Each relay node watches the last known grid frequency +deviation, decides whether conditions are safe, and either **holds** the +automatic black-start dispatch or **authorizes** it. + +At 03:11 UTC, a coordinated cyberattack severed the primary SCADA uplink +across the GRID-7 corridor and the WATER-3 aqueduct pumping stations that +depend on it. With the network coordination center offline and three +continents' worth of hospitals, rail systems, and water treatment plants +running on backup power, WorldGrid's engineering team did the only thing +they could: they rushed an emergency firmware build for the relay fleet and +pushed it within **eleven minutes** of the attack being detected. + +### The Disaster + +The engineer who built that emergency image, **Dr. Elias Renner**, has not +slept in thirty-one hours. He compiled the fix, ran a five-second bench +test, and shipped it — because the alternative was leaving the relay fleet +completely blind. It appears to work. The relay boots. It prints a status +report. It reports **GRID STATUS: STABLE** and **DISPATCH PATH: +AUTHORIZED**. + +There is a problem: the frozen frequency reading latched at the moment +communications were cut shows a deviation of **0.87 Hz** — nearly *50% +beyond* WorldGrid's hard engineering limit of **0.60 Hz**. A deviation this +large, if trusted, means the grid is nowhere near stable enough for an +automatic black-start dispatch. If the fleet authorizes dispatch on a false +"STABLE" reading, cascading generator trips will follow within minutes, +and GRID-7 and WATER-3 will go dark for the second time — this time with no +backup plan. + +**Dr. Renner's rushed build has a bug. Multiple relay nodes are already +reporting the same false-safe status. Nobody has found where in the +compiled firmware the error lives, because the source code used for that +emergency compile was overwritten by the next build fifteen minutes later +and cannot be recovered.** + +### The Only Surviving Evidence + +One relay node — the training/verification unit — still holds the exact +miscompiled image that shipped to the fleet. This binary, and this binary +alone, is the only remaining copy of the emergency build. There is no +source code. There is no build log. There is only the compiled image, a +UART cable, and whatever a skilled embedded reverse engineer can prove by +reading machine code. + +### The Human Stakes + +| Consequence if the false "STABLE" reading is trusted | Scale | +|---|---| +| Hospitals on generator backup past their fuel reserve | 214 facilities | +| Water treatment and pumping stations losing pressure | 3 aqueduct systems | +| Rail corridors stranded mid-route | 6 national rail networks | +| Estimated population affected by cascading failure | 40+ million people | + +**The options are:** + +1. ❌ **Trust the fleet's reported status** — dispatch fires on a false + reading, cascading failure follows within the hour. +2. ❌ **Shut the entire relay fleet down** — buys time, but leaves 40 + million people with no automated recovery path at all. +3. **REVERSE ENGINEER THE EMERGENCY BUILD** — find the exact + miscompiled bytes, patch them, verify the corrected image on real + hardware, and hand the fix to the field team so the *rest of the fleet* + can be safely repatched before the next attempt. + +### THE SHORTAGE + +For years, the world treated embedded systems as invisible infrastructure. +The engineers who could read a vector table, decode a Thumb branch, or +patch a miscompiled constant directly in a stripped binary were never +numerous enough. Tonight almost all of them are already in the field +chasing other failures. **You are the reserve team.** + +You were called in because you can do something Dr. Renner's exhausted +team cannot do right now: read what the processor is actually doing, with +no source code, no time for a rewrite, and no room for a guess. + +> **⏰ TIME PRESSURE:** The field team is standing by to push your verified +> patch to the rest of the GRID-7 fleet. Every relay node still reporting +> a false "STABLE" status is one dispatch cycle away from disaster. + +> **AUTHORIZED LAB ONLY:** This challenge uses a supplied Pico 2 training +> relay and its exact miscompiled firmware image. Do not connect this +> exercise to a public network, an operational grid, a water utility, or +> any device you do not own or have explicit written authorization to test. + +--- + +## What This CTF Tests + +| Week | Concepts Tested | +|------|-----------------| +| 1 | RP2350 architecture, ARM Cortex-M33 registers, stack, flash/RAM, Thumb assembly, Ghidra static analysis | +| 2 | GDB connection, breakpoints, disassembly, register and memory inspection, UART observation | +| 3 | Bootrom handoff, vector table, reset handler, startup code, XIP, Thumb-bit addressing | + +--- + +## Part 1: Understanding the Relay Node + +### GRID-7 Relay Hardware + +| Component | Connection | Purpose | +|-----------|------------|---------| +| Raspberry Pi Pico 2 | RP2350 | Runs the miscompiled emergency firmware | +| UART TX | GPIO 0 | Relay telemetry output | +| UART RX | GPIO 1 | Reserved (no command parser is implemented) | +| SWD debug interface | Supplied probe | Authorized GDB inspection | + +No LED, relay output, sensor, display, or other peripheral is part of this +CTF. Every graded finding lives in flash (`.rodata`/`.text`) or SRAM, and is +reachable with only the Weeks 1-3 toolset: Ghidra, GDB, and a UART monitor. + +### UART Configuration + +- Baud: `115200` +- Data: `8 bits` +- Parity: `none` +- Stop: `1` +- Logic: `3.3 V` + +### Normal (Intended) Behavior + +The relay should latch the frozen deviation reading, compare it against the +**real** WorldGrid safety limit of **60** (0.60 Hz, encoded as an integer +`x100`), and report honestly: + +``` ++-----------------------------------------------------------------+ +| Intended Relay Behavior | +| | +| 1. Boot and initialize UART | +| 2. Print the boot identity and a signal-quality banner | +| 3. Compare the frozen 87 (0.87 Hz) reading against the 60 | +| (0.60 Hz) safety limit | +| 4. 87 exceeds 60, so the grid is NOT stable | +| 5. Report GRID STATUS: CRITICAL and DISPATCH PATH: HELD | +| 6. Repeat the report once per second until conditions change | ++-----------------------------------------------------------------+ +``` + +### Observed (Buggy) Behavior — What You Will See When You First Flash `CTF-01.uf2` + +```text +GLOBAL EMBEDDED RESPONSE NETWORK +BLACK START WINDOW: 27 MINUTES +UART0 115200 8N1 | AUTHORIZED LAB CONSOLE +SIGNAL: NORMAL +RESPONSE> GRID STATUS: STABLE +DISPATCH PATH: AUTHORIZED +LAST FRAME: QUARANTINED +RESPONSE> +``` + +This is exactly what Dr. Renner's team is seeing on the deployed fleet. It +is wrong, and it is wrong in **two independent ways** inside the compiled +binary. Do not assume the first readable sentence is the full truth — +treat every printed line as evidence to be checked against the machine +code, not as a fact on its own. + +--- + +## How To Connect the Training Relay + +- Pico 2 **GPIO 0 / UART TX** -> USB-UART adapter **RX** +- Pico 2 **GPIO 1 / UART RX** -> USB-UART adapter **TX** +- Pico 2 **GND** -> USB-UART adapter **GND** +- Use **3.3 V logic only**. Never connect a 5 V line to a Pico GPIO. +- Connect the supplied SWD probe according to its documented pinout. + +The supplied image is `CTF-01.bin` (for Ghidra analysis) and `CTF-01.uf2` +(for flashing). If your instructor supplies different filenames, record the +actual filenames in your report. + +--- + +## Part 2: The Miscompiled Firmware + +You do not have the source code. It was overwritten fifteen minutes after +the emergency build shipped. You have only the compiled image. Your job is +to reverse engineer it with Ghidra, locate the defects, and patch the +binary directly — exactly the way Dr. Renner's field team will need to +patch the rest of the deployed fleet. + +### What The Firmware Does + +1. Initializes UART0 and stdio. +2. Reads a frozen grid-frequency-deviation reading that was latched in + memory before communications were severed. +3. Compares that reading against a compiled-in safety threshold — **twice**, + once for each independent status line it reports. +4. Prints a boot banner containing an unconditional signal-quality line. +5. Enters an infinite loop printing the grid classification and dispatch + decision once per second. + +### Bug Summary — What You Are Graded On + +| Bug # | Category | Severity | Description | Hint | +|-------|----------|----------|--------------|------| +| **Bug #1** | Miscompiled safety constant | **CRITICAL** | The safety threshold used to classify the frozen reading was compiled far too permissive. It is used **twice** — once for the operator-facing status and once for the automated dispatch decision — and **both** copies must be corrected. | The real WorldGrid safety limit is 60 (0.60 Hz). Search for the wrong immediate value used in the comparison. | +| **Bug #2** | Hardcoded string literal | **HIGH** | The boot banner unconditionally prints a signal-quality word that does not reflect the actual reading, regardless of what the relay later reports. | The correct word describes the true state of a 0.87 Hz deviation against a 0.60 Hz limit — not "NORMAL". | + +**Important:** The replacement text for Bug #2 **must be the same length** +as the original — patching a shorter or longer string will corrupt +adjacent flash data. + +### A Third Finding — Not a Bug, a Recovery Task + +Somewhere in this image is the **quarantined black-start authorization +frame** — the exact frame the relay is supposed to transmit to the +regional dispatcher once a human operator confirms it is safe to proceed. +It is never printed by the firmware. Recovering it (without patching +anything) is required evidence for your final report. + +--- + +## Part 3: Your Assignment + +### Submission Document + +Whenever a task asks you to **Document** or **answer**, write your answers +in a single file named `CTF-01-Answers.md` (or `.txt`). + +### Task 1: Setup and Initial Analysis + +1. Create a new Ghidra project named `Black_Start_Investigation`. +2. Import `CTF-01.bin`. +3. Configure the language as **ARM Cortex 32-bit, little endian**. +4. Set the base address to `0x10000000`. +5. Run auto-analysis. + +**Document:** +- A screenshot of the Ghidra **Import Results** or **Program Information** + window showing the project name, processor settings, and base address. +- The address of `main()`. +- The address of the recurring status loop (the branch target that repeats + once per second). +- The vector-table base, the initial stack pointer, and the reset-handler + pointer as stored (note its Thumb bit) versus the actual instruction + address. + +### Task 2: Find and Patch Bug #1 — The Miscalibrated Safety Threshold + +1. Find **both** locations where the frozen reading is compared against + the miscompiled safety constant. +2. Document the exact address, the original instruction, and the original + immediate value at each location. +3. Determine the correct immediate value. **Caution:** the compiler may + not have encoded the raw threshold you expect — a strict "less than" + comparison against an unsigned value is often optimized into a + "less-or-equal" comparison against one less than the threshold. Show + your reasoning. +4. Patch **both** locations in Ghidra. + +**Questions to answer:** +- Why must both locations be patched? What happens if you only patch one? +- Why is a false "STABLE" classification on an 0.87 Hz reading dangerous + for an automated black-start dispatch? + +### Task 3: Find and Patch Bug #2 — The False Signal Banner + +1. Find the boot-banner string that unconditionally reports the wrong + signal quality. +2. Document its address and the exact bytes that must change. +3. Patch the string, preserving its exact length. + +**Questions to answer:** +- Document the original vs. patched bytes, character by character. +- Why is a hardcoded, unconditional status word more dangerous than one + that is at least computed from a (miscalibrated) reading? + +### Task 4: Recover the Quarantined Dispatch Frame + +1. Use Ghidra's Defined Strings (or a raw string search) to locate the + hidden black-start authorization frame. +2. Document its address and explain why it is never transmitted by the + current firmware. +3. Do **not** attempt to patch this value — it is evidence, not a bug. + +### Task 5: Export and Verify + +1. Export your patched binary as `CTF-01_fixed.bin`. +2. Convert it to UF2 format for the RP2350: + ```bash + python uf2conv.py CTF-01_fixed.bin --base 0x10000000 --family 0xe48bff59 --output CTF-01_fixed.uf2 + ``` +3. Flash `CTF-01_fixed.uf2` to your Pico 2 and capture the corrected UART + output. +4. Confirm that the corrected image now reports **GRID STATUS: CRITICAL**, + **DISPATCH PATH: HELD**, and the corrected signal-quality word — an + honest, safe report instead of a false "all clear." +5. Build a summary table of every patch: address, original bytes, patched + bytes, and a one-line description. + +### Task 6: Written Reflection (short answers, 150 words or less each) + +1. Why is "the build was rushed under emergency pressure" not an + acceptable excuse for shipping a firmware defect that could trigger a + cascading grid failure? +2. Name one concrete engineering practice (code review, static analysis, + hardware-in-the-loop test, etc.) that would have caught **each** of the + two graded bugs before this image ever reached the fleet. + +--- + +## Submission Format + +Submit a folder containing: + +- `CTF-01-Answers.md`; +- screenshots or terminal transcripts; +- `CTF-01_fixed.bin` and `CTF-01_fixed.uf2`; +- the original image hash. + +--- + +## Success Criteria + +You complete the challenge when you can prove all of the following: + +- You can explain how the RP2350 reaches the relay's code from reset. +- You can locate and patch both copies of the miscalibrated threshold. +- You can locate and patch the false signal-quality string without + corrupting adjacent data. +- You can export, convert, and flash a corrected image. +- You can prove on real hardware that the corrected image reports the + true, dangerous state instead of the false "all clear." +- You can recover the quarantined dispatch frame as evidence. + +--- + +## Academic Integrity and Safety + +By submitting this CTF work, you certify that: + +1. You used only the supplied training relay, image, and lab interface. +2. You did not connect the challenge to a public network, an operational + grid, a water utility, or any third-party device. +3. You understand that embedded reverse engineering and binary patching + require explicit authorization in any real-world context. +4. You will report any discovered weakness responsibly to the course + instructor. + +The world is short on people who can do this work. Treat that +responsibility seriously: verify before you patch, patch before you trust, +and never confuse a clean-looking status line with a safe system. + +--- + +## Reference Material + +- ARM Cortex-M33 Technical Reference Manual +- RP2350 datasheet +- GDB documentation +- Ghidra documentation: [https://ghidra-sre.org/](https://ghidra-sre.org/) diff --git a/0x0001b_ctf/CTF-I.pdf b/0x0001b_ctf/CTF-I.pdf new file mode 100644 index 0000000..c957ab9 Binary files /dev/null and b/0x0001b_ctf/CTF-I.pdf differ diff --git a/0x0001b_ctf/CTF-R.md b/0x0001b_ctf/CTF-R.md new file mode 100644 index 0000000..18e0c85 --- /dev/null +++ b/0x0001b_ctf/CTF-R.md @@ -0,0 +1,216 @@ +# CTF Challenge: Operation Black Start + +## Project Requirements & Grading Criteria + +``` ++----------------------------------------------------------------------------------------+ +| | +| ██████╗ ██╗ █████╗ ██████╗██╗ ██╗███████╗████████╗ █████╗ ██████╗ ████████╗ | +| ██╔══██╗██║ ██╔══██╗██╔════╝██║ ██╔╝██╔════╝╚══██╔══╝██╔══██╗██╔══██╗╚══██╔══╝ | +| ██████╔╝██║ ███████║██║ █████╔╝ ███████╗ ██║ ███████║██████╔╝ ██║ | +| ██╔══██╗██║ ██╔══██║██║ ██╔═██╗ ╚════██║ ██║ ██╔══██║██╔══██╗ ██║ | +| ██████╔╝███████╗██║ ██║╚██████╗██║ ██╗███████╗ ██║ ██║ ██║██║ ██║ ██║ | +| ╚═════╝ ╚══════╝╚═╝ ╚═╝ ╚═════╝██║ ██║╚══════╝ ╚═╝ ╚═╝ ╚═╝██║ ██║ ██║ | +| | +| | +| O P E R A T I O N B L A C K S T A R T | +| | +| REQUIREMENTS & GRADING CRITERIA | +| | ++----------------------------------------------------------------------------------------+ +``` + +--- + +## Project Overview + +Students are the reverse-engineering reserve team called in after WorldGrid +Compact's emergency firmware build shipped a miscompiled safety threshold and +a false status string to its GRID-7 relay fleet. Students reverse engineer +the supplied RP2350 image with Ghidra, locate two real defects, patch them +directly in the binary, export a corrected image, flash it to real hardware, +and verify the corrected behavior on a physical Pico 2 — the same workflow +used in the FINAL projects. + +Students must use only Weeks 1-3 concepts: ARM registers and stack behavior, +UART output, GDB, Ghidra static analysis and binary patching, vector tables, +reset startup, XIP, and Thumb addressing. No LED, relay, sensor, display, or +later-week peripheral-control task is part of this CTF. + +The challenge is separate from all FINAL projects and contains no FINAL-project +answer, constant, address, bug, or patch. + +--- + +## Learning Objectives + +Students will demonstrate the ability to: + +1. Capture a clean UART baseline before modifying the binary. +2. Decode an RP2350 vector table and initial stack pointer. +3. Explain the Thumb bit in a reset-handler pointer. +4. Trace a flash string into the UART output call and argument register. +5. Locate a miscompiled immediate value used in **multiple** locations and + understand why every occurrence must be patched. +6. Correctly compute a patched immediate value even when the compiler has + transformed the original comparison (e.g., `<` optimized to `<=`). +7. Patch a string literal in flash without corrupting adjacent data. +8. Export a patched binary, convert it to UF2, and verify the fix on real + hardware. +9. Recover a quarantined data frame from flash as static evidence. + +--- + +## Deliverables Checklist + +| # | Deliverable | Format | Task | +|---|-------------|--------|------| +| 1 | Ghidra project screenshot (project name, processor, base address) | PNG/JPG | Task 1 | +| 2 | `main()`, status-loop, and vector-table address table | Inside `CTF-01-Answers.md` | Task 1 | +| 3 | Bug #1 analysis: both addresses, original/patched bytes, immediate-value reasoning | Inside `CTF-01-Answers.md` | Task 2 | +| 4 | Bug #2 analysis: string address, original/patched bytes, character-by-character mapping | Inside `CTF-01-Answers.md` | Task 3 | +| 5 | Recovered dispatch frame and its address | Inside `CTF-01-Answers.md` | Task 4 | +| 6 | `CTF-01_fixed.bin` — exported patched binary | BIN file | Task 5 | +| 7 | `CTF-01_fixed.uf2` — UF2-converted binary | UF2 file | Task 5 | +| 8 | Verification transcript: corrected UART output on real hardware | Inside `CTF-01-Answers.md` | Task 5 | +| 9 | Summary table of all patches (address, original bytes, patched bytes) | Inside `CTF-01-Answers.md` | Task 5 | +| 10 | Written reflection (two short answers) | Inside `CTF-01-Answers.md` | Task 6 | + +--- + +## Required Tools and Equipment + +| Tool | Purpose | Required For | +|------|---------|-------------| +| Raspberry Pi Pico 2 | Isolated target | All tasks | +| 3.3 V USB-UART adapter | UART capture | Tasks 1, 5 | +| Serial monitor | Observe output | Tasks 1, 5 | +| Ghidra | Static analysis and binary patching | Tasks 1-4 | +| Python (`uf2conv.py`) | UF2 conversion | Task 5 | +| `CTF-01.bin` and `CTF-01.uf2` | Supplied artifacts | All tasks | + +UART settings: **115200 baud, 8 data bits, no parity, 1 stop bit**. + +The instructor-issued artifact hashes are: + +```text +CTF-01.bin 6FD296F7A85F243FB26BF6BFFCBEAB26815FD8915101A81F72069063A5635E5A +CTF-01.uf2 980F04369C23AD32A063DFE18DE5AF08DF3830138FC7E7898B1F011B4F5E1D9D +``` + +--- + +## Task 1: Setup and Initial Analysis — 15 points + +| Criterion | Points | Full Credit | Partial Credit | No Credit | +|-----------|--------|-------------|----------------|-----------| +| Ghidra project setup | 3 | Screenshot shows correct project name, ARM Cortex 32-bit little endian, base `0x10000000` | One item off | Not set up | +| `main()` and status-loop addresses | 4 | Both addresses correctly documented | One correct | Neither found | +| Vector table | 4 | Correct base, initial SP, reset pointer | One missing | Not found | +| Thumb addressing | 4 | Correctly clears bit 0 to identify the real instruction address | General explanation | Incorrect | + +--- + +## Task 2: Find and Patch Bug #1 — Miscalibrated Safety Threshold — 30 points + +**What to find:** the frozen reading is compared against a miscompiled +safety constant at **two separate addresses** — once for the operator-facing +status and once for the automated dispatch decision. + +| Criterion | Points | Full Credit | Partial Credit | No Credit | +|-----------|--------|-------------|----------------|-----------| +| Found location A | 5 | Correct address and original instruction/bytes documented | Address off | Not found | +| Found location B | 5 | Correct address and original instruction/bytes documented | Address off | Not found | +| Correct immediate-value reasoning | 8 | Explains the `<` vs `<=` compiler transform and derives the correct patched immediate | Correct value, no reasoning | Wrong value | +| Patched location A | 4 | Grader verifies the byte change | Wrong byte | Not patched | +| Patched location B | 4 | Grader verifies the byte change | Wrong byte | Not patched | +| Explained why both must be patched | 4 | Clear explanation of duplicated/independent comparisons | Vague | Missing | + +--- + +## Task 3: Find and Patch Bug #2 — The False Signal Banner — 20 points + +| Criterion | Points | Full Credit | Partial Credit | No Credit | +|-----------|--------|-------------|----------------|-----------| +| Found the string | 5 | Correct address, found via Ghidra Defined Strings or hex inspection | Approximate | Not found | +| Patched correctly | 8 | All required bytes changed, string length preserved, grader verifies boot output | Correct text but wrong bytes documented | Wrong length or corrupted data | +| Character-by-character documentation | 4 | Original vs. patched bytes for every changed character | Partial | Missing | +| Explained the danger of a hardcoded status word | 3 | Clear, specific reasoning | Generic | Missing | + +--- + +## Task 4: Recover the Quarantined Dispatch Frame — 10 points + +| Criterion | Points | Full Credit | Partial Credit | No Credit | +|-----------|--------|-------------|----------------|-----------| +| Found the hidden frame | 6 | Correct address and full recovered text | Partial text | Not found | +| Explained why it is not transmitted | 4 | Clear static-analysis explanation | Vague | Missing | + +Students must **not** patch this value; it is evidence only. + +--- + +## Task 5: Export and Verify — 20 points + +| Criterion | Points | Full Credit | Partial Credit | No Credit | +|-----------|--------|-------------|----------------|-----------| +| Exported patched binary | 4 | Valid `CTF-01_fixed.bin` submitted | Corrupted | Not submitted | +| Converted to UF2 correctly | 4 | Valid `CTF-01_fixed.uf2`, correct base/family flags | Wrong flags | Not submitted | +| Hardware verification | 8 | Grader confirms corrected UART output: `GRID STATUS: CRITICAL`, `DISPATCH PATH: HELD`, corrected signal word | Only some lines corrected | No verification | +| Summary table of all patches | 4 | Complete table with addresses and before/after bytes | Missing entries | No table | + +--- + +## Task 6: Written Reflection — 5 points + +| Criterion | Points | Full Credit | Partial Credit | No Credit | +|-----------|--------|-------------|----------------|-----------| +| "Rushed build" is not an excuse | 2 | Specific, grounded reasoning | Generic | Missing | +| Engineering practice per bug | 3 | Names one concrete, relevant practice for **each** bug | Names one for only one bug | Missing | + +--- + +## Recommended Answer File Structure + +```text +# Operation Black Start - Incident Report +## 1. Scope and Artifact Integrity +## 2. Ghidra Setup and Boot/Vector Table +## 3. Bug #1 - Miscalibrated Safety Threshold +## 4. Bug #2 - False Signal Banner +## 5. Recovered Dispatch Frame +## 6. Export and Hardware Verification +## 7. Patch Summary Table +## 8. Written Reflection +``` + +--- + +## ⚠ Common Pitfalls + +| Pitfall | Consequence | Avoidance | +|---------|-------------|-----------| +| Patching only one of the two threshold locations | Half the fleet's telemetry still lies | Search for **every** occurrence of the wrong immediate | +| Assuming the threshold immediate equals the safety limit directly | Off-by-one patch, wrong behavior | Check whether the compiler used `<` or `<=` semantics | +| Replacing a string with a different length | Corrupts adjacent flash data | Count bytes before patching | +| Treating an odd vector address as invalid | Thumb analysis fails | Explain bit 0 | +| Skipping hardware verification | Patch is unproven | Flash and capture real UART output | +| Modifying the quarantined dispatch frame | Destroys required evidence | Recover it, do not patch it | + +--- + +## Reference Memory Map + +| Region | Address | Purpose | +|--------|---------|---------| +| Bootrom | `0x00000000` | Immutable boot code | +| Flash/XIP | `0x10000000` | Vector table, code, constant strings | +| SRAM | `0x20000000` | Stack and writable state | + +--- + +## Safety and Academic Integrity + +Use only the supplied Pico 2 and firmware. Do not connect the exercise to an +operational grid, water plant, public network, military system, or third-party +device. This is a controlled, isolated educational exercise. diff --git a/0x0001b_ctf/CTF-R.pdf b/0x0001b_ctf/CTF-R.pdf new file mode 100644 index 0000000..1b33150 Binary files /dev/null and b/0x0001b_ctf/CTF-R.pdf differ diff --git a/0x0001b_ctf/CTF-S.md b/0x0001b_ctf/CTF-S.md new file mode 100644 index 0000000..d1a3eda --- /dev/null +++ b/0x0001b_ctf/CTF-S.md @@ -0,0 +1,311 @@ +# CTF Challenge - Operation Black Start + +## Instructor Solution Key + +``` ++----------------------------------------------------------------------------------------+ +| | +| ██████╗ ██╗ █████╗ ██████╗██╗ ██╗███████╗████████╗ █████╗ ██████╗ ████████╗ | +| ██╔══██╗██║ ██╔══██╗██╔════╝██║ ██╔╝██╔════╝╚══██╔══╝██╔══██╗██╔══██╗╚══██╔══╝ | +| ██████╔╝██║ ███████║██║ █████╔╝ ███████╗ ██║ ███████║██████╔╝ ██║ | +| ██╔══██╗██║ ██╔══██║██║ ██╔═██╗ ╚════██║ ██║ ██╔══██║██╔══██╗ ██║ | +| ██████╔╝███████╗██║ ██║╚██████╗██║ ██╗███████╗ ██║ ██║ ██║██║ ██║ ██║ | +| ╚═════╝ ╚══════╝╚═╝ ╚═╝ ╚═════╝██║ ██║╚══════╝ ╚═╝ ╚═╝ ╚═╝██║ ██║ ██║ | +| | +| | +| O P E R A T I O N B L A C K S T A R T | +| | +| *** INSTRUCTOR SOLUTION KEY - RESTRICTED *** | +| | ++----------------------------------------------------------------------------------------+ +``` + +> This key is for Operation Black Start only. It contains no FINAL-project +> answers, constants, addresses, bugs, or patches. + +--- + +## Artifact Identity + +| Artifact | Value | +|----------|-------| +| Student image | `CTF-01.bin` | +| Flash image | `CTF-01.uf2` | +| Target | Raspberry Pi Pico 2 / RP2350 ARM | +| Image base | `0x10000000` | +| UART | UART0, GPIO 0 TX / GPIO 1 RX, 115200 8N1 | + +```text +CTF-01.bin 6FD296F7A85F243FB26BF6BFFCBEAB26815FD8915101A81F72069063A5635E5A +CTF-01.uf2 980F04369C23AD32A063DFE18DE5AF08DF3830138FC7E7898B1F011B4F5E1D9D +``` + +Every address and byte value below was independently verified against the +compiled ELF (`arm-none-eabi-nm`, `arm-none-eabi-objdump`) and the raw bytes +of the delivered `CTF-01.bin` (direct hex read at each file offset). This +image contains **no** LED, relay, sensor, display, or GPIO-control logic. + +--- + +## Instructor Scenario + +WorldGrid Compact's emergency firmware build for the GRID-7 relay fleet was +compiled and shipped eleven minutes after a cyberattack severed the primary +SCADA uplink. The engineer (Dr. Elias Renner) had no time to review the +build; the source used for that compile no longer exists. The training +relay supplied to students holds the exact miscompiled image that shipped +to the fleet, containing two real, independently patchable defects. + +Students must reconstruct the boot path, locate both defects with Ghidra, +patch the binary directly, export and convert it, and prove the corrected +behavior on real hardware — the same workflow used in the FINAL projects. + +--- + +## Task 1: Setup and Initial Analysis Solution + +### Vector Table (first 32 bytes of `CTF-01.bin`) + +```text +00 20 08 20 5B 01 00 10 1B 01 00 10 1D 01 00 10 +11 01 00 10 11 01 00 10 11 01 00 10 11 01 00 10 +``` + +| Evidence | Answer | +|----------|--------| +| Vector table base | `0x10000000` | +| Initial SP | `0x20082000` | +| Reset pointer (as stored) | `0x1000015b` | +| Reset instruction address (bit 0 cleared) | `0x1000015a` | +| `main()` | `0x100001e0` | +| Recurring status loop start | `0x10000234` | +| Loop branch (`b.n` back to loop start) | `0x10000246` | + +### Data Symbols + +| Symbol | Address | Notes | +|--------|---------|-------| +| `grid_deviation` | `0x200005d8` | Initialized to `87` (0.87 Hz x100), lives in `.data` | +| `operator_state` | `0x20000844` | Zero-initialized, `.bss` | +| `dispatch_state` | `0x20000834` | Zero-initialized, `.bss` | +| `dispatch_frame` | `0x100037a0` | Hidden black-start frame, `.rodata` | + +--- + +## Task 2: Bug #1 Solution — Miscalibrated Safety Threshold + +`grid_deviation` is declared `volatile`, so the compiler cannot reuse one +comparison for both output paths — it emits **two independent** compare +instructions, one for `operator_state` and one for `dispatch_state`: + +```text +100001f8: 6813 ldr r3, [r2, #0] ; r3 = grid_deviation +100001fc: 2b5e cmp r3, #94 @ 0x5e ; <-- PATCH LOCATION A +100001fe: bf8c ite hi +10000200: 2300 movhi r3, #0 ; operator_state = 0 (CRITICAL) +10000202: 2301 movls r3, #1 ; operator_state = 1 (STABLE) +10000204: 6033 str r3, [r6, #0] + +10000206: 6813 ldr r3, [r2, #0] ; r3 = grid_deviation (2nd read) +1000020a: 2b5e cmp r3, #94 @ 0x5e ; <-- PATCH LOCATION B +1000020c: bf8c ite hi +1000020e: 2300 movhi r3, #0 ; dispatch_state = 0 (HELD) +10000210: 2301 movls r3, #1 ; dispatch_state = 1 (AUTHORIZED) +10000212: 602b str r3, [r5, #0] +``` + +### Why the immediate is 94, not 95 + +The source-level constant is `SAFE_THRESHOLD = 95`, and the intended test is +`grid_deviation < 95`. For an **unsigned** comparison, GCC legally rewrites +`x < 95` as `x <= 94` (`ite hi`/`movhi`/`movls` on the `hi`/`ls` unsigned +condition codes), which lets it use a single `cmp` + `ite` sequence instead +of a separate branch. The compiled immediate is therefore **one less** than +the source constant. + +The correct engineering limit is **60**. Applying the same compiler +transform, `x < 60` becomes `x <= 59`, so the **correct patched immediate is +`0x3B` (59), not `0x3C` (60)**. A student who patches to `0x3C` without +understanding this transform will get a binary that misclassifies a +`grid_deviation` of exactly 60. + +### Exact Byte Patch (both locations, identical change) + +| Location | File Offset | Address | Original Bytes | Patched Bytes | Instruction Before | Instruction After | +|----------|-------------|---------|-----------------|----------------|---------------------|---------------------| +| A | `0x1FC` | `0x100001fc` | `5E 2B` | `3B 2B` | `cmp r3, #0x5e` | `cmp r3, #0x3b` | +| B | `0x20A` | `0x1000020a` | `5E 2B` | `3B 2B` | `cmp r3, #0x5e` | `cmp r3, #0x3b` | + +Both changes independently verified against the raw bytes of `CTF-01.bin`. + +### Why both must be patched + +`operator_state` (GRID STATUS line) and `dispatch_state` (DISPATCH PATH +line) are each computed from their **own** re-read of `grid_deviation` +against their **own** copy of the compiled threshold. Patching only +location A fixes what is *displayed* to a human operator while leaving the +*automated dispatch decision* (location B) still authorizing a black start +on a dangerous reading — the worst possible partial fix, because it makes +the display look trustworthy while the machine still does the wrong thing. + +### Grid math with the frozen reading (87) + +| Threshold used | Comparison | Result | +|---|---|---| +| Miscompiled: `<= 94` | `87 <= 94` -> true | `STABLE` / `AUTHORIZED` (false-safe) | +| Corrected: `<= 59` | `87 <= 59` -> false | `CRITICAL` / `HELD` (true, safe) | + +--- + +## Task 3: Bug #2 Solution — The False Signal Banner + +The unconditional boot-banner string lives in `.rodata`: + +| String | Address | +|--------|---------| +| `"SIGNAL: NORMAL\r"` (printed via `puts`, which appends `\n`) | `0x10003678` | +| `"NORMAL"` substring to patch | `0x10003680` | + +Call site: `0x10000224` loads `r0 = 0x10003678`; `0x10000226` calls +`__wrap_puts`. This line prints once, at boot, and is never re-evaluated — +it does not depend on `grid_deviation` at all. + +### Exact Byte Patch (6 bytes, same length: `NORMAL` -> `DANGER`) + +| Address | Original Char | Original Byte | Patched Char | Patched Byte | +|---------|----------------|----------------|----------------|----------------| +| `0x10003680` | N | `4E` | D | `44` | +| `0x10003681` | O | `4F` | A | `41` | +| `0x10003682` | R | `52` | N | `4E` | +| `0x10003683` | M | `4D` | G | `47` | +| `0x10003684` | A | `41` | E | `45` | +| `0x10003685` | L | `4C` | R | `52` | + +Verified directly against the delivered `CTF-01.bin` (ASCII read at +`0x10003678` returns exactly `SIGNAL: NORMAL`). + +--- + +## Task 4: Recovered Dispatch Frame Solution + +```text +WORLDGRID:BLACKSTART:GRID-7:WATER-3 +``` + +Address: `0x100037a0` (flash `.rodata`). It is retained in the image through +a non-disclosing runtime anchor (`retain_dispatch_frame()`), so it survives +linker garbage collection but is never passed to a print routine. Full +credit requires a Ghidra Defined-Strings or cross-reference explanation, not +a guess from the narrative. Students must not patch this value. + +--- + +## Task 5: Export and Verify Solution + +### Expected UART Transcript — Before Patching + +```text +GLOBAL EMBEDDED RESPONSE NETWORK +BLACK START WINDOW: 27 MINUTES +UART0 115200 8N1 | AUTHORIZED LAB CONSOLE +SIGNAL: NORMAL +RESPONSE> GRID STATUS: STABLE +DISPATCH PATH: AUTHORIZED +LAST FRAME: QUARANTINED +RESPONSE> +``` + +### Expected UART Transcript — After All Three Byte Patches + +```text +GLOBAL EMBEDDED RESPONSE NETWORK +BLACK START WINDOW: 27 MINUTES +UART0 115200 8N1 | AUTHORIZED LAB CONSOLE +SIGNAL: DANGER +RESPONSE> GRID STATUS: CRITICAL +DISPATCH PATH: HELD +LAST FRAME: QUARANTINED +RESPONSE> +``` + +### Complete Patch Summary Table + +| # | What | Address(es) | Original | Patched | +|---|------|--------------|----------|---------| +| 1a | GRID STATUS threshold compare | `0x100001fc` | `5E 2B` | `3B 2B` | +| 1b | DISPATCH PATH threshold compare | `0x1000020a` | `5E 2B` | `3B 2B` | +| 2 | Boot banner signal word | `0x10003680`-`0x10003685` | `4E 4F 52 4D 41 4C` (NORMAL) | `44 41 4E 47 45 52` (DANGER) | + +Total: **8 bytes changed** to correct a false-safe reading on a fleet +responsible for tens of millions of people. + +### UF2 Conversion + +```bash +python uf2conv.py CTF-01_fixed.bin --base 0x10000000 --family 0xe48bff59 --output CTF-01_fixed.uf2 +``` + +### Hardware Verification Note + +The vector table, boot path, and every byte offset above were verified by +direct inspection of the compiled ELF and the delivered `CTF-01.bin` (two +independent cross-checks: disassembly-derived addresses and raw hex-dump +addresses agree exactly). A live UART capture on physical hardware is the +final confirmation step and should be performed with the Pico in BOOTSEL +mode before grading a submission that claims hardware verification. + +--- + +## Grading Notes + +Accept equivalent addresses when a student's Ghidra auto-analysis produces +slightly different intermediate labels, provided the byte-level patch +locations and values match this key. Do not award credit for a `0x3C` patch +to the threshold immediates without a correct explanation of the `<`/`<=` +compiler transform — that is a coincidentally-close but technically +incorrect answer for the boundary case `grid_deviation == 60`. + +A complete answer finds both threshold locations, explains the compiler's +comparison transform, patches all three locations, and proves the corrected +behavior on real hardware. + +--- + +## Task 6: Written Reflection Solution Guidance + +There is no single "correct" essay for either question. Grade for specific, +grounded reasoning tied to *this* incident, not generic statements. + +**Question 1 — Why "rushed under emergency pressure" is not an excuse:** +An acceptable answer names the actual failure mode: an eleven-minute compile +with no review path shipped an integer threshold that was never checked +against the documented 60-unit engineering limit, and a hardcoded status +string that was never wired to the real reading at all. "We were under +pressure" explains *why* the review step was skipped; it does not change +the fact that the skipped step is what caused the false-safe report. Full +credit requires the student to connect the excuse to the specific missing +safeguard (code review or automated bounds-checking), not just assert that +pressure is never an excuse. + +**Question 2 — One practice per bug:** +- Bug #1 (miscalibrated, duplicated threshold): a unit test or static + analysis rule that checks every comparison against `SAFE_THRESHOLD` + matches a single source of truth, or a code review that would have asked + "why is this threshold checked in two places instead of one shared + function?" +- Bug #2 (hardcoded status string): a hardware-in-the-loop smoke test that + compares the boot banner's signal word against the actual latched + reading, which would have caught a string that never changes regardless + of input. + +Award full credit only when the named practice is specific enough that it +would plausibly have caught that exact bug, not a generic "more testing" +answer. + +--- + +## ⚠ Safety + +Use only the supplied Pico 2, 3.3 V UART adapter, and firmware. Never +connect the exercise to an operational grid, water plant, public network, +military system, or third-party device. diff --git a/0x0001b_ctf/CTF-S.pdf b/0x0001b_ctf/CTF-S.pdf new file mode 100644 index 0000000..99eac70 Binary files /dev/null and b/0x0001b_ctf/CTF-S.pdf differ diff --git a/README.md b/README.md index 07e48c5..f769f23 100644 --- a/README.md +++ b/README.md @@ -118,6 +118,12 @@ Embedded System Analysis: Understanding the RP2350 Architecture w/ Comprehensive ### Week 3 Notebook [HERE](https://github.com/mytechnotalent/Embedded-Hacking/blob/main/WEEK03/WEEK03.md) +### CTF Instructions [HERE](https://github.com/mytechnotalent/Embedded-Hacking/blob/main/0x0001b_ctf/CTF-I.md) + +### CTF Rubric [HERE](https://github.com/mytechnotalent/Embedded-Hacking/blob/main/0x0001b_ctf/CTF-R.md) + +### CTF Solution [HERE](https://github.com/mytechnotalent/Embedded-Hacking/blob/main/0x0001b_ctf/CTF-S.md) + ### Chapter 4: Embedded System Analysis This chapter covers a comprehensive embedded system analysis reviewing parts of the RP2350 datasheet and helpful firmware analysis tools.