pwnfreeeasy

Brick Workshop

umasscybersec

Task: an amd64 menu service stores calibration integers in stack locals inside `workshop_turn()` and later reuses them after a state change. Solution: trigger diagnostics once to seed stale stack values, choose pigment `0xBEEF`, then invoke diagnostics again so the uninitialized reuse satisfies the win check.

$ ls tags/ techniques/
stale_stack_value_reusestateful_menu_logic_abusealgebraic_input_selection

Brick Workshop — UMass Cybersecurity CTF

Description

Provided challenge materials: bad_eraser, bad_eraser.c, Dockerfile, Makefile, and the remote service nc bad-eraser-brick-workshop.pwn.ctf.umasscybersec.org 45002.

English summary: this was a small amd64 menu binary themed as a brick workshop. The goal was to review the control flow, find how the hidden win() condition could be reached, and retrieve the flag from the remote service.

Service:

nc bad-eraser-brick-workshop.pwn.ctf.umasscybersec.org 45002

Challenge Summary

This was not a classic memory-corruption pwn with a buffer overflow or ROP chain. The binary was an amd64 ELF, dynamically linked, non-PIE, NX enabled, no canary, partial RELRO, and not stripped, but the real issue was a logic bug caused by uninitialized stack variables.

The exploit path was just:

  1. Choose menu option 3
  2. Enter 0 48879
  3. Choose menu option 3 again

That second diagnostics call reused stale stack values from the previous call and immediately hit win().

Recon / Code Review

The important code lives in workshop_turn():

static void workshop_turn(void) { int choice; unsigned int mold_id; unsigned int pigment_code; banner(); if (scanf("%d", &choice) != 1) { exit(0); } ... if (!service_initialized) { puts("First-time calibration required."); puts("Enter mold id and pigment code."); if (scanf("%u %u", &mold_id, &pigment_code) != 2) { exit(0); } puts("Calibration saved. Re-enter diagnostics for clutch validation."); service_initialized = 1; return; } diagnostics_bay(mold_id, pigment_code); }

The hidden success path is in diagnostics_bay():

static unsigned int clutch_score(unsigned int mold_id, unsigned int pigment_code) { return (((mold_id >> 2) & 0x43u) | pigment_code) + (pigment_code << 1); } static void diagnostics_bay(unsigned int mold_id, unsigned int pigment_code) { puts("Running clutch-power diagnostics..."); if (clutch_score(mold_id, pigment_code) == 0x23ccdu) { win(); } puts("Result: unstable clutch fit. Send batch back to sorting."); exit(0); }

Vulnerability Explanation

The bug is use of uninitialized stack variables.

...

🔒

Permission denied (requires auth)

Sign in to read this free writeup

This writeup is free — just sign in with GitHub to read it.

$ssh [email protected]