Settle
Settle is a payments backend for small merchants: sign up a shop, take card payments, and view reporting. An internal admin console handles exports and merchant reporting.
The Scenario
Settle processes card payments for small shops. After a suspicious export and an admin
action nobody owns up to, the team wants to know how far an outsider could get starting
from a plain merchant signup, across the merchant site, the admin console, and the
reporting database.
Begin as a merchant and see how much of the stack you can take apart without ever being
handed a credential.
Lab Intel
Synopsis
Four containers: nginx gateway, a Node app serving both the merchant (settle.local) and admin (admin.settle.local) consoles, a PHP signed-export service (export.settle.local), and an internal-only Postgres. The remember cookie is AES-128-CBC(iv||ct) of uid=<n>&role=<role>; /api/session/restore returns 400 on bad PKCS7 vs other codes otherwise - a padding oracle. CBC-R forges a role=admin cookie. The admin signed-export links use MD5(XPORT_SECRET||d) as a MAC; MD5 length-extension appends &file=../../../config/settle.ini (binary-safe parse) to read the internal config, which holds the report_key. The admin reporting endpoint fetches a merchant's name (stored safely at signup) and concatenates it into an elevated query run by a Postgres SUPERUSER role (second-order SQLi). Stacked statements run COPY ... FROM PROGRAM 'cat /var/lib/postgresql/flag.txt' in the DB container; the flag is read back in the report. Two distinct crypto attacks precede any SQL.
Architecture
A master chain stacking two crypto-oracle attacks and a database-container RCE. Recon (JS bundle) -> AES-CBC padding oracle + CBC-R to forge the admin session -> MD5 hash length-extension on the home-rolled signed-export MAC to read an internal config (report_key) -> second-order SQL injection (a stored merchant name concatenated into a superuser reporting query) -> COPY ... FROM PROGRAM RCE landing in the internal Postgres container, where the flag is read as the non-root postgres OS user.
Who It's For
Advanced players who want crypto-oracle practice wired into a realistic chain: a padding oracle used for forgery (not just decryption), hash length-extension against a bad MAC, and a Postgres-specific COPY TO/FROM PROGRAM RCE reached through a second-order injection in a separate DB container.
Skills You'll Practice
- AES-CBC padding oracle and CBC-R ciphertext forgery
- MD5/SHA hash length-extension against MAC = hash(secret||message)
- Recognising and triggering a second-order (stored) SQL injection
- Postgres COPY ... FROM PROGRAM for RCE and reading a DB-container file
What You'll Gain
- Why unauthenticated CBC with distinguishable padding errors is a forgery primitive
- Why hash(secret||data) is a broken MAC (length extension)
- COPY TO/FROM PROGRAM as a superuser-only RCE sink, and cross-container flag placement