The Master Key Was in the Box the Whole Time
Hardcoded keys in firmware: how one private key baked in at the factory unlocks every unit ever made.
Imagine a landlord who fits every apartment in the city with the exact same lock. Same cut, same pins, one key opens all of them. Now imagine that to save the installers a trip, he tapes a copy of that key inside each door. Nobody notices, because you’d have to open the door to see it, and if you can already open the door, why would you look?
That’s a hardcoded key in firmware. The key that unlocks the device is stored inside the device, identical on every unit, shipped from the factory. The only thing standing between an attacker and every one of those locks is the assumption that nobody will pull the firmware apart and read what’s inside. That assumption has a shelf life, and for abandoned hardware it has already expired.
Why abandoned hardware is the good stuff
The device in the book, a Nestfield Pro Home Hub v2.3.1, is interesting precisely because the company that made it is gone. No more updates. No CDN to pull the firmware down. No security team to email. Whatever shipped in 2021 is what’s still running in someone’s hallway, and it will keep running until the power goes out for good.
That’s not a Nestfield problem. It’s the default state of consumer IoT. A hub is bought once, bolted to a wall, and forgotten. The vendor’s incentive to patch it drops to roughly zero the day the warranty ends, and to actually zero the day they go under. The kernel freezes in time. In the boot log, this one announces Linux version 4.14.98, a kernel from early 2019, running years past its last security patch. Hold that thought; it matters at the end.
Getting inside the image
You don’t need the physical device to read its firmware. You need a copy of the image. In the book Cade pulls nestfield_pro_v2.3.1_firmware.bin from an enthusiast archive mirror, which is exactly how this goes: someone hoards the images before the vendor’s servers disappear.
The first tool out of the bag is binwalk. Binwalk scans a blob byte by byte, matching known magic signatures, and tells you what’s inside and where. The output is three columns, decimal offset, hex offset, description:
$ binwalk nestfield_pro_v2.3.1_firmware.bin
DECIMAL HEXADECIMAL DESCRIPTION
--------------------------------------------------------------------------------
0 0x0 uImage header, header size: 64 bytes, header CRC: 0x8B2A1F3C,
OS: Linux, CPU: ARM, image type: OS Kernel Image,
compression type: lzma, image name: "Linux-4.14.98"
64 0x40 LZMA compressed data, properties: 0x5D,
dictionary size: 8388608 bytes
1048576 0x100000 Squashfs filesystem, little endian, version 4.0,
compression: xz, size: 6291456 bytes, 762 inodes,
blocksize: 131072 bytes
That’s a textbook embedded layout: a U-Boot uImage header, an LZMA-packed kernel, and a SquashFS root filesystem, the compressed, read-only image that holds the actual Linux userland. SquashFS is where the interesting files live because it’s where all the files live.
Extraction is one flag. -e carves out and decompresses everything binwalk recognized:
$ binwalk -e nestfield_pro_v2.3.1_firmware.bin
Older binwalk drops the results in _nestfield_pro_v2.3.1_firmware.bin.extracted/, with the unpacked root under squashfs-root/. (The v3 Rust rewrite reorganizes carved files into offset-named subdirectories, but the SquashFS still unpacks to a browsable tree either way.) Now you have the device’s entire filesystem sitting in a folder on your laptop, no soldering required.
Reading the walls
Once you have a rootfs, finding hardcoded secrets is embarrassingly mechanical. You’re not reverse-engineering anything. You’re grepping a directory for the string that PEM keys always start with:
$ grep -rl "BEGIN RSA PRIVATE KEY" squashfs-root/etc squashfs-root/root
squashfs-root/etc/ssh/ssh_host_rsa_key
squashfs-root/root/.ssh/id_rsa
There it is. A private key, in the base firmware image, the same file on every unit off the line. Standard places worth checking on any embedded target: /etc/ssh/ and /etc/dropbear/ for host keys, ~/.ssh/id_rsa and authorized_keys for account keys, plus any config file that inlines a certificate or password.
The kill shot is when the same key is both trusted and present. Check what the device’s SSH server accepts:
$ cat squashfs-root/root/.ssh/authorized_keys
ssh-rsa AAAAB3NzaC1yc2EAAAADAQAB...QX9 nestfield-mfg@build-srv-03
If that public key is the mate of the id_rsa you just extracted, the private key is a universal master credential: it authenticates as root, or a sudo-capable service account, on every device that shipped with this image. Not “a” hub. The whole model line. You didn’t crack anything. You read a file the manufacturer left in the box.
This is a real, catalogued class of bug
None of this is exotic, and it isn’t fiction outside the book. Hardcoded and unchangeable credentials sit at number one on the OWASP IoT Top 10: “Weak, Guessable, or Hardcoded Passwords,” explicitly including backdoor keys baked into firmware. And it has the CVE trail to prove it:
- CVE-2015-6476 — Advantech EKI industrial gateways shipped with hardcoded SSH keys the user could not change, letting anyone with the key onto the device remotely. CISA advisory and firmware fix.
- Cisco has patched multiple products for shipping default or shared SSH keys and hardcoded support credentials. Same shape, bigger blast radius.
The pattern repeats because the root cause is always a scheduling decision, not a cryptographic one. Generating a unique key per device at manufacture costs engineering time; baking one static key in costs nothing. In the book there’s even a TODO comment in the leaked source admitting it: “uses static key for manufacturing convenience. MUST fix before v3.0.” Version 3.0 never shipped. That comment is a real artifact of real codebases.
And the kernel? 4.14.98 is years stale. A known local privilege-escalation bug, the kind that was patched upstream ages ago and rated “nothing” on a maintained system, is a live root exploit on a device that stopped receiving updates. Dirty COW (CVE-2016-5195) is the archetype: fixed upstream in weeks, still landing on orphaned devices years later. The remote key gets you a shell; the unpatched kernel turns that shell into root. Neither half is clever. Both work because nobody’s home.
The fix
- Unique credentials per device, provisioned at manufacture. One compromised key should burn one device, not the entire model line. This is the whole ballgame.
- Verified boot and signed firmware updates, so a device runs only images the vendor signed, and so a vendor can still ship a fix.
- Kill debug access in production. Serial and JTAG headers left live are the front door to everything above. Disable or lock them before shipping.
- Segment IoT off your real network. Assume the hub is compromised and put it on a VLAN where a foothold buys the attacker nothing but the hub.
- Buy from vendors who’ll still exist. An update pipeline is only as good as the company behind it.
The point
The security of that hub was never in the lock. It was in the bet that nobody would open the box and read what was taped inside, a bet the manufacturer stopped being able to lose the moment they stopped being able to win, because they stopped existing. The device is exactly as secure as it was the day it shipped, which is the problem: the world moved, the exploits got written, and the firmware didn’t change a byte. Abandoned tech doesn’t get safer with age. It just gets quieter, while the key it’s holding stays good.
Read next
- The scene: Chapter 0.2 — Side Hustle — a surplus hub, a serial console, and a supply run to Ki’s shop.
- More field notes: Service Accounts Never Change Their Passwords — another credential that outlives everyone who should have rotated it · Padlocks are Suggestions — reading traffic that was supposed to be private.
- Codex: Ki Sou Mihn · M.I.H.N Custom Systems · The Bust
Sources & further reading
- binwalk (ReFirmLabs) — the firmware analysis tool
- OWASP IoT Top 10 — “Weak, Guessable, or Hardcoded Passwords” sits at #1
- CISA ICSA-15-309-01 — Advantech hardcoded SSH keys (CVE-2015-6476), a real instance of exactly this