UMDCTF 2026 - insider-info
A mysterious DNS server is running on the inside. It holds a secret — but you'll need to be clever to extract it all.
Hint: Can you ask more than one question at a time?
DNS 基础
1. DNS 消息长什么样
DNS 消息在网络上是二进制数据,分五段:
1 | +------------------------+ |
Header 里最重要的四个字段是计数,告诉解析器每个区有多少条目:
1 | QDCOUNT — 问题区有几个问题 |
一般情况下 QDCOUNT=1,每次只问一个问题。
2. 域名在消息里不是字符串
域名不是直接写 www.example.com。它按 .
拆成标签(labels),每个标签前加 1 字节长度:
1 | www.example.com 编码为: |
记这个编码方式,后面解压缩要用到。
3. DNS 名称压缩——核心机制
同一个域名后缀会在一个消息里反复出现(问题区一个、回答区可能好几个)。每次都完整编码很浪费空间。
解决方案:用 2 字节的指针代替重复标签。
指针怎么和标签区分?标签长度字节的高 2 位是标识位:
| 高 2 位 | 含义 |
|---|---|
| 00 | 普通标签(长度 0-63) |
| 11 | 压缩指针 |
普通标签最长 63 字节,二进制
00111111,高两位永远00。所以用11做指针标识不会混淆。
指针格式:
1 | 1 1 | 14-bit OFFSET |
高 2 位 = 11 → 第一字节 ≥ 192 (0xC0) 低 14 位 =
从消息开头算起的偏移量
举例:0xC0 0x0C - 0xC0 =
11000000 → 是指针 - 低 14 位 = 12 → 指向消息偏移 12
的位置
域名可以部分用标签、部分用指针拼接:
FOO.example.com 如果 .example.com
已经在前面出现过:
1 | [3] 'F' 'O' 'O' + [指针指向.example.com的位置] |
甚至可以整个域名只用一个指针指向之前出现过的相同域名。
4. 一个消息可以问多个问题吗?
可以。QDCOUNT 字段可以大于 1。
不过传统 DNS 服务器通常不支持(RFC 9619 甚至禁止了),但自定义 DNS 服务器可以自己处理。这题的服务端就支持。
5. TCP 也能跑 DNS
常规 DNS 用 UDP 端口 53,但 TCP 也行。
| UDP | TCP | |
|---|---|---|
| 消息前缀 | 无 | 2 字节长度(大端)+ 消息体 |
| 大小限制 | 512 字节传统上限 | 无实际限制 |
| 使用场景 | 普通查询 | 大响应、zone transfer |
TCP 传输时:先发 2 字节告诉我们接下来有多少字节的 DNS 消息,再发消息体。
Challenge Overview
题目给了一个自定义 DNS 服务器(监听 TCP),每次连接生成一个 819 字符的随机 secret。
服务器接受两种 TXT 记录查询:
- 单字符查询:查
<N>.inside.info(N 是 0~818)→ 返回第 N 位的字符 - 完整 secret 查询:查
完整secret(用点分63字符块).inside.info→ 返回 flag
限制:每个连接只能发 2 次 DNS 查询,新连接生成全新 secret。
分析
要拿到 819 个字符,但只许问 2 次。意味着第一次查询要一次性提取全部字符。
每次查一个(0.inside.info → 拿字符
0,1.inside.info → 拿字符
1...)如果每个都单独发一次查询,需要 819 次,显然不行。
思路
利用 QDCOUNT > 1,把 819 个问题全塞进一个 DNS 消息:
1 | 一条消息里: |
服务端收到 QDCOUNT=819,逐个回答,一次返回 819 个字符。
如果不压缩,每个 question: - 0.inside.info 的域名编码 ≈
16 字节 - QTYPE(2) + QCLASS(2) = 4 字节 - 共 ≈ 20 字节
819 × 20 = 16,380 字节 → 太大了。
819 个 question 共享同一个后缀
.inside.info。
把 .inside.info
的完整标签编码放在消息末尾,每个 question 用2
字节指针指向它:
1 | 未压缩的 0.inside.info: |
每个 question 从 ~20 字节压缩到 ~7 字节。
819 × 7 ≈ 5,700 字节,TCP 消息完全装得下。
攻击流程
Query 1 — 塞入 819 个压缩 question:
1 | Header: QDCOUNT=819 |
服务器回复 819 条 TXT 记录,每条一个字符。拼接出完整 secret。
Query 2 — 查 完整secret.inside.info →
拿到 flag。
Exploit Code
1 | import struct |
关键点总结
| 概念 | 在这道题里的作用 |
|---|---|
| QDCOUNT > 1 | 一个消息塞 819 个问题,一次拿到全部字符 |
| 名称压缩(指针) | 每个 question 共享 .inside.info 后缀,大小从 20
字节降到 7 字节 |
| TCP 传输 | 消息太大放不进 UDP,用 TCP 的 2 字节长度前缀可靠传输 |
| TXT 记录 | 服务器用 TXT 返回单字符,1 字节长度前缀 + 1 字节字符 |