Self-Checkout
Cartwell Market's Scan and Go app locks your account behind a one-time code texted to your phone at sign in. Create an account, reach the verification step, and see whether that second factor really holds.
The Scenario
Cartwell rolled out Scan and Go so members can ring themselves up and skip the queue. The account sign in picked up a second step (a code sent to your phone) in the sprint before launch. An engineer wired the check into the app, shipped it, and moved on to the next ticket.
Challenge Intel
Synopsis
A two-step login (password, then a one-time code) where the server checks the code but returns the verdict to the browser and then trusts the browser's copy of it to complete the login. Intercept the verify response, flip otp_verified from false to true, and the front-end finalizes the sign in for you.
What It Is
After the password step, /login marks the session pending (pw_ok) and stores a random one-time code server-side, then sends you to /otp. The OTP page posts the entered code to POST /api/otp/verify, which checks it against the stored copy and answers with JSON only, {"otp_verified": false, "next": "/otp"} for a wrong code or {"otp_verified": true, "next": "/account"} for the right one. That endpoint does not grant access, it only reports the verdict. The front-end trusts the verdict, and on true it calls POST /api/session/finalize with {"otp_verified": true}. The finalize endpoint is the bug, it believes the client-supplied boolean and sets mfa_verified on the session without re-checking the code. So the verified state is a value that round-tripped through the client. Submit a wrong code, intercept the /api/otp/verify response in a proxy, change otp_verified to true, and forward it. The page script then finalizes with true, the server marks you verified, and /account renders the account recovery key, which is the flag. The /account page strictly requires mfa_verified, so force browsing it after the password step just redirects back to /otp. The one-time code is stored in the database and never in the cookie, and the session is signed with a per-container secret, so the finalize step is the only way to become verified.
Who It's For
Anyone learning multi-factor bypass. Assumes you can use an intercepting proxy (Burp or similar) to edit a response body. No brute force or injection needed.
Skills You'll Practice
- Reading a two-step login flow and spotting where the verdict is decided
- Intercepting and editing a JSON response body in a proxy
- Recognising a client-trusted verification result
- Flipping a boolean the server should never have trusted
What You'll Gain
- The instinct to check whether a verified flag is decided by the server or the client
- A concrete example of a flippable MFA verdict returned to the browser
- Practice completing a login by editing a response rather than guessing a code