preeeetham/solana-ctf

GitHub: preeeetham/solana-ctf

一套包含 14 个 Solana 智能合约 CTF 挑战及完整题解的安全学习仓库,帮助开发者通过实战掌握 Solana 链上常见漏洞模式。

Stars: 0 | Forks: 0

# 🏴 Solana CTF — 夺旗赛挑战与题解 一份精心整理的 **14 个基于 Solana 的夺旗赛 (CTF)** 挑战合集,包含完整题解、漏洞利用脚本以及一份详尽的智能体指南。这些挑战涵盖了真实的 Solana 漏洞模式——从缺少 signer 检查到 DeFi预言机操纵——所有挑战均部署在 Solana **Devnet** 上。 ## 📂 仓库结构 ``` solana-ctf/ ├── challenge-1/ # Ghost Admin (100 pts) — Missing signer check ├── challenge-2/ # Good First Impression (100 pts) — Vanity address grind ├── challenge-3/ # Logs of Truth (100 pts) — Input-dependent log emission ├── challenge-4/ # The Birthday Seed (100 pts) — Genesis timestamp PDA ├── challenge-5/ # Named by Numbers (200 pts) — Account data parsing ├── challenge-6/ # Signature Safari (200 pts) — Ed25519 verification ├── challenge-7/ # The Lamport Clock (200 pts) — Lamport value as timestamp ├── challenge-8/ # Where is the Needle? (250 pts) — Mass PDA account scanning ├── challenge-9/ # (Integer Overflow) (300 pts) — Arithmetic overflow ├── challenge-10/ # Monkeys and Bananas (250 pts) — NFT metadata tracing ├── challenge-11/ # Do Not Claim Thyself (300 pts) — Creator vs caller exploit ├── challenge-12/ # Voucher Roulette (300 pts) — MD5 hash brute-force ├── challenge-13/ # (Steganography) (400 pts) — RGB steganography ├── challenge-14/ # Sus Protocol (400 pts) — DeFi take_while vs filter bug │ ├── SOLUTIONS.md # Detailed write-ups for all solved challenges ├── CTF_V2_SPEC.md # Predicted v2 challenges (harder successors) ├── SOLANA_CTF_AGENT_GUIDE.md # Full agent knowledge base for solving CTFs ├── solutions_dashboard.html # Visual dashboard of all challenge scores ├── package.json # Node.js dependencies ├── tsconfig.json # TypeScript configuration └── ctf_wallet.json # CTF solver wallet (DO NOT COMMIT REAL FUNDS) ``` 每个 `challenge-N/` 目录通常包含: - `question.txt` — 挑战题目与提示 - `public_source.rs` — 已部署的 Solana program 的 Rust 源码(如果提供) - `solve.ts` — 漏洞利用/解题 TypeScript 脚本 - `explore*.ts` — 用于链上侦察的探测脚本 ## 🏆 积分榜 | # | 标题 | 积分 | 漏洞 | Flag | |---|-------|--------|---------------|------| | 1 | Ghost Admin | 100 | 缺少 signer 检查 (`UncheckedAccount`) | `ST_FLAG{trust_n0_pubk3y}` | | 2 | Good First Impression | 100 | 个性化地址前缀检查 | `ST_FLAG{k3yp41r_gr1nd1ng_ch4mp}` | | 3 | Logs of Truth | 100 | 通过 `msg!()` 依赖输入输出 flag | `ST_FLAG{1sol_2sol_3sol_truth}` | | 4 | The Birthday Seed | 100 | 使用 Solana 创世时间戳作为种子的 PDA | `ST_FLAG{ep0ch_0}` | | 6 | Signature Safari | 200 | 跨越 500 个配对的 Ed25519 验证 | `ST_FLAG{s1g_ch4mp_d1d_th3_d1ff}` | | 7 | The Lamport Clock | 200 | Lamport 转账金额作为 Unix 时间戳 | `ST_FLAG{a_ba1ance_b0rn_in_2006}` | | 8 | Where is the Needle? | 250 | 使用 `getProgramAccounts` 扫描 500 个 PDA | `ST_FLAG{pda_hunt1ng_m4st3r}` | | 10 | Monkeys and Bananas | 250 | NFT 交易链追踪 | `ST_FLAG{ca11ern0tc4eat0r}` | | 11 | Do Not Claim Thyself | 300 | 调用者 ≠ 创建者 program 区分 | `ST_FLAG{ca11er_n0t_creat0r}` | | 12 | Voucher Roulette | 300 | 逐位置 MD5 哈希暴力破解 | `ST_FLAG{g00d_on3}` | | 14 | Sus Protocol | 400 | `take_while` 与 `filter` 引发的 DeFi 借贷漏洞 | `ST_FLAG{t00k_y0u_a_wh1le}` | **累计得分:2300+ 积分** ## ⚡ 快速开始 ### 前置条件 - **Node.js** ≥ 18 - **Solana CLI**(用于生成钱包及进行 CLI 交互) - **TypeScript** / `ts-node` ### 1. 安装依赖 ``` npm install ``` ### 2. 设置解题钱包 ``` # 生成新的 keypair solana-keygen new --outfile ctf_wallet.json --no-bip39-passphrase # 将 Solana CLI 指向 Devnet solana config set --url devnet --keypair ctf_wallet.json # Airdrop 测试 SOL solana airdrop 5 # 或访问 https://faucet.solana.com ``` ### 3. 运行题解脚本 每个挑战都有各自的 `solve.ts` 脚本。例如: ``` # 解决 Challenge 1 (Ghost Admin) npx ts-node challenge-1/solve.ts # 解决 Challenge 14 (Sus Protocol) npx ts-node challenge-14/solve.ts ``` ## 🔍 挑战概述 ### 挑战 1 — Ghost Admin ★☆☆☆☆ **漏洞:** `admin` 账户使用了 `UncheckedAccount<'info>` 而非 `Signer<'info>`。该 program 检查了 `admin.key() == vault.admin`,但从未验证该账户是否实际签署了交易。 **利用方式:** 将 admin 的公钥作为 `admin` 账户传入,但无需使用它进行签名。 ### 挑战 2 — Good First Impression ★☆☆☆☆ **漏洞:** 该 program 要求交易 signer 的公钥必须以 `bo1t` 开头。 **利用方式:** 运行 `solana-keygen grind --starts-with bo1t:1`,为生成的钱包充值,并使用它进行签名。 ### 挑战 3 — Logs of Truth ★☆☆☆☆ **漏洞:** `verifyNumber` 指令会在特定的 lamport 输入值(1 SOL、2 SOL、3 SOL)下,通过 `msg!()` 输出部分 flag 字符串。 **利用方式:** 分别传入 `1_000_000_000`、`2_000_000_000` 和 `3_000_000_000` 来调用该指令,并拼接日志片段。 ### 挑战 4 — The Birthday Seed ★☆☆☆☆ **漏洞:** Vault PDA 是使用 Solana 的创世区块时间戳(`1584368940`)作为种子派生出来的。 **利用方式:** 使用 `seeds = [b"vault", 1584368940_u64.to_le_bytes()]` 派生该 PDA,并读取其中存储的 flag。 ### 挑战 6 — Signature Safari ★★☆☆☆ **漏洞:** 提供了 500 个 `signature::message` 配对;其中只有一个是给定公钥的有效 Ed25519 签名。 **利用方式:** 使用 `tweetnacl` 的 `sign.detached.verify()` 遍历所有配对以找到有效的那一个,然后在 Devnet 上查找该交易。 ### 挑战 7 — The Lamport Clock ★★☆☆☆ **漏洞:** 一个特定的钱包转账了 `1152684000` lamports,这是一个表示 2006 年 7 月 12 日日期的 Unix 时间戳。 **利用方式:** 将 lamport 金额解码为 Unix 时间戳,推导出具体日期,并将其 POST 到 CTF 的提交端点。 ### 挑战 8 — Where is the Needle? ★★☆☆☆ **漏洞:** 该 program 拥有的 500 个 PDA 账户中,其中一个包含了 flag。 **利用方式:** 使用 `getProgramAccounts` 获取所有账户,对每个账户进行反序列化(8 字节 discriminator + 32 字节 flag + 4 字节索引),并搜索 `ST_FLAG`。 ### 挑战 10 — Monkeys and Bananas ★★★☆☆ **漏洞:** flag 被隐藏在 NFT 创建链的交易历史记录中,而不是在 NFT 本身。 **利用方式:** 追踪 NFT → 更新权限 → 资金钱包 → program 交互 → `ClaimFlag` 指令日志的路径。 ### 挑战 11 — Do Not Claim Thyself ★★★☆☆ **漏洞:** 该 program 会奖励不是 token 创建者的调用者。flag 在第一笔 `GetEntry` 交易的日志中被输出。 **利用方式:** 从该 program 有史以来的第一笔交易签名中读取交易日志。 ### 挑战 12 — Voucher Roulette ★★★☆☆ **漏洞:** 该 program 通过独立计算每个位置的 `MD5(char + position_index)` 来验证一个 17 字符的代码。每个位置都可以单独进行暴力破解。 **利用方式:** 对于每个位置(0–16),尝试所有 256 个字节值,计算 MD5,并与 `EXPECTED_HASHES[i]` 进行比较。 ### 挑战 14 — Sus Protocol ★★★★☆ **漏洞:** 一个 DeFi 借贷协议使用 `.take_while()` 计算可见头寸(在遇到 `Pubkey::default()` 间隔时停止),但使用 `.filter()` 验证漏洞利用条件(检查所有头寸)。从中间位置提取头寸会制造一个视觉盲区。 **利用方式:** 存款 → 关闭中间头寸 → 越过间隔再次存款 → 针对“不可见的”真实抵押品进行多次借款,直到 `real_loans > max_allowed * 2`。 ## 📚 核心文档 | 文件 | 描述 | |------|-------------| | [`SOLUTIONS.md`](./SOLUTIONS.md) | 所有 11 个已解挑战的详细步骤记录,包含终端输出及获得的 flag | | [`CTF_V2_SPEC.md`](./CTF_V2_SPEC.md) | 预测的 v2 挑战(每个 v1 挑战的难度进阶版,总计 5,500 积分) | | [`SOLANA_CTF_AGENT_GUIDE.md`](./SOLANA_CTF_AGENT_GUIDE.md) | 完整知识库:Solana 基础知识、探测手册、漏洞目录、漏洞利用模板 | | [`solutions_dashboard.html`](./solutions_dashboard.html) | 可视化所有挑战分数和解题方案的交互式 HTML 仪表盘 | ## 🛠️ 技术栈 | 工具 | 用途 | |------|---------| | **TypeScript** + `ts-node` | 漏洞利用脚本编写和链上交互 | | **`@coral-xyz/anchor`** | 用于 program 交互的 Anchor 框架客户端 | | **`@solana/web3.js`** | 底层 Solana RPC 调用 | | **`tweetnacl`** | Ed25519 签名验证 | | **`pngjs`** | PNG 图像解析(隐写术挑战) | | **Solana CLI** | 钱包管理、空领、交易检查 | ## 🔑 漏洞模式参考 | 模式 | 对应挑战 | 核心概念 | |---------|-------------|-------------| | 缺少 signer 检查 | 挑战 1 | `UncheckedAccount` 与 `Signer` 对比 | | 个性化地址暴力生成 | 挑战 2 | `solana-keygen grind` | | 依赖输入的日志输出 | 挑战 3 | 带有特定输入的 `msg!()` | | 作为 PDA 种子的历史链上数据 | 挑战 4 | Solana 创世时间戳 `1584368940` | | Ed25519 签名验证 | 挑战 6 | `tweetnacl.sign.detached.verify()` | | Lamport 值编码 | 挑战 7 | Lamports 作为 Unix 时间戳 | | 海量 PDA 账户扫描 | 挑战 8 | `getProgramAccounts` + `memcmp` 过滤 | | NFT/交易链追踪 | 挑战 10 | 多跳账户关系图谱 | | 创建者与调用者区分 | 挑战 11 | Program CPI 身份校验 | | 哈希暴力破解(按位置) | 挑战 12 | `(char + index)` 的 MD5 | | DeFi 迭代器不匹配 | 挑战 14 | `take_while` 相比 `filter` 制造了盲区 | ## 🔮 v2 挑战(预测版) [`CTF_V2_SPEC.md`](./CTF_V2_SPEC.md) 记录了每个挑战的预测 **v2** 版本——旨在修复 v1 中被利用的漏洞。总计:涵盖 14 个难度更高挑战的 **5,500 积分**(对于经验丰富的 Solana 开发者约需 30–50 小时)。 | v1 漏洞利用 | v2 漏洞利用 | |-----------|-----------| | 缺少 signer 检查 | 重新初始化覆盖 | | 简单前缀暴力生成 | PDA 派生前缀暴力生成 | | 读取 `msg!()` 日志 | 解码 `set_return_data()` + XOR 解密 | | 单一创世时间戳 | 多源链上考古 | | 扁平化 Borsh 结构 | 版本化 schema + 加密 | | 简单 Ed25519 验证 | 部分签名重构 | | 500 个账户,1 个 flag | 50,000 个账户,100 个诱饵 + bump 验证 | | `take_while` 与 `filter` | 通过未验证账户进行预言机价格操纵 | ## ⚠️ 免责声明 本仓库仅供**教育目的**使用。所有挑战均在 Solana **Devnet**(测试网)上运行,不包含任何实际价值。此处展示的漏洞利用技术是 CTF 比赛和安全研究中常见的漏洞模式。请勿将这些技术应用于主网 program 或真实资产。 ## 📄 许可证 MIT
标签:Anchor, MITM代理, Solana, TypeScript, 区块链安全, 可视化界面, 后端开发, 安全插件, 智能合约审计