$ cat writeup.md…
$ cat writeup.md…
umasscybersec
Task: a KiCad PCB file described a logic board with seven inputs and nineteen LED outputs. Solution: reconstruct the gate-level netlist from the board text, simulate all 7-bit input values, and map each LED-driving net to one ASCII character to recover the flag.
Organizer description was not preserved in the local task files.
English summary: the challenge provided a KiCad PCB layout for a custom logic board. The goal was to understand what the circuit displayed and recover the hidden flag without manually tracing every wire in the CAD viewer.
The strongest initial clue was the file format itself: smart-brick-v2.kicad_pcb. That matches the hint about a popular open-source EDA tool, so the right starting point was to inspect the board as KiCad data rather than treat it as a binary blob.
Reconnaissance immediately showed a few important structural facts:
IN0..IN6J1 breaks out those seven inputs plus GNDJ2 provides power with +5V and GND74LS21 devices plus 74LS02, 74LS20, 74LS00, 74LS32, 74LS86, 74LS04, 74LS27, and 74LS082N7002 MOSFETSeven independent input bits strongly suggest 7-bit ASCII. The many TTL gates and absence of storage elements also suggest pure combinational logic: for any input value, the board computes a fixed set of outputs.
At that point, the challenge becomes a netlist-recovery problem. Instead of manually following traces in the PCB viewer, it is faster and more reproducible to parse the KiCad board file as text, extract each footprint, collect pad-to-net assignments, and translate each chip package into logic operations.
The included solver does exactly that. It:
footprint blocks from the .kicad_pcb text/IN0 through /IN6 as the seven bits of all 128 possible ASCII inputsThis works because every final LED-driving net is true for exactly one input character. So each LED is effectively a hard-wired character recognizer.
The final step is to recover display order. Since each LED is driven by a 2N7002, sorting those transistor footprints by Y coordinate gives the top-to-bottom board order. Reading the nineteen decoded characters in that order yields the flag.
IN0..IN6 inputs and nineteen LED outputs.128 possible 7-bit input values.The recovered string is:
UMASS{REDACTED}
A compact excerpt of the provided solver shows the overall approach:
for i in range(7): mask = 0 for x in range(128): if (x >> i) & 1: mask |= 1 << x cache[f"/IN{i}"] = mask def ev(net: str) -> int: if net in cache: return cache[net] op, ins = ops[net] vals = [ev(n) for n in ins] ... for net in final_gate_nets: hits = [x for x in range(128) if (ev(net) >> x) & 1] gate_to_char[net] = chr(hits[0]) flag = "".join(gate_to_char[gnet] for _y, _ref, gnet in sorted(led_rows)) print(flag)
The full solve_smart_brick_v2.py script prints the flag directly once the netlist model is built.
$ cat /etc/motd
Liked this one?
Pro unlocks every complete writeup and expanded API access. $9/mo.
$ cat pricing.md$ grep --similar