Tanuki is a flashcard web app with an XML-based deck export and a JSON-driven restore endpoint. The server secretly round-trips your JSON through an XML template with DTD processing enabled — giving you a path to read arbitrary files off the server without any out-of-band channel. Your goal is to exfiltrate the flag at /app/flag.txt entirely in-band.
Objective: Identify which top-level JSON key has its value interpolated inside the DOCTYPE's internal subset ([ ]), rather than inside the document body — since only that position allows an entity definition to be declared.
Context: An XML external entity must be declared inside the DOCTYPE internal subset to be valid. Fields like name and description land inside <backup>...</backup> — too late in the document. One undocumented JSON key is concatenated directly into <!DOCTYPE backup [ HERE ]>. Fuzz plausible key names while pointing name at &xxe; to detect resolution.
Only reveal the ones you need. Claude tracks how many you used to calibrate the feedback.
Entity declarations must appear in the DOCTYPE, not inside a body element. Think about what key name would logically represent 'the DTD content' that a developer might splice into that slot.
Fuzz top-level JSON keys (try: dtd, doctype, schema, internal, subset, entities, meta, xml, type) by setting each one to an entity definition and setting name to &xxe;. For each attempt, create a deck and read back the name field. Resolution means you found the right key.
For each candidate key K, POST {"K": "<!ENTITY xxe SYSTEM \"file:///etc/passwd\">", "name": "&xxe;", "description": "d", "category": "c", "cards": []}. GET the new deck. If name is [object Object] or file content instead of the literal &xxe;, K is your injection point. The working key is dtd.
Chat with a spoiler-safe tutor for this step. It uses only this lab spec and gives the smallest useful nudge first.
Tell the tutor what you tried, where you got stuck, or paste the response/error you are seeing.
Enjoying Hintru? Buy me a coffee ☕ ☕