Night Coder - Writeup by AI
1. 题目描述
题目名称 : Night Coder
题目来源 : bugku Crypto
题目类型: 密码学 / Python random 模块分析
题目代码
python
import random
import datetime
from secret import flag
#Im a night coder, i coded this at night (thursday morning)
def seed_shuffler(my_list, seed):
random.seed(seed)
random.shuffle(my_list)
return my_list
seed=int(datetime.datetime.now().strftime('%Y%m%d%H%M'))
flag = [f for f in flag]
enc = seed_shuffler(flag,seed)
print("".join(enc))
#result at that time: "N_gs{aesD_he_3AtrsOLlh3ROT1sECRl0m}s"
2. 考点分析
| 考点 | 分值权重 | 说明 |
|---|---|---|
| Python random 模块原理 | 40% | 理解 Mersenne Twister 算法的确定性 |
| 固定种子伪随机数重现 | 30% | 相同种子产生相同的 shuffle 序列 |
| 时间戳分析 | 15% | 从注释中提取关键时间信息 |
| Flag 格式识别 | 15% | 根据已知格式验证解密结果 |
3. 解题思路
3.1 核心原理
Python 的 random 模块基于 Mersenne Twister 算法,这是一个确定性的伪随机数生成器。关键特性:
- 种子决定性 : 只要
random.seed()的值相同,后续所有shuffle()、randint()等操作产生的序列完全一致 - 可重现性: 即使原始数据被打乱,只要知道种子,就可以重现整个打乱过程
3.2 攻击路径
分析源码 → 提取时间线索 → 枚举可能时间 → 重现 shuffle → 逆置换恢复 → 验证 Flag 格式
3.3 关键线索
- 注释提示:"thursday morning"(周四凌晨)
- 用户提示:2022 年 5 月 25 日凌晨
- Flag 格式:
shellmates{...}(不是标准的flag{...})
4. 详细步骤
4.1 分析加密过程
加密逻辑:
python
flag_chars = [f for f in flag] # 将 flag 转为字符列表
enc = seed_shuffler(flag_chars, seed) # 使用固定种子打乱
这意味着:enc[i] = flag[perm[i]],其中 perm 是 shuffle 后的索引排列
4.2 构造逆置换
要恢复原始 flag,需要应用逆置换:
python
perm = list(range(n))
shuffled_perm = seed_shuffler(perm[:], seed)
recovered = [''] * n
for i in range(n):
recovered[shuffled_perm[i]] = enc_result[i]
4.3 枚举时间范围
2022 年 5 月的所有周四:
- 5 月 5 日 (Thursday)
- 5 月 12 日 (Thursday)
- 5 月 19 日 (Thursday)
- 5 月 26 日 (Thursday) ← 正确答案在这个日期
4.4 编写解题脚本
python
import random
import datetime
import calendar
enc_result = "N_gs{aesD_he_3AtrsOLlh3ROT1sECRl0m}s"
n = len(enc_result)
def seed_shuffler(my_list, seed):
random.seed(seed)
random.shuffle(my_list)
return my_list
# 遍历 2022 年所有周四
for month in range(1, 13):
days_in_month = calendar.monthrange(2022, month)[1]
for day in range(1, days_in_month + 1):
target_date = datetime.datetime(2022, month, day)
if target_date.weekday() != 3: # 只检查周四
continue
for hour in range(24):
for minute in range(60):
seed = int(target_date.replace(hour=hour, minute=minute).strftime('%Y%m%d%H%M'))
# 获取置换排列
perm = list(range(n))
shuffled_perm = seed_shuffler(perm[:], seed)
# 应用逆置换
recovered = [''] * n
for i in range(n):
recovered[shuffled_perm[i]] = enc_result[i]
recovered_str = ''.join(recovered)
# 验证 shellmates{...} 格式
if recovered_str.startswith('shellmates{') and recovered_str.endswith('}'):
print(f"找到 Flag: {recovered_str}")
print(f"时间:{target_date.replace(hour=hour, minute=minute)}")
print(f"种子:{seed}")
exit(0)
4.5 实际输出结果
============================================================
Night Coder - CTF 密码学解题脚本
============================================================
密文:N_gs{aesD_he_3AtrsOLlh3ROT1sECRl0m}s
长度:36 字符
Flag 格式:shellmates{...}
搜索范围:2022 年所有周四的全天时间
种子格式:YYYYMMDDHHMM
正在检查:2022-05-26 Thursday...
✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓
找到 Flag!
时间:2022-05-26 02:13:00
星期:Thursday
种子:202205260213
Flag: shellmates{N1ghT_C0D3Rs_ArE_LOOs3Rs}
✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓
6. 总结
6.1 攻击链图谱
分析源码
发现固定时间种子
提取周四凌晨线索
枚举所有可能时间
重现 shuffle 排列
应用逆置换解密
验证 shellmates 格式
成功获取 Flag
6.2 技术要点
- Python random 模块的安全性问题: 绝不能用干密码学目的
- 时间戳作为种子的风险: 如果时间范围可知,完全可以暴力破解
- 置换密码的特点: 可逆操作,知道排列就能还原
6.3 防御建议
| 场景 | 建议 |
|---|---|
| 安全随机数生成 | 使用 secrets 模块而非 random |
| 种子选择 | 使用加密安全的熵源,避免可预测的值 |
| Shuffle 操作 | 对敏感数据不要使用基于 PRNG 的 shuffle |