Cookbook
A recipe manager and meal planner. You can export any recipe to a portable backup and import it on another device — and the restore step trusts the backup a little too much.
The Scenario
Cookbook keeps every recipe you love in one place: clean cards, a weekly meal planner, and a backup format so your collection moves with you. To make switching painless, the team built an "Import a recipe" screen that restores a card straight from an exported backup blob — reviving the saved object, title and all, exactly as it left the other kitchen. Restoring a saved object from untrusted text is where things get interesting.
Challenge Intel
Synopsis
The "Import a recipe" feature restores a backup by deserializing attacker-controlled text with a library that evaluates function-valued fields, turning the recipe title into server-side code execution.
What It Is
The Express app serializes and restores recipe "backups" with node-serialize 0.0.4. On POST /import it calls serialize.unserialize(req.body.backup) on the raw pasted text, then echoes the restored card's title back as "Imported '<title>'". node-serialize tags function-valued fields with the literal marker _$$ND_FUNC$$_ and, on unserialize, eval()s any field whose value starts with that marker. Because a function definition followed by () is an immediately-invoked function expression (IIFE), authoring the title as _$$ND_FUNC$$_function(){return require('child_process').execSync('cat /flag.txt').toString()}() runs the command at restore time and assigns its return value to title. The flag (written to /flag.txt by entrypoint.sh, chmod 644) is then rendered in-band on the confirmation page. There is no input filter and a single sink — this is the friendliest challenge in the deserialization set. The recon hook is authentic: the player's own exported backup contains a _$$ND_FUNC$$_-tagged field (the card's render hint), so the format reveals itself without the UI ever naming the library.
Who It's For
Players who have met insecure deserialization conceptually and want a clean, single-sink Node.js example to learn the node-serialize _$$ND_FUNC$$_ IIFE technique end to end. No filter bypass or chaining required.
Skills You'll Practice
- Recognising a serialized-object backup/restore format from your own export
- Identifying the node-serialize _$$ND_FUNC$$_ function marker
- Crafting an IIFE payload (trailing ()) so unserialize executes it
- Reading command output returned in-band via a reflected object field
- Remembering execSync returns a Buffer, so .toString() is required
What You'll Gain
- A concrete grasp of why deserializing untrusted input is RCE, not just data tampering
- The canonical node-serialize exploitation pattern, reusable across real targets
- An instinct to treat import/restore features as a high-risk trust boundary