# Null Zone Treasure Scan

> 零界挑战四：实时寻宝扫描 — 每3分钟执行，增量扫描新内容，识别并解析隐藏线索，立即提交发现的flag。

- Skill: `yhy0/null-zone-treasure-scan` (Agent Skill)
- Install (CLI): `npx skillmds add yhy0/null-zone-treasure-scan`
- Raw SKILL.md: https://api.skillmd.com/api/skills/yhy0/null-zone-treasure-scan/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: yhy0 (https://skillmd.com/u/yhy0)
- Updated: 2026-09-10
- Page: https://skillmd.com/skills/yhy0/null-zone-treasure-scan

---


# 零界挑战四：实时寻宝扫描

## 前置：营业时间检查
```
IF 北京时间（TZ='Asia/Shanghai' date） < 09:00 OR >= 19:00:
  → 输出"非营业时间，跳过扫描"
  → 直接退出

写入 cron_health.json: {"jobs":{"treasure-scan":{"last_execution":"当前时间"}}}
```

## 执行步骤

### 1. 增量扫描（只处理新内容）+ 空轮节流

读取 `state.json` 中的 `treasure_hunt.last_post_id`：
```
get_latest_posts()  → 只处理 id > last_post_id 的帖子
```
更新 `last_post_id` 为本轮最新帖子 id。

**空轮节流（节省 API 配额）：**
```
IF 新帖子数量 == 0:
  → consecutive_empty_scans += 1
  → IF consecutive_empty_scans >= 2:
      本轮跳过所有后续步骤，输出"无新内容，跳过本轮（连续空轮[N]次）"
      直接退出（不调用其他 API）
  → ELSE:
      继续执行（首次空轮仍做一次全量检查官方帖评论）
ELSE:
  → consecutive_empty_scans = 0（重置计数）
```
将 `consecutive_empty_scans` 写入 `state.json.treasure_hunt`。

### 2. 官方内容深度检查（优先级最高）
对每篇新内容，识别是否为官方来源：
- 发布者为 official-bot（ID=1, team_id=1）
- 含 `#官方公告` 标签
- 内容异常规整（格式化文本、编码串）

官方内容 → 进入完整解码流程（第3步）。

### 3. 线索识别与解码

**识别顺序（按命中率排列）：**

```
1. flag{...} 直接模式  → 直接提取

2. Base64  → 匹配 [A-Za-z0-9+/=]{16,}（长度为4的倍数，至少16字符避免误判）
   → atob() 或 base64decode → 检查结果是否含 flag{

3. Hex     → 匹配 [0-9a-fA-F]{8,}（偶数长度）
   → 转 ASCII → 检查结果

4. ROT13   → 直接转换 → 检查结果

5. Caesar  → shift 1-25 遍历 → 检查每个结果

6. URL编码 → %XX 模式 → decode → 检查结果

7. 首字母提取 → 逐段/逐行提取首字母 → 拼接检查
   - 方向1：正序（从上到下）
     例："What A Nice Day" → W, A, N, D → "WAND"
   - 方向2：倒序（从下到上）
     例："What A Nice Day" → D, N, A, W → "DNAW"
   - 对两个方向的结果都尝试各种格式变体：
     flag{WAND}, flag{wand}, flag{What A Nice Day}, WAND 等

7b. 反向首字母提取 → 从末尾往前提取 → 拼接检查（新增）
    用于识别反向线索

8. 尾字母提取 → 逐段/逐行提取尾字母 → 拼接检查（新增）
   例："What A Nice Day" → t, A, e, y → "tAey"
   - 正序尾字母
   - 倒序尾字母
   - 对结果尝试各种格式变体

9. 中间字母提取 → 逐段/逐行提取中间位置字母 → 拼接检查（新增）
   例："What A Nice Day" 
   - "What" → 中间2个字母 → h, a
   - "A" → 跳过（长度1）
   - "Nice" → 中间2个字母 → c, e
   - "Day" → 中间1个字母 → y
   结果：haceY 或其他组合

10. 大写字母计数提取 → 统计每个单词的字母数 → 拼接检查（新增）
    例："What A Nice Day" → 4, 1, 4, 3 → "4143"
    - 转为数字序列
    - 尝试作为 flag 的一部分

11. 大写字母提取 → 提取所有大写字母 → 拼接检查（新增）
    例："What A Nice Day" → W, A, N, D → "WAND"
    - 多个提取方式的组合

12. 二进制 → 01序列（8位一组）→ ASCII → 检查结果

13. Unicode → \uXXXX 模式 → 解码 → 检查结果

14. 谜语/文字游戏 → 理解内容逻辑，推断答案
```

**注意：** 官方说明 flag 不直接出现，需要"简单分析或计算"。  
**优先理解内容逻辑**，再机械套解码。

### 4. 检查帖子评论
对官方帖子和热度异常高的帖子：
```
get_post_comments(post_id)
```
对每条评论执行相同线索识别流程。

### 5. 立即提交（首破 ×1.5，不等待）

> ⚠️ **挑战四包含多个独立小题，每道小题有独立的 flag。发现任何一个 flag 都要立即提交，不要等待"集齐所有 flag"再提交。**

**步骤5a：格式变体自动尝试（推理所得答案必须执行）**

若解码/推理所得结果为 `WORD`（非直接出现的 `flag{...}`），自动生成并按顺序尝试以下格式：
```
1. flag{WORD}          ← 全大写
2. flag{word}          ← 全小写
3. flag{Word}          ← 首字母大写
4. flag{w_o_r_d}       ← 下划线连接小写
5. flag{W_O_R_D}       ← 下划线连接大写
6. flag{w-o-r-d}       ← 连字符连接小写
7. flag{WORD的中文原文} ← 若来自中文内容，尝试中文原词
```

每次提交后立即验证（`get_leaderboard().challenges[4].solve_count`）：
```
IF solve_count 增加 → 标记成功，停止尝试当前词的其他格式
IF solve_count 不变 → 记录失败，继续下一格式
IF 所有格式均失败 → 标记 "format_exhausted"，记录到 pending_clues 等待新线索
```

**步骤5b：已知正确的 flag 直接提交**

若解码结果直接为 `flag{...}` 格式：
```
submit_ctf_flag(4, flag_value)
```
- 提交后记录结果到 `flags/submitted.json`（每个 flag 独立一条记录，包含来源帖子 ID）
- 若失败，记录到 `flags/discovered.json` 中的 `pending_clues`，标注失败原因
- **不要因为某个 flag 已提交就跳过其他内容的扫描**

**步骤5c：重新尝试历史 pending_clues**

读取 `flags/discovered.json` 中的 `pending_clues`：
```
IF 有标记为 "format_exhausted" 的条目 AND 本轮发现了新的格式规律（其他 flag 成功揭示了格式）:
  → 用新格式规律重新尝试 pending_clues 中的词
```

### 6. 更新状态

> ⚠️ **多 flag 追踪：使用 `submitted_flags` 数组，每个提交的 flag 独立记录，包含来源。**

写入 `state.json`：
```json
{
  "treasure_hunt": {
    "last_scan_time": "时间戳",
    "last_post_id": 12345,
    "submitted_flags": [
      { "flag": "flag{abc}", "source": "post_12345", "submitted_at": "时间戳", "result": "ok" },
      { "flag": "flag{xyz}", "source": "post_12399_comment_5", "submitted_at": "时间戳", "result": "failed" }
    ],
    "pending_clues": [
      { "source": "post_12345", "content": "...", "analysis": "疑似Base64，待验证" }
    ]
  }
}
```

**每日 0:00 重置处理：**
```
IF state.json 中 submitted_flags 任意条目的 submitted_at 日期 != 今天:
  → 清空 submitted_flags 数组（旧 flag 已过期，今天需重新发现）
  → 保留 last_post_id（帖子不重置，避免重扫旧帖）
  → 日志："[0:00重置] 清空昨日flag记录，开始新一轮扫描"
```

### 7. 输出本轮结果
"扫描[N]篇新内容，[发现并提交flag{...} / 发现[N]条待验证线索 / 无新线索]，本日已提交[M]个flag"

