2019 De1CTF WriteUp
🏛️ 组织架构
主办方:De1ta 战队
技术支持:赛宁网安
赞助商:华为、天融信、陌陌安全、红帽安全实验室
📊 赛事规模
本次比赛规模盛大,共吸引了来自全球 77 个国家和地区的 1362 支队伍参赛
🏆 比赛结果
| 排名 | 队伍名称 | 解题数 | 总分 |
|---|---|---|---|
| 1 | Whitzard (复旦大学) | 23 | 11226 |
| 2 | 0ops (上海交通大学) | 21 | 9117 |
| 3 | Balsn (中国台湾) | 20 | 8852 |
| 4 | NU1L (联合战队) | 18 | 7559 |
| 5 | Venom | 17 | 7016 |
| 6 | AAA | 16 | 6569 |
| 7 | W&M | 17 | 6526 |
| 8 | 天枢 | 17 | 6169 |
| 9 | Vidar-Team | 16 | 5039 |
| 10 | bi0s | 16 | 4947 |
Crypto
xorz(重复密钥 XOR)

加密逻辑是
1 | cipher[i] = plain[i] ^ key[i % len(key)] ^ salt[i % len(salt)] |
其中 salt 已知,所以先异或回去
1 | tmp[i] = cipher[i] ^ salt[i % 14] |
得到
1 | tmp[i] = plain[i] ^ key[i % len(key)] |
这就变成了经典的 repeating-key XOR。因为明文是英文长文本,key 长度又小于 38,所以可以用英文频率分析、重合指数 IC、汉明距离或者 printable 约束恢复 key
去 salt 后,对 key_len = 2..37 分组
1 | subs = [cipher[i::key_len] for i in range(key_len)] |
每一组都相当于被同一个 key 字节 XOR 的英文字符列,所以正确 key_len 下,各列的英文统计特征会更明显
拿到 key_len = 30 后,每一位单独爆破
1 | for pos in range(30): |
1 | from itertools import cycle |
Reverse
Mine Sweeping(Unity)

打开附件可以看到这是一个 Unity 游戏,Unity C# 题的核心逻辑通常都在 Mine Sweeping_Data/Managed/Assembly-CSharp.dll
直接用 dnSpy 反编译,其中
1 | Elements 单个格子的逻辑 |

在 Elements.Awake() 中有一段非常关键的判断
1 | private void Awake() |
也就是 “雷” 的生成逻辑是先异或,再减 233,再整除 2333
思路一是通过这一步直接逆向写脚本生成所有雷所在的位置,但是很麻烦,我们可以直接 patch 游戏逻辑
比如修改 OnMouseUpAsButton()
1 | private void OnMouseUpAsButton() |
我们可以完全取消输赢判断
1 | using System; |

最后保存模块

这样子最后会得到一张二维码图片,但还是需要手动点击

熟悉这个流程过后我们可以直接修改 Elements.Awake() 逻辑
1 | private void Awake() |

最后得到 flag:de1ctf{G3t_F1@g_AFt3R_Sw3ep1ng_M1n3s}