2025.10-切题
10月切题
pycryptojail
题目
1 | #!/usr/local/bin/python3 |
题目允许运行你输入任意的位于 0123456789abcdefghijklmnopqrstuvwxyz_+-*/ 的字符串,然后目的是计算出 flag。
恢复 n
由于输出是给 rsa 加密了,但是我们没有 rsa 模数所以第一步肯定是先恢复 n
这就非常简单了,随便输个值 m 进去,得到密文 c 肯定有
那么我们多输入几个进去做 就可以拿到 n 了。
恢复 secret
接下来就是核心了,如果我们想要 print(flag),那么我们肯定要想办法得到 secret
如果考虑爆破 secret 的话,时间复杂度是 ,显然是不大现实的
我们考虑 python 的一个特征,如果我们已经定义了一个变量 abcdefghijk,再输入 abcdefghijk 的话,会有
1 | >>> abcdefghijk=123456 |
这里就会出现一个很神奇的 trick,如果我们的输入和正确的变量最够接近,那么 NameError 就会给我们正确变量的名称
而 python 使用 Levenshtein distance 来判断是否足够接近。按照源码,No more than 1/3 of the involved characters should need changed
如果我们输入 flag_you_will_never_guess_thiszzzzzzzzzzzzzzzzz,肯定会报
1 | Traceback (most recent call last): |
假如正确的变量是 flag_you_will_never_guess_this_648087513328cc46
如果我们有一个值和其对上,比如 flag_you_will_never_guess_thisz6zzzzzzzzzzzzzzz,就会返回
1 | NameError: name 'flag_you_will_never_guess_thisz6zzzzzzzzzzzzzzz' is not defined. Did you mean: 'flag_you_will_never_guess_this_648087513328cc46'? |
那么我们可以做这样子一个判断,我们输入
1 | flag_you_will_never_guess_thisz0zzzzzzzzzzzzzzz |
看对没有 Did you mean 的报错进行加密,如果和返回的密文一样,我们就判断这个位置是猜对的。
然后对下个位置进行
1 | flag_you_will_never_guess_thiszz0zzzzzzzzzzzzzz |
这样子的猜测。
计算 flag
我们拿到了正确的变量名称后面就是计算 flag 了,如果直接输入变量名称的话只会给出 flag 的密文。如何才可以想办法弄到 flag 呢?
在没有任何私钥的情况下我们似乎还有一个方式可以做,就是 Franklin–Reiter,但是有个问题就是 flag 是字符,如何才能让其拼接上其它任意的字符呢,而且我们没有 '" 可以使用,这时候题目里面就给出了提示,注意题目里有一行 if __name__ == '__main__':,这不就是一个很好的 trick,因为我们可以输入 flag_you_will_never_guess_this_648087513328cc46+__name__
,这样子就会返回 flag 和 '__main__' 的拼接。那我们把 flag 作为未知的变量,对于两个加密的式子做 肯定就有共根 flag 了,就是一个简单的 Franklin–Reiter 打法了。
exp
1 | from Crypto.Util.number import * |