栅栏里的保险箱

题目

题目链接https://pan.quark.cn/s/de897361a032

下载题目解压后得到一个txt文档,除此之外什么都没有了

解题思路

第一眼看到这个题觉得十分奇怪,以为是出题人的脑洞题,发现保险箱外面和里面的数字长度相等,以为是进行异或或者按位异或后转化为字符串,使用栅栏解密后即可得到flag,经过一番尝试后发现这样的方法行不通,全部都是乱码,又尝试先进行栅栏解码在异或处理,还是没有什么结果,这时候已经在问候出题人了

仔细阅读同意题目后发现钥匙不是一个而是一大堆,于是对外面的数字进行手动处理,按ASCII编码格式进行分类,还是一无所获

后来经过队友的提示后发现了一种新的解题思路,假设题目里面是RSA加密,那么被n锁在保险箱里的数字很大可能是n,外面是秘文c,尝试使用yafu进行分解,发现n果然可以分解,思路没错便继续进行尝试

目前已知的条件有c,n,p,q,缺少e,尝试常见素数65537发现不对,对保险箱字母n的个数进行尝试,发现还是不对,接下来便只能暴力循环e求解flag,但这样会存在一个很大的问题:不论可不可以打印的字符都会出来许多乱码明文,于是根据题目中的栅栏猜测明文应该还会使用栅栏加密,虽然无法直接使用’flag{‘来判断正确的字符串,但是’f’,’l’,’a’,’g’,’{‘,’}’这六个字符是肯定存在于正确的结果中的,通过这一个条件我们便可以进行明文的筛选

遍历后发现只有一个符合条件的明文f513lb9f22}a1a161gfe1f9{74ac82cc27cf23,将其放入随波逐流一把梭得到最终的flag

这个题的脑洞确实比较大,从一开始的两串数字到最后的RSA解密,同时改变了正确明文的格式,大大增加了筛选结果的困难程度

解题代码

``

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
from sympy import Integer
import gmpy2
from Crypto.Util.number import long_to_bytes

# 输入的密文、两个大素数和N的公钥部分
p = 475983529392229563986300263627
q = 50994851324392722608175048292980313487272936248176620246821369736608473
c = 14357527460442347355096404625497793506543049498914015672502337590355030280127374107997576931872991169

# 计算N和φ(N)
n = p * q
phi = (p - 1) * (q - 1)

# 定义要求的字符集
required_chars = {'f', 'l', 'a', 'g', '{', '}'}

# 计算模反元素(用于求私钥d)
def mod_inverse(a, m):
return gmpy2.invert(int(a), int(m)) # 使用gmpy2的invert函数计算逆元

# 判断明文是否包含所有需要的字符
def contains_required_chars(plaintext):
return required_chars.issubset(set(plaintext))

# 尝试使用e进行解密,返回解密的明文(如果符合条件)
def try_decrypt(e, c, n, phi):
try:
d = mod_inverse(e, phi) # 使用gmpy2计算私钥d
decrypted = pow(c, d, n) # 使用d解密密文c
decrypted_bytes = long_to_bytes(decrypted) # 转换为字节
decrypted_text = decrypted_bytes.decode('utf-8', errors='ignore') # 转为明文
if decrypted_text.isprintable() and contains_required_chars(decrypted_text): # 检查是否包含所有要求的字符
return decrypted_text
except (ValueError, ZeroDivisionError):
return None

# 遍历e的值并打印成功的解密结果
print("开始尝试解密...")
for e in range(1, 11000001): # e从1开始,逐步增加
decrypted_text = try_decrypt(e, c, n, phi)
if decrypted_text:
print(f"e = {e}, 解密结果 = {decrypted_text}") # 输出成功的解密结果

if e % 10000 == 0: # 每检查10000次,打印一次进度
print(f"已检查到e = {e}...")

print("解密尝试结束。")