courses

Classroom Activities

How to use this page

Three activities per week, sized for a class meeting rather than a lab session:

That is roughly 35 minutes of the week’s contact time, split across the two meetings — warm-up plus one activity on Monday, warm-up recap plus the second activity on Wednesday, or both blocks in one sitting if the lecture runs short. Week 7 has a single meeting because the university is closed on 11 November, so both of its blocks land on the 9th.

Some ground rules that make these work:

⚠️ Authorization applies in the classroom too. The boards in the swap bin are course property and fair game. Your laptop, your phone, and the building’s access control system are not. The scope note on the schedule is not a formality.

Week 1 — Introduction and hardware fundamentals

Warm-up (5 min): Linux skills — find the board without a GUI

Everything in the next nine weeks starts with a device node and permission to open it. Find both now, on the machine you will actually use all term.

Run, in order, and read the output rather than skimming it:

$ lsusb
$ dmesg | tail -20
$ ls -l /dev/serial/by-id/
$ id -nG

Then answer three questions in your notebook:

  1. What is the full /dev/serial/by-id/ path for your Feather? Use that path, not /dev/ttyACM0 — the by-id name survives a reboot and a second board, and the numbered one does not.
  2. Are you in the group that owns that device node? Compare the group in the ls -l output against your id -nG list. On Debian and Ubuntu that group is dialout; on Arch and Fedora it is uucp.
  3. If you are not in it, what is the command to add yourself, and why do you have to log out afterwards?

🛠️ Fix the group membership now. It is the single most common reason a student loses the first twenty minutes of the Week 2 bench activity to a Permission denied they read as a broken board.

Deliverable: the three answers, plus the ls -l line for your board, in notebook/week01.md.

Activity 1 (15 min): The four questions, on someone else’s board

Setup: each pair draws an unfamiliar board from the swap bin — a dead router, a thermostat, a disassembled IP camera. Phone camera, good light.

Run:

  1. Photograph both sides at the highest resolution your phone will do, before you touch anything. This is the photo you will want in ten minutes.
  2. Work the four questions of hardware recon in order, writing each answer down before moving to the next: biggest chip, what is next to it, what talks to the outside world, what is left over.
  3. For the biggest chip only, transcribe the markings exactly — including the line you think is a date/lot code — and find one candidate datasheet.

Debrief: pairs read out their answer to question 4 only. Unpopulated headers and test-pad rows are the whole course in one observation, and hearing six boards in a row all have them makes the point better than a slide does.

Deliverable: both photographs, the four answers, the transcribed markings, and the datasheet URL.

Activity 2 (10 min): The FCC ID race

Setup: the exterior label of a radio-bearing device — from your swap-bin board if it has one, otherwise use the one projected at the front.

Run: an FCC ID looks like 2AB3C-XYZ100: a grantee code, then a product code. Search it at https://fccid.io or the FCC’s own equipment authorization search — the grantee code goes in the first field and the product code in the second — and find:

  1. The internal photographs.
  2. The test report, and the frequency range it was tested across.
  3. The block diagram, if the grantee did not get it withheld.

Debrief: compare the internal photos against your Activity 1 answers. Did the filing name a chip you could not read? The point lands hard: for any device with a radio sold in the US, someone has already taken it apart, photographed it, and published the results — and in a real assessment that is a free first hour.

⚠️ Confidentiality requests routinely hide schematics and internal photos. A filing with everything withheld is a legitimate finding, not a failed search — note which exhibits exist and which are confidential.

Deliverable: the FCC ID, a link to the filing, the tested frequency range, and one thing the filing told you that the board did not.

Week 2 — UART and instrumentation

Warm-up (5 min): Week 1 review — packages and date codes

Four photographs on the projector, sixty seconds each. For each one, write down the package type and the most likely role on the board:

Then one arithmetic question: a part is marked 2417. What is the earliest the firmware on that board could have been built, and what does that let you say when the vendor claims the unit shipped with version 3.2 from 2023?

Deliverable: four package/role pairs and the date-code answer.

Activity 1 (15 min): Ground, then voltage, then talk

Setup: the class demo board with a four-pad header, a multimeter, and a logic analyzer or scope. Your homework board stays in your bag for this one.

Run — in this order, because the order is the lesson:

  1. Ground first. Multimeter in continuity mode, one probe on a known ground (a shield can, or the negative terminal of a large electrolytic), the other walking the four pads. One will beep. Mark it.
  2. VCC second. Power the board. Measure each remaining pad against your ground. The one sitting steady at 3.3 V — or 1.8 V — and not moving is VCC. Write the number down. That number decides what you are allowed to connect in step 3.
  3. TX third. Put the analyzer on the two remaining pads and power-cycle the board. TX produces a burst of activity in the first second or two. RX idles high and does nothing.

Debrief: ask who connected anything before completing step 2. The voltage-domain callout exists because this is how probes and pads die, and doing the steps out of order once in a classroom is cheaper than doing it once on a customer’s only unit.

Deliverable: a labelled version of your Activity-1 photo — which pad is ground, VCC, TX, RX — and the measured idle voltage.

Activity 2 (10 min): Baud from the pulse, and prove it

Setup: week02-mystery.sr — or the .vcd if you would rather not install sigrok — plus PulseView or sigrok-cli. One channel named tx, sampled at 8 MHz. No hardware needed.

Run:

  1. Open the capture and zoom until individual bit cells are visible.
  2. Find the narrowest pulse in the capture. That is one bit time, because somewhere in the data there is an isolated 1 between two 0s.
  3. Compute baud = 1 / bit_period and round to the nearest standard rate.
  4. Prove it by decoding. From the command line:

    $ sigrok-cli -i week02-mystery.sr \
        -P uart:baudrate=<yours>:tx=tx:format=ascii -A uart=tx-data
    

    Substitute the rate you computed. Bytes with no printable form appear in brackets, so [0A] is a newline.

Debrief: now re-run the decode at 9600, and at 115200. Neither is silent — every rate produces bytes:

Rate Bytes decoded
9600 48
19200 88
38400 177
correct 290
115200 451

A wrong rate does not fail loudly. It hands you a plausible-looking pile of bytes, and the only thing distinguishing the right answer is that the output is readable and the byte count is stable. “The decoder produced output” is not evidence of anything. That is worth internalizing now, because the same trap is waiting in Week 9 with base addresses.

Deliverable: the measured pulse width, the computed baud, the nearest standard rate, and the decoded text.

Week 3 — I2C and SPI

Warm-up (5 min): Week 2 review — baud arithmetic sprint

Three numbers on the board; everyone computes, no calculators beyond the one on the phone:

  1. Narrowest pulse 8.68 µs → baud? Nearest standard rate?
  2. Narrowest pulse 104 µs → baud? Nearest standard rate?
  3. Your decoder produces plausible byte boundaries but every character is wrong. Is your problem the rate or the framing, and what do you change first?

Deliverable: three answers, with the reasoning on the third.

Activity 1 (15 min): Scan the bus, then watch the scan

Setup: your Feather with the OLED FeatherWing seated, plus a logic analyzer on SDA and SCL. The OLED is the only I2C device on the stack, which is what makes it a good first target — you know what the right answer is.

Run:

  1. Scan the bus from the CircuitPython REPL:

    import board
    i2c = board.STEMMA_I2C()
    while not i2c.try_lock():
        pass
    print([hex(a) for a in i2c.scan()])
    i2c.unlock()
    

    You should get ['0x3c'] — the SH1107 controller’s default address. The STEMMA QT connector and the FeatherWing header pins are the same bus, so it does not matter which the Wing uses.

  2. Now put the analyzer on SDA and SCL and run the scan again while capturing. Decode one transaction and identify, by hand, from the waveform: the START condition, the seven address bits, the R/W bit, and the ACK.
  3. Find a transaction for an address with nothing on it, and identify the NAK — SDA staying high during the ninth clock because nobody pulled it down.

Debrief: the scan is the NAK. i2c.scan() addresses all 112 valid addresses and reports the ones that answered; every other address produced the waveform you found in step 3. A tool’s output and the wire are the same story.

Deliverable: the scan result, an annotated screenshot of one decoded transaction with address / R/W / ACK marked, and one showing a NAK.

Activity 2 (10 min): JEDEC ID from a capture

Setup: week03-flash.sr — five channels at 16 MHz: CS_A, CS_B, SCK, MOSI, MISO. Decoding from a capture rather than a live part keeps this separate from HW #2 Task 2, which asks you to do it in situ.

Two chip selects share one set of data lines, which is how a board with more than one SPI device is always wired. Only one of them is talking to a flash. sigrok-cli takes one annotation class at a time, so decode each direction separately:

$ sigrok-cli -i week03-flash.sr \
    -P spi:clk=SCK:mosi=MOSI:miso=MISO:cs=CS_B -A spi=mosi-data
$ sigrok-cli -i week03-flash.sr \
    -P spi:clk=SCK:mosi=MOSI:miso=MISO:cs=CS_B -A spi=miso-data

Run:

  1. Decode the SPI transaction. The master sends one byte, 0x9F — Read JEDEC ID — and the part answers with three.
  2. Byte 1 is the JEDEC manufacturer ID. Byte 2 is the memory type; byte 3 is the capacity, encoded as a power of two: 0x18 means 2^24 bytes = 16 MiB.
  3. Identify the manufacturer and the most likely part number, and say how big the dump you are about to take in Week 5 will be.

Debrief: three bytes told you the vendor, the size of the image, and the command set you will use to read it. Note which line CS is on and what it did before the transaction — that is how you will find the flash on a board with four SPI devices sharing MOSI, MISO, and SCK.

Deliverable: the three ID bytes, the decoded manufacturer and capacity, the expected dump size in bytes, and a datasheet link.

Week 4 — JTAG and SWD

Warm-up (5 min): Week 3 review — two buses from memory

Reproduce this table without looking it up, then check it against the schedule:

  I2C SPI
Wires ? ?
How a device is addressed ? ?
Does the receiver acknowledge? ? ?

Then one question: you are watching four signals. One of them goes low just before each burst of activity on the other three, and high again after. Which bus is this, which signal is that, and what does it tell you about how many devices are on the bus?

Deliverable: the filled table and the answer.

📋 Run Activity 1 first this week. It is the paper exercise, and it gives you the vocabulary you need before the probe touches a target.

Activity 1 (10 min): Decode an IDCODE

Setup: paper, or a hex calculator. No hardware.

Run: IEEE 1149.1 fixes the layout of the 32-bit IDCODE register:

Bits Field
31–28 Version
27–12 Part number
11–1 Manufacturer identity (JEDEC)
0 Always 1

Given 0x4BA00477, split it into the four fields and answer:

  1. What is the manufacturer ID, and who is it? Shift right by 1 and mask to 11 bits. That 11-bit value is not a flat number: the low 7 bits are the JEDEC ID and the top 4 are a continuation count naming which bank of JEP106 to look in. Split it before you search, or you will find nothing.
  2. What is the part number? Look it up — and note that on ARM parts this field names the debug port, not the CPU. Which part of the chip have you actually identified, and what have you not?
  3. Bit 0 is always 1. Why does that matter to a scanner that does not yet know whether anything is on the chain?

Debrief: bit 0 is how a scan distinguishes “a device answered” from “the line is floating”. That single bit is why IDCODE is the first thing every JTAG tool tries.

Deliverable: the four field values, the decoded manufacturer, and the answer to question 3.

Activity 2 (15 min): Halt a running core

Setup: a class-set Black Magic Probe and one of the demo Cortex-M target boards. Not your Feather — the Feather RP2040 RFM95 does not break out SWDIO and SWCLK, which is itself worth two minutes of discussion at the end.

Run:

$ arm-none-eabi-gdb
(gdb) target extended-remote /dev/ttyACM0
(gdb) monitor swdp_scan
(gdb) attach 1
(gdb) info registers
(gdb) x/16xw 0x20000000

monitor swdp_scan scans the Serial Wire Debug Port; use monitor jtag_scan instead if the target is wired for JTAG. attach 1 attaches to the first target the scan reported.

Debrief: you just stopped a running processor mid-instruction and read its RAM, without the firmware’s cooperation and without anything having been printed to a console. Contrast that with Week 2: UART gives you what the firmware chose to say; SWD gives you the silicon. Then ask what the vendor should have done — and note that the Feather in your bag already does it, by simply not bringing the pads out.

Deliverable: the scan output, the register dump, and one paragraph on what an attacker gains here that a UART console would not have given them.

Week 5 — Firmware extraction from memory

Warm-up (5 min): Week 4 review — what does the silicon give you?

Two questions, written answers:

  1. Name three things SWD gives you that a root shell on a UART console does not. Name one thing the UART console gives you that SWD does not.
  2. A device answers an IDCODE scan on the main SoC but not on the second core. Give two different explanations, and say how you would tell them apart.

Deliverable: both answers.

Activity 1 (15 min): Triage three blobs

Setup: blob-a.bin, blob-b.bin and blob-c.bin, plus binwalk. Three images from three different devices, none of them the one HW #3 uses.

Run: for each blob, in under five minutes:

$ binwalk blob-a.bin
$ binwalk -E blob-a.bin

Classify each as one of:

For each, write one sentence on what you would do next.

⚠️ binwalk -E writes a PNG graph rather than printing numbers. Open it. The shape is the signal — a flat line at the top means stop, a line with structure means keep going.

Debrief: the third category is where assessments end, and knowing that in five minutes rather than five hours is the entire value of the technique. A flat 1.0 means either good encryption or somebody’s compression — and the header, or its absence, is usually what tells you which.

Deliverable: three classifications, the entropy graph for each, and the next-step sentence.

Activity 2 (10 min): Carve it yourself

Setup: whichever blob from Activity 1 binwalk found a filesystem in.

Run: binwalk told you an offset. Use it by hand rather than letting binwalk -e do it:

$ binwalk blob-a.bin
DECIMAL     HEXADECIMAL   DESCRIPTION
65536       0x10000       SquashFS filesystem, little endian, version 4.0, ...

$ dd if=blob-a.bin bs=1 skip=65536 of=rootfs.sqfs status=none
$ unsquashfs -d root rootfs.sqfs
$ ls root/

Debrief: two points, both worth the ten minutes.

  1. binwalk -e runs external extractors against attacker-controlled data. A malformed archive crafted by the vendor you are assessing is a code execution path into your analysis machine. dd is auditable; the wrapper is convenient. Choose deliberately, and run the wrapper in a container.
  2. You did not need the length. dd with skip and no count runs to the end of the file, and unsquashfs reads the size out of the superblock. Knowing which tool will find its own end saves you a second binwalk run.

Deliverable: the dd command you ran, the directory listing, and one sentence on why you would not run binwalk -e on a client’s firmware on your own laptop.

Week 6 — Networks, WiFi, BLE, and firmware from the wire

Warm-up (5 min): Week 5 review — read the entropy

Three entropy graphs on the projector. For each, say what it is and what you would do next:

  1. Flat at roughly 0.5 across the whole file.
  2. Flat near 1.0 across the whole file.
  3. Near 1.0 for most of the file, dropping to about 0.3 for the last eighth.

Then: which of the three is the one you most want, and why?

Deliverable: three classifications and the answer.

Activity 1 (15 min): Capture your own device updating

Setup: your Feather with the Airlift FeatherWing, your laptop, and tcpdump or Wireshark. You are making your own capture here — HW #3 Task 5 has you do the recovery against the course capture, so do not open that file in class.

Run:

  1. Serve a small file from your laptop over plain HTTP:

    $ python3 -m http.server 8000
    
  2. Start a capture on the interface your laptop’s WiFi is on.
  3. Have the Airlift fetch the file. The ESP32SPI requests example you already got running in Lab 2 does this in three lines.
  4. In Wireshark, find the transfer with Statistics → Conversations → TCP, sorted by bytes. Recover the file with File → Export Objects → HTTP.
  5. Hash what you recovered and compare it against the original:

    $ sha256sum served-file.bin recovered-file.bin
    

Debrief: you extracted a file off the wire in about four minutes, with no access to the device. Now the two questions that matter:

Deliverable: the conversation statistics screenshot, the two matching hashes, and written answers to both debrief questions.

Activity 2 (10 min): BLE advertising census

Setup: a phone with nRF Connect or LightBlue, or a laptop with bluetoothctl. Everyone at once — the room is the dataset.

Run:

$ bluetoothctl
[bluetooth]# scan on

Over five minutes, build a table of the ten strongest advertisers:

| Address | Type | Name (if any) | RSSI | Manufacturer data | | — | — | — | — | — |

For each, note whether the address is public, random static, or resolvable private. Then identify one device by its manufacturer-specific data alone — the first two bytes are a Bluetooth SIG company identifier.

Debrief: count how many devices in the room advertise a stable identifier. Those are trackable across locations and sessions by anyone with a $30 radio, with no pairing and no interaction. Then ask whose devices they are — the answer is usually “ours”, and that lands better than any slide about privacy.

Deliverable: the table, the company identifier you decoded, and a count of stable versus rotating addresses.

Week 7 — RF capture and spectrum analysis

📅 One meeting this week (Monday 9 November; the university is closed on Veterans Day). Both blocks run in that meeting, with the warm-up between them as a breather.

Warm-up (5 min): Week 6 review — which extraction path?

Three scenarios. For each, name the cheapest extraction path and what would have to be true for it to work:

  1. The vendor publishes firmware images on a public support page.
  2. The device pulls updates over HTTPS with certificate pinning, and the UART is silent.
  3. The device has a U-Boot prompt on an unlabelled four-pad header.

Then: in Activity 1 last week you verified a hash matched. What did that prove, and what did it not prove?

Deliverable: three paths and the hash answer.

Activity 1 (15 min): Find your partner’s transmitter

Setup: one SDR per pair — an RTL-SDR is enough for this — and a partner pair with a Feather transmitting on the 915 MHz band.

Run:

  1. Sweep the whole US 915 MHz ISM band before you tune anything:

    $ hackrf_sweep -f 902:928 -w 100000 -1 -r sweep.csv
    

    or, with an RTL-SDR:

    $ rtl_power -f 902M:928M:25k -i 20 -e 2m -g 40 us915.csv
    
  2. Have the other pair transmit repeatedly. Find the peak. Write down its centre frequency.
  3. Now tune a capture to it and confirm you can see it in a waterfall.
  4. Break it on purpose. Re-tune 2 MHz away, keeping the same bandwidth. The signal disappears completely. Then set the sample rate too low to span the channel and watch what survives.

Debrief: the three numbers — centre frequency, sample rate, gain. Step 4 is the point: a capture with the wrong centre frequency looks exactly like “there is no signal here”, and that misreading has ended more assessments than any technical limitation.

Deliverable: the sweep output, the peak frequency, a waterfall screenshot with the signal visible, and one with it missing because you re-tuned.

Activity 2 (10 min): Name that modulation

Setup: the four week07-signal-*.cs8 captures, opened in inspectrum. No transmitting.

They are complex signed 8-bit at 1 Msps, 100 ms each. A raw IQ file records none of that, so you have to be told:

$ inspectrum -r 1000000 -f cs8 week07-signal-1.cs8

Run: identify each by eye, using both the waterfall and the time-domain amplitude. You are looking for:

For each, write down the one visual feature that decided it for you.

Debrief: you did not demodulate anything. Modulation identification is a visual skill and it is fast, and it tells you which of the Week 8 pages to open before you have written a line of DSP.

Deliverable: four identifications, each with the deciding feature named.

Week 8 — Radio hacking: LoRa, Zigbee, Thread, and Matter

Warm-up (5 min): Week 7 review — sample-rate arithmetic

  1. You need to see a 500 kHz-wide channel. What is the minimum sample rate, and what would you actually set, and why is that more than the minimum?
  2. At 2 Msps with 8-bit I and 8-bit Q samples, how many megabytes does a 30-second capture consume?
  3. Your capture shows the signal pinned at full scale with flat tops. What is wrong, and which knob fixes it?

Deliverable: three answers with the arithmetic shown.

Activity 1 (15 min): Replay, and the counter that stops it

Setup: two pairs working together. Pair A transmits, Pair B captures and replays, using the RFM95 radios you already have running from Lab 1.

Run:

  1. Pair A sends a fixed message on 915 MHz; Pair B’s receiver prints it.
  2. Pair B records the payload it received, then transmits those same bytes back. Pair A’s receiver accepts it — it has no way to tell the difference, because there is none.
  3. Now Pair A adds a counter to the payload and rejects any message whose counter is not greater than the last one seen. Ten lines of CircuitPython.
  4. Pair B replays the same captured bytes again. Rejected.
  5. Now break it again. Pair B captures a newer message and replays that. What happens? What if Pair B suppresses Pair A’s transmission and replays it later?

Debrief: step 5 is where this activity earns its time. A frame counter stops naive replay and nothing else — it does not authenticate the sender, it does not provide confidentiality, and it has a well-known failure at rollover and at rejoin. That is precisely the LoRa versus LoRaWAN boundary: the counter is a LoRaWAN feature and your raw RFM95 link has nothing.

⚠️ Transmit only on the bench radios, at the lowest power that works. You are in an ISM band, but the building has real LoRa traffic in it and Lab 3 depends on that traffic staying intact.

Deliverable: the code diff adding the counter, evidence of the accepted replay before and the rejection after, and your answer to step 5.

Activity 2 (10 min): Key management on paper

Setup: paper. No hardware.

Run: a Zigbee light bulb ships with a well-known default link key. It is joined to a network in front of you, and you are listening.

  1. What can you recover from the join exchange, and what does it get you?
  2. Once you have it, what else on that network can you read — and why is the answer “everything”, not “that bulb”?
  3. An install code changes this. What exactly does it change, where does the code come from, and why do so many devices ship without one?
  4. Matter uses a J-PAKE-based commissioning flow with a per-device passcode and attestation certificates. Which of problems 1–3 does that actually solve, and which does it leave alone?

Debrief: question 2 is the one to dwell on. A single shared network key means the security of the network equals the security of its weakest-provisioned device, and that is an architectural property, not a bug in any one product.

Deliverable: four written answers.

Week 9 — Software reverse engineering and bootloaders

Warm-up (5 min): Week 8 review — LoRa versus LoRaWAN

  1. Which layer provides the AppKey, and which provides nothing at all?
  2. Name one thing a LoRaWAN frame counter protects against and two things it does not.
  3. OTAA versus ABP — which one re-derives session keys on join, and why does that matter after a power cycle?

Deliverable: three answers.

Activity 1 (15 min): Two words, one base address

Setup: week09-cm.bin, xxd, and Ghidra. A raw flash image — no ELF, no headers, no symbols — from a different device and needing a different method than HW #5 Task 1.

Run: a Cortex-M image begins with a vector table, and its first two words tell you where the image belongs.

$ xxd -e -g4 -l 8 week09-cm.bin
00000000: 20004000 100001c1                    .@. ....

Load the image in Ghidra at that base, ARM:LE:32:Cortex, and let auto-analysis run. It will not find much on its own — a raw blob has no entry point, so Ghidra has nothing to start disassembling from. Give it one: go to the reset handler address, press D to disassemble, and F to make it a function. Re-run auto-analysis and the call graph unrolls from there.

Debrief: two 32-bit words, read in ten seconds, replaced a pointer histogram. Always check for a header or a vector table before you reach for the statistical method — and note that this trick works because Cortex-M mandates the layout. An ARM Linux image has no such guarantee, which is exactly why HW #5 is harder than this.

Deliverable: both words, your derived base address with the reasoning, and a screenshot of the Ghidra import dialog.

Activity 2 (10 min): Prove the base address is wrong

Setup: the same image, still open in Ghidra.

Run:

  1. In your correctly-loaded image, open Window → Defined Strings and note how many of them have a cross-reference. Pick one and follow it to the function that uses it.
  2. Now import the same file again, at base 0x00000000.
  3. Repeat step 1 on the second import, and compare.

You should see something close to this:

Base Functions Strings Strings with xrefs
the one you derived 6 13 13
0x00000000 0 12 0
  1. One more check on the wrong load: go to address 0x00000004 and read the reset vector. It still contains the same value it always did — but that address is now nowhere near the image you have loaded.

Debrief: a wrong base address does not produce an error. Ghidra imports it without complaint, shows you bytes, and disassembles anything you point it at. What it cannot do is resolve anything: the literal pools still hold absolute addresses, and at the wrong base those addresses land outside the program, so every string reference dangles.

That is why the test is not “does it disassemble” but “do cross-references resolve” — and it is the same lesson as the baud rate in Week 2, one layer up. Both tools produce confident output at the wrong setting. Step 4 is the cheapest tell of all: if the reset vector points somewhere your image does not cover, your base is wrong before you have disassembled a single instruction.

Deliverable: the two tables side by side, one screenshot of a resolving cross-reference and one of a dangling one, and the reset-vector observation from step 4.

Week 10 — IoT operating systems and secure architecture

Warm-up (5 min): Week 9 review — evidence and trust

  1. You used two words to find a base address. Name a second source of evidence for a load address, and one kind of image where neither is available.
  2. Secure boot verifies the next stage before running it. Name the three things that verification has to establish, and the one thing an on-device SHA-256 check establishes on its own.

Deliverable: both answers.

Activity 1 (15 min): Five provisions, one device

Setup: ETSI EN 303 645 V3.1.3 open on one screen, your term’s accumulated findings on the other.

Run: the standard has thirteen outcome-focused clauses. Take these five:

Clause Provision
5.1 No universal default passwords
5.3 Keep software updated
5.5 Communicate securely
5.6 Minimize exposed attack surfaces
5.7 Ensure software integrity

For each, assess the device you have been working on all term as pass, fail, or not assessable, and cite the specific evidence — a capture, a dump offset, a file path, a photo. “Not assessable” is a legitimate verdict and it requires you to say what you would need in order to decide.

Then write one finding properly, in this shape:

Debrief: read two findings aloud and let the class attack them. The most common failure is an Impact section that describes the technique (“an attacker can intercept the update”) rather than the consequence (“an attacker on the same network can install arbitrary firmware, permanently”). The second is a Remediation that says “use TLS” without saying what the device does about certificate validation on a part with no real-time clock.

Deliverable: the five verdicts with evidence, and one fully written finding.

Activity 2 (10 min): Three changes

Setup: your findings from Activity 1. Pairs, then whole class.

Run: you have spent ten weeks building an attack chain against this device. Now spend ten minutes on the other side.

  1. Write down the minimum three changes that would have broken your chain. Not a wish list — three, and they have to be changes a product team could actually ship.
  2. For each, estimate the cost in the terms a vendor uses: unit BOM cost, engineering time, support burden, and what it breaks in the field.
  3. Rank them by cost-effectiveness and defend the ranking.

Debrief: the answers converge on remarkably cheap things — do not populate the debug header, do not ship a universal default password, sign the update and check the signature. None of those has a meaningful BOM cost. Then ask the real question: if they are this cheap, why is the device in front of you the way it is? The answer is organizational, not technical, and recognizing that is the difference between a report that gets acted on and one that does not.

Deliverable: three changes, three cost estimates, the ranking, and a paragraph on why the vendor did not make them.

Key takeaways

References


Related course pages: Activity Handouts · Schedule · Tools of the Trade · UART · I2C · SPI · JTAG and SWD · Dumping flash · Radio Protocols · LoRa and LoRaWAN · Zigbee · Thread and Matter · Software Reverse Engineering · Attacks

🛠️ Maintenance note: the handout files are generated, and the generator carries a verification pass — run it at the start of each offering to confirm every artifact still behaves the way the activity above says it does. The deconfliction notes throughout assume the current homework task numbering; if a homework task moves, re-check that the matching activity still rehearses the skill rather than solving the assignment. ETSI EN 303 645 is at V3.1.3 (September 2024) and the clause numbering in Week 10 tracks that revision. The Week 4 activity assumes Black Magic Probe firmware where the scan command is monitor swdp_scan; check monitor help if the probe’s firmware has moved on. The Week 9 figures come from Ghidra’s raw binary loader with ARM:LE:32:Cortex — a future release may find a different number of functions, but the xref column is structural and will not move.