Trust Issues
tjctf
Task: a custom DNSSEC resolver and admin bot had to be abused to redirect trust-issues.tjc.tf to an attacker host. Solution: poison the resolver cache through the upstream parameter and SQL injection, then bypass DNSSEC verification with a skipped fake RRSIG and capture the flag from the bot URL.
$ ls tags/ techniques/
$ cat /etc/rate-limit
Rate limit reached (20 reads/hour per IP). Showing preview only — full content returns at the next hour roll-over.
Trust Issues — TJCTF
Challenge summary
This challenge looked cryptographic at first: the bundled nameserver used custom ECDSA signing on P-521 with algorithm 17, and the obvious first idea was to attack nonce generation. That path was a dead end for us.
The real solution was a web/logic chain in the DNS resolver. By poisoning its cache and exploiting a DNSSEC verification flaw, we made the admin bot resolve trust-issues.tjc.tf to our own HTTPS host and leak the flag in the URL.
Final captured flag:
tjctf{trust_n0_on3_ev3r}
Source review
Relevant files from trust-issues.zip:
admin-bot.jsdnsresolver/app.pydnsresolver/dnssec.pywebsite/app.pywebsite/templates/index.htmlnameserver/app.py
1. The admin bot already gives us the exfiltration primitive
admin-bot.js is the key to the whole challenge:
urlRegex: /^https:\/\/dnsresolver-[a-f0-9]*\.tjc\.tf\//, const response = await fetch(url + '?name=trust-issues.tjc.tf&type=A'); const json = await response.json(); const data = json.data; await page.goto('https://' + data + '?flag=' + flag, ...);
So the bot does three things:
- Accepts only a
dnsresolver-*.tjc.tfURL. - Fetches that resolver with
?name=trust-issues.tjc.tf&type=A. - Takes
json.dataand browses tohttps://<data>?flag=<flag>.
That means we do not need XSS, cookie theft, or browser tricks. If we can make the resolver return our hostname, the bot sends us the flag directly.
2. The website reflects the flag from the query string
website/app.py and website/templates/index.html show that the site simply renders request.args.get("flag"):
return render_template('index.html', flag=request.args.get('flag', None))
and:
<p>{{ flag }}</p>
So the flag is intentionally transported via the URL parameter. Once the bot is redirected to our host, the flag arrives in the request line as:
https://our-host/?flag=tjctf{...}
Why the crypto path was a red herring for the actual solve
nameserver/app.py signs DNSSEC records with algorithm 17 on P-521 and uses:
...
$ grep --similar
Similar writeups
- [web][free]chained— tjctf
- [web][Pro]board_of_secrets— miptctf
- [web][free]Tiny Web smol— gpnctf
- [network][free]offknock— umdctf
- [web][Pro]Board of Secrets Revenge— miptctf