Writeup 4 PCTF — Leonidas left message
题目信息
- 题目名称:Leonidas left message
- Author:HxN0n3
- 难度:Easy
- 题目描述:
The 300 Spartans as fighting entirely alone. In reality, King Leonidas led a coalition of roughly 6,000 to 7,000 Greek allies, including hundreds of Thespians and Thebans who also stayed and died in the final stand.
Leonidas left message
u(x/&B(FICB"qCGqWFG-qIzC"yqt)Iq"EEvqIBq}`Biq(zEq&)~EG1Flag format:
pctf{...}
一、初步观察
拿到密文:
u(x/&B(FICB"qCGqWFG-qIzC"yqt)Iq"EEvqIBq}`Biq(zEq&)~EG1字符集包含:
- 小写字母:
u x q z y t v i - 大写字母:
B F I C G W E - 符号:
( / & " - ) }( ) ~` - 数字:
1
字符分布很不自然,大量出现q、I、B、E等,且没有任何空格或常见英文单词痕迹。Flag 格式是pctf{...},但密文中没有{,反而出现了},说明密文经过了某种整体变换。
二、寻找关键线索
题目描述反复强调两个数字:
- 300 Spartans(300 名斯巴达勇士)
- 6,000 到 7,000 Greek allies(实际联军人数)
其中300是最突出的数字,也是最经典的 CTF 提示。
常见的 CTF 编码/加密方式中,与数字直接相关的是ROT(Caesar 移位)。
ROT 通常有两种作用域:
- 字母表(模 26):ROT13、ROT5 等
- ASCII 可见字符(模 94):ROT47、ROT18 等
题目里的密文包含大量符号,说明它很可能是在ASCII 可见字符范围(33~126,共 94 个字符)上做的移位。
计算:
300 mod 94 = 300 - 94 × 3 = 300 - 282 = 18得到18。
于是猜测加密方式是ROT18:对每个 ASCII 可见字符(33~126)偏移 18 位。
三、ROT18 原理
ROT18 的加解密公式相同(因为 18 与 94 不互素?实际上 18 和 94 的最大公约数是 2,但 ROT18 加两次不等于原文,所以加密和解密方向相反):
加密:
c' = 33 + ((c - 33 + 18) mod 94)解密:
c' = 33 + ((c - 33 - 18) mod 94)其中c必须满足33 ≤ c ≤ 126,否则字符不变。
四、解密过程
对密文逐字符做 ROT18 解密(减 18):
密文:
u(x/&B(FICB"qCGqWFG-qIzC"yqt)Iq"EEvqIBq}`Biq(zEq&)~EG1解密结果:
ctf{r0t4710n_15_E45y_7h1ng_bu7_n33d_70_kN0W_th3_rul35}逐段解读(leetspeak):
| 密文片段 | 解密结果 | 含义 |
|---|---|---|
ctf{ | ctf{ | 开头 |
r0t4710n | r0t4710n | rotation |
_15_ | _15_ | is |
E45y | E45y | Easy |
_7h1ng | _7h1ng | _thing |
_bu7_ | _bu7_ | but |
n33d | n33d | need |
_70_ | _70_ | to |
kN0W | kN0W | kN0W |
_th3_ | _th3_ | the |
rul35 | rul35 | rules |
} | } | 结尾 |
得到明文:
ctf{r0t4710n_15_E45y_7h1ng_bu7_n33d_70_kN0W_th3_rul35}注意:题目要求 Flag 格式为pctf{...},而解出的明文开头是ctf{,缺少首字母p。
检查密文开头:
- 密文第一个字符是
u u减 18 得到c- 如果明文第一个字符是
p,加密(加 18)后应该是$ - 即
pctf{加密后为$u(x/
而题目给出的密文开头是u(x/&,正好少了开头的$,多了一个&?不,仔细对比:
明文:p c t f { r ... 加密:$ u ( x / & ... 密文: u ( x / & ...密文确实是$u(x/&...去掉第一个$后的结果。
也就是说,题目密文可能漏掉了第一个字符$,或者出题人故意省略了p,让选手根据格式补全。
根据 Flag 格式pctf{...},补上前缀p,得到最终 Flag:
pctf{r0t4710n_15_E45y_7h1ng_bu7_n33d_70_kN0W_th3_rul35}五、Python 解密脚本
defrot18_decrypt(s):result=[]forcins:o=ord(c)if33<=o<=126:result.append(chr(33+((o-33-18)%94)))else:result.append(c)return''.join(result)cipher='u(x/&B(FICB"qCGqWFG-qIzC"yqt)Iq"EEvqIBq}`Biq(zEq&)~EG1'plain=rot18_decrypt(cipher)print(plain)# 输出:ctf{r0t4710n_15_E45y_7h1ng_bu7_n33d_70_kN0W_th3_rul35}六、Flag
pctf{r0t4710n_15_E45y_7h1ng_bu7_n33d_70_kN0W_th3_rul35}七、总结
| 步骤 | 内容 |
|---|---|
| 1 | 观察密文包含大量符号,推测是 ASCII 可见字符范围的移位 |
| 2 | 题目描述强调300,计算300 mod 94 = 18 |
| 3 | 确定加密方式为ROT18 |
| 4 | 对密文逐字符减 18 解密 |
| 5 | 得到 leetspeak 明文,补全pctf{前缀 |
| 6 | 提交 Flag |
关键点:CTF 中看到“300”“斯巴达”等数字提示,要立刻联想到 ROT 系列;ROT18 是 ASCII 可见字符(94 个)上的移位,与 ROT47 类似但偏移量不同。
Rambo
2026年9月26日