WeChall - Snake
Challenge
WeChall Snake(by Gizmore and lazer, 2010):Java Applet
贪吃蛇游戏,目标 "reach exactly 300000
points"。没有答案提交框——玩家在 Applet
里玩完游戏,客户端把成绩加密提交到
CGI_Highscore.php,完成判定完全靠服务端校验提交构型是否"真实可达成"。
1 | https://www.wechall.net/en/challenge/snake/index.php |
Solution
向 CGI_Highscore.php 发送加密的 HT_RATE +
HT_INSERT 请求,INSERT 一个完全自洽的
300000 分构型:
- GET 挑战页(记录游戏开始时间)
- 等待 ≥ 300 秒
- HT_RATE score=300000(返回 rank,写 trixx.txt)
- HT_INSERT score=300000(7 秒内):
- K=10(字母轮数)→ M = 1.0 + 0.5K = 6.00
- B=250, C=250, H=0 → L = 14 + 4B + 6C - 2H + 5K = 2564
- md5 = MD5("250:250:0:2564:300000").upper()
- name=<你的用户名> & sessid=
分析过程
1. 协议逆向
Applet(snake.jar)与 CGI_Highscore.php 的通信:
- body =
encrypted=URLEncode(GWF_Crypt(payload, "Snake$Poors!")) - GWF_Crypt:
out[i] = key[ki % len] ^ c ^ 101;key 索引按递增步长循环(每轮 wrap 后步长 +1,越过 keylen 复位为 1) - payload:
cmd=HT_INSERT&score=&name=&length=&hemps=&cherries=&bananas=&multi=&md5=&sessid= - md5 =
MD5("bananas:cherries:hemps:length:score").toUpperCase() - 命令:
HT_RATE(评分+写 trixx)、HT_INSERT(写榜)、HT_HOTD(英雄日)、HT_UNREQUEST
2. 服务端规则
snake.gizmore.org 原站 PHP 短标签未开启 → 源码直接泄露,可与线上行为交叉验证。
1 | HT_Rate(): rank = 分数在榜排名;rank ≤ 100 时把 "time:score" 写入 trixx.txt |
时间检测:除 RATE/INSERT
窗口外,还有最小游戏时长检查——从 HT_HOTD 到
HT_RATE
的间隔必须达到一定时长,且随分数增大
3. 计分规则(从 applet 字节码逆向)
- banana=250 分/+4 长、cherry=750/+6、hemp=500/-2、字母=100/+1
- multiplier = 1.0 + 0.5×K(K = 集齐 5 个字母食物的轮数)
- 字母分合计 A(K) = 500K + 125K(K-1)
- 死亡动画 effectDie() 每帧 score += 10×L
- 蛇长 L = 14 + 4B + 6C − 2H + 5K
- 得分可达区间 [10L + A + Σ, 10L + A + M×Σ],Σ = 250B + 750C + 500H
线上版 CGI 比仓库版多了反作弊:分数 ≥ 300000 的记录会被标记
user_thief.png(Cheater)图标,且不会触发
solved。检测本质是 "golden ratio" 比例检查(M 与 K
自洽、计数合理性),不查 10
整除性、不做严格代数校验。被标记的构型共同点:
- M 与 K 不自洽(如 K=46 但提交 M=20.00,应为 24.0)
- 食物计数离谱(H=394、C=319 —— 真实游戏不可能)
- score 超出构型可达区间(失败构型的共同点;服务端给检测留了 margin,但偏离太多照样标)
Script
1 | #!/usr/bin/env python3 |