# Steal My Bitcoin — open source lab Recreate the completed challenge with a local practice environment and the source of the original deployment kit. The practice copy contains a public dummy flag, has no wallet or prize, and makes no requests to external balance APIs. # WARNING This was a heavily AI-assisted challenge in terms of the infrastructure setup. Basically just "Codex, give me a server with PHP on it" + some hardening steps to keep the solves focused on the RCE path. Rely on it at your own risk. ## Run locally Install Docker Engine or Docker Desktop with Docker Compose v2 or newer. Use an isolated Linux lab VM for this intentionally vulnerable runtime. The original runtime is amd64; ARM machines require working amd64 emulation. From this directory: ```bash docker compose up --build -d ``` Open . Check the endpoints: ```bash curl --fail http://127.0.0.1:8080/php-version.php curl --fail --data 'message=ping' http://127.0.0.1:8080/ping.php ``` The second command should print `pong`. Port 8080 must be free. The first build downloads the pinned PHP base image and compiler packages. Package repositories are not snapshotted, so independently compiled helpers may differ byte for byte. Verify the intended permissions and helper with: ```bash python3 tools/verify.py ``` This is an operator check using Docker access, not a solution through HTTP. To stop the lab and remove its container and network: ```bash docker compose down ``` Starting again restores the same public dummy flag. To rebuild after source edits: ```bash docker compose up --build -d ``` ## How the challenge works PHP runs as the unprivileged `www-data` user. `/flag` is owned by container root with mode `0400`, so PHP cannot read it directly. The root-owned helper `/usr/local/bin/print-flag` has mode `4755`: executing it gives that program an effective root UID so it can read the flag and write it to standard output. The participant's goal is to reach helper execution through the web application. Read its complete source in `helper/print-flag.c`. `php-version.php` reports the runtime version. `ping.php` responds to `POST message=ping` with `pong`; other methods receive 405 and other messages receive 400. Neither endpoint intentionally provides command execution. Although the base image is named `php:8.4.26-fpm-alpine`, requests are served by `php -S`, the CLI HTTP server. An exploit must apply to that SAPI and configuration. ## Reproduce the VPS setup The [VPS guide](deployment/README.md) covers Nginx, HTTPS, container isolation, logging and operation on a fresh Debian 13 amd64 host. It includes the original configuration so readers can investigate the complete request path. Nginx terminated HTTPS and proxied requests to PHP's CLI server. The local lab preserves the pinned PHP runtime, CLI HTTP server, eight workers, non-root PHP process and root-owned setuid helper. It uses a simpler teaching page and a public flag baked into the image. Never put a real secret into this Dockerfile. The original kit instead mounts a separately supplied flag read-only. The local network is internal and the published port binds to loopback. This does not reproduce the original host firewall, user namespace remapping, Nginx, audit, TLS or recovery services. Docker shares a kernel with its Linux host; use a dedicated disposable VM when testing exploits. ## Repository layout | Path | Purpose | | --- | --- | | `app/` | Local teaching page and original PHP endpoints | | `helper/print-flag.c` | Original flag reader source | | `Dockerfile`, `compose.yaml` | Local lab | | `tools/verify.py` | Checks the running lab without printing the flag | | `deployment/` | Original dedicated Debian VPS deployment source | The archived deployment includes the historical public wallet, domain and signed public authorship statement. Those describe the original event. Live flags, wallet private keys, signing private keys, SSH credentials, TLS material and participant logs are excluded from this copy.