2026 ctfshow 新年赛
2026-08-22 20:05:38
热身签到
1 | s = '54515552545455515456547055555566545654495548554855575370515051485150515453705555545755525456537054515551515051485150515450495568' |
ctfshow{happy_2026_with_cs2026!}
happy2026
1 | <?php |
Step1:绕过 if 条件判断
条件要求同时满足三个条件:
| 条件 | 含义 | 绕过方式 |
$year == 2026 |
松散比较等于 2026 | 字符串 "2026"与整数 2026松散比较为 true |
$year !== 2026 |
严格比较不等于 2026 | 字符串 "2026"与整数 2026类型不同,严格比较为 true |
is_numeric($year) |
必须是数字 | 字符串 "2026"是合法数字字符串,返回 true |
PHP 弱类型比较
GET 参数默认为字符串类型,所以传入 year=2026 时,$year 的值为字符串 "2026":
"2026" == 2026→true(松散比较会进行类型转换)"2026" !== 2026→true(严格比较要求类型和值都相同,字符串 ≠ 整数)is_numeric("2026")→true
三个条件全部满足,成功进入if分支
Step2:控制文件包含路径
进入 if 后执行:
1 | include $happy[$new[$year]]; |
这里 $happy、$new 都是通过 GET 传入的,可以用 PHP 数组传参的方式控制:
$year = "2026"- 传入
new[2026]=a,则$new[$year] = $new["2026"] = "a" - 传入
happy[a]=目标文件,则$happy[$new[$year]] = $happy["a"] = 目标文件
最终 include 的就是我们指定的文件路径。
Step3:利用 php://filter 读取 flag
使用 php://filter 伪协议以 base64 编码方式读取文件内容,避免 PHP 代码被执行而无法看到源码:
1 | happy[a]=php://filter/read=convert.base64-encode/resource=/var/www/html/flag.php |
paylord
1 | https://145f47cc-c14f-4610-8f8f-9785636cb44c.challenge.ctf.show/?year=2026&new[2026]=a&happy[a]=php://filter/read=convert.base64-encode/resource=/var/www/html/flag.php |
返回的 base64 内容:
1 | PD9waHAgJGZsYWc9J2N0ZnNob3d7NGUyNWQyMGYtYTFlYy00YjQ3LWJkZmUtYmJmOTM3ZGQyZjU2fSc7Cg== |
解码后:
1 | <?php $flag='ctfshow{4e25d20f-a1ec-4b47-bdfe-bbf937dd2f56}'; |
1 | ctfshow{4e25d20f-a1ec-4b47-bdfe-bbf937dd2f56} |
SafePIN
高等级身份验证识别系统,一个Web的系统,一个Misc的音频分析。
已经拦截了嫌疑人的密码音频 record.wav,需要还原最终 6 位 PIN。

阅读js代码,可以获得这些信息:
1. 会话初始化
页面加载时依次请求:
/init.php— 初始化会话,获取 Cookie(CID+CID_SIG)/seed.php— 获取当前会话的seed、token和record_url
2. 数字到音色的映射
每个数字 0-9 通过 permute_0_9(seed) 函数映射到一个 soundId(0-9):
1 | async function permute_0_9(seed){ |
其中 prng_u32(seed, tag) 是对 SHA256(seed + "|" + tag) 取前 8 个 hex 字符转为小端序 uint32。
3. 音色参数生成
每个 soundId 对应不同的基频:
1 | async function soundParams(seed, soundId){ |
关键点:每个 soundId 的基频 base 是可以通过 seed 精确计算的。
4. 特殊按键
soundId = 10→ Cancel(清空已输入的 PIN)soundId = 11→ Enter(提交 PIN)
5. 验证接口
POST /check.php,body 为 {"pin": "xxxxxx"},正确返回 flag。
exp
1 | # 1. 在同一个 HTTP Session 中完成 init → seed → 下载 record.wav |
音频分析结果示例
以某次会话为例,record.wav 中检测到 11 个音段:
| # | 时间 | 主频率 | soundId | 操作 |
| 0 | 0.220s | 1242.9Hz | 9 | digit=8 |
| 1 | 0.380s | 1128.1Hz | 5 | digit=6 |
| 2 | 0.550s | 1059.4Hz | 1 | digit=2 |
| 3 | 0.710s | 1257.1Hz | 10 | CANCEL |
| 4 | 0.900s | 1260.7Hz | 8 | digit=4 |
| 5 | 1.060s | 1260.7Hz | 8 | digit=4 |
| 6 | 1.220s | 1121.9Hz | 2 | digit=7 |
| 7 | 1.390s | 1128.1Hz | 5 | digit=6 |
| 8 | 1.550s | 1242.9Hz | 9 | digit=8 |
| 9 | 1.710s | 1231.2Hz | 7 | digit=5 |
| 10 | 1.870s | 1289.3Hz | 11 | ENTER |
操作模拟:
- 输入
862→ 被 CANCEL 清空 - 输入
447685→ ENTER 提交 - 最终 PIN =
447685✅
1 | ctfshow{298886a8-c9e7-4dd0-aa84-568de814bc27} |