栅栏里的保险箱
题目
题目链接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("解密尝试结束。")
|